O que são "métodos de classe" e "métodos de instância", em Python?
Um "método de instância" usa as informações contidas na instância para descobrir qual valor retornar (ou qual efeito colateral fazer). Estes são muito comuns.
Um "método de classe" usa informações sobre a classe (e não uma instância dessa classe) para afetar o que faz (elas geralmente são usadas para criar novas instâncias como construtores alternativos e, portanto, não são incrivelmente comuns).
Um "método estático" não usa nenhuma informação sobre a classe ou instância para calcular o que faz. Geralmente é apenas na classe por conveniência. (Como tal, também não são muito comuns.)
Uma função de X
Lembre-se da aula de matemática, "y é uma função de x f(x)
,?" Vamos aplicar isso no código:
y = function(x)
O que está implícito acima é que, uma vez que x
pode mudar, y
pode mudar quando x
muda. É isso que queremos dizer quando dizemos que " y
é uma função dex
"
O que y
será quando z
é 1
? 2
? 'FooBarBaz'
?
y
não é uma função de z
, portanto z
pode ser qualquer coisa e não afetar o resultado da função, assumindo que nossa function
é uma função pura. (Se acessarz
como uma variável global, não será uma função pura - é isso que significa pureza funcional.)
Lembre-se do que foi dito acima ao ler as seguintes descrições:
Métodos de instância
Um método de instância é uma função que é uma função de uma instância . A função aceita implicitamente a instância como argumento e a instância é usada pela função para determinar a saída da função.
Um exemplo interno de um método de instância é str.lower:
>>> 'ABC'.lower()
'abc'
str.lower
é chamado na instância da sequência e usa as informações contidas na instância para descobrir qual nova sequência retornar.
Métodos de classe:
Lembre-se, em Python, tudo é um objeto. Isso significa que a classe é um objeto e pode ser passada como argumento para uma função.
Um método de classe é uma função que é uma função da classe . Ele aceita a classe como argumento.
Um exemplo embutido é dict.fromkeys
:
>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}
A função conhece implicitamente sua própria classe, a função usa a classe para afetar a saída da função e cria um novo dessa classe a partir do iterável. Um OrderedDict demonstra isso ao usar o mesmo método:
>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])
O método da classe usa informações sobre a classe (e não uma instância dessa classe) para afetar qual tipo de classe retornar.
Métodos estáticos
Você mencionou um método que "não conhece sua classe" - este é um método estático no Python. É apenas anexado por conveniência ao objeto de classe. Opcionalmente, poderia ser uma função separada em outro módulo, mas sua assinatura de chamada seria a mesma.
Um método estático não é uma função da classe nem do objeto.
Um exemplo interno de um método estático é o str.maketrans do Python 3.
>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}
Dado alguns argumentos, ele cria um dicionário que não é função de sua classe.
É conveniente porque str
está sempre disponível no espaço de nomes global, para que você possa usá-lo facilmente com a função de conversão:
>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'
No Python 2, você precisa acessá-lo no 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'
Exemplo
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 instanciar:
>>> instance = AClass()
Agora a instância pode chamar todos os 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)
Mas a classe normalmente não se destina a chamar o método de instância, embora se espere chamar os outros:
>>> 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'
Você precisaria passar explicitamente a instância para chamar o método da instância:
>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)