¿Qué son los "métodos de clase" y los "métodos de instancia" en Python?
Un "método de instancia" utiliza la información contenida en la instancia para determinar qué valor devolver (o qué efecto secundario hacer). Estos son muy comunes.
Un "método de clase" usa información sobre la clase (y no una instancia de esa clase) para afectar lo que hace (se usan generalmente para crear nuevas instancias como constructores alternativos, y por lo tanto no son increíblemente comunes).
Un "método estático" no utiliza ninguna información sobre la clase o instancia para calcular lo que hace. Por lo general, es solo en la clase por conveniencia. (Como tal, estos tampoco son muy comunes).
Una función de X
Recuerde la clase de matemáticas, "y es una función de x f(x)
,?" Apliquemos eso en el código:
y = function(x)
Implícito en lo anterior es que, dado que x
puede cambiar, y
puede cambiar cuando x
cambia. Esto es lo que significa cuando decimos que " y
es una función de x
"
¿Qué será y
cuando z
sea 1
? 2
? 'FooBarBaz'
?
y
no es una función de z
, por lo que z
puede ser cualquier cosa y no afectar el resultado de la función suponiendo que nuestra function
es una función pura. (Si accede z
como una variable global, entonces no es una función pura, esto es lo que se entiende por pureza funcional).
Tenga en cuenta lo anterior mientras lee las siguientes descripciones:
Métodos de instancia
Un método de instancia es una función que es función de una instancia . La función acepta la instancia implícitamente como un argumento, y la instancia la utiliza para determinar el resultado de la función.
Un ejemplo incorporado de un método de instancia es str.lower:
>>> 'ABC'.lower()
'abc'
str.lower
se llama en la instancia de la cadena y usa la información contenida en la instancia para determinar qué nueva cadena devolver.
Métodos de clase:
Recuerde, en Python, todo es un objeto. Eso significa que la clase es un objeto y se puede pasar como argumento a una función.
Un método de clase es una función que es una función de la clase . Acepta la clase como un argumento para ello.
Un ejemplo incorporado es dict.fromkeys
:
>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}
La función conoce implícitamente su propia clase, la función utiliza la clase para afectar la salida de la función y crea una nueva de esa clase a partir del iterable. Un OrderedDict demuestra esto cuando se usa el mismo método:
>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])
El método de clase utiliza información sobre la clase (y no una instancia de esa clase) para afectar qué tipo de clase devolver.
Métodos Estáticos
Usted menciona un método que "no conoce su clase"; este es un método estático en Python. Simplemente se adjunta por conveniencia al objeto de clase. Opcionalmente, podría ser una función separada en otro módulo, pero su firma de llamada sería la misma.
Un método estático no es función de la clase ni del objeto.
Un ejemplo incorporado de un método estático es str.maketrans de Python 3.
>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}
Dado un par de argumentos, crea un diccionario que no es una función de su clase.
Es conveniente porque str
siempre está disponible en el espacio de nombres global, por lo que puede usarlo fácilmente con la función de traducción:
>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'
En Python 2, debe acceder desde el string
módulo:
>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'str' has no attribute 'maketrans'
>>> import string
>>> 'abracadabra'.translate(string.maketrans('abc', 'bca'))
'bcrbabdbcrb'
Ejemplo
class AClass(object):
"""In Python, a class may have several types of methods:
instance methods, class methods, and static methods
"""
def an_instance_method(self, x, y, z=None):
"""this is a function of the instance of the object
self is the object's instance
"""
return self.a_class_method(x, y)
@classmethod
def a_class_method(cls, x, y, z=None):
"""this is a function of the class of the object
cls is the object's class
"""
return cls.a_static_method(x, y, z=z)
@staticmethod
def a_static_method(x, y, z=None):
"""this is neither a function of the instance or class to
which it is attached
"""
return x, y, z
Vamos a instanciar:
>>> instance = AClass()
Ahora la instancia puede llamar a todos los métodos:
>>> instance.an_instance_method('x', 'y')
('x', 'y', None)
>>> instance.a_static_method('x', 'y')
('x', 'y', None)
>>> instance.a_class_method('x', 'y')
('x', 'y', None)
Pero la clase generalmente no tiene la intención de llamar al método de instancia, aunque se espera que llame a los demás:
>>> AClass.a_class_method('x', 'y')
('x', 'y', None)
>>> AClass.a_static_method('x', 'y')
('x', 'y', None)
>>> AClass.an_instance_method('x', 'y')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: an_instance_method() missing 1 required positional argument: 'y'
Tendría que pasar explícitamente la instancia para llamar al método de instancia:
>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)