O que são “métodos de classe” e “métodos de instância”, em Python?

35

Houve uma discussão no bate-papo relacionada a uma pergunta (a questão em si é irrelevante para essa), que revelou que talvez eu não saiba nada sobre Python.

Na minha opinião, embora a terminologia seja diferente entre os idiomas, geralmente podemos categorizar funções como:

  • funções [livres]
  • métodos estáticos / funções de membro estático
  • métodos não estáticos / funções de membro não estático

Aparentemente, em Python, há outro tipo de função que não se encaixa nas categorias acima, uma que é um método, mas "não conhece sua classe".

O que são "métodos de classe" e "métodos de instância", em Python?

    
por Lightness Races in Orbit 29.12.2015 / 15:28
fonte

3 respostas

44

A resposta curta

  • um método de instância conhece sua instância (e, a partir disso, sua classe)
  • um método de classe conhece sua classe
  • um método estático não conhece sua classe ou instância

A resposta longa

Métodos de classe

Um método de classe é aquele que pertence à classe como um todo. Não requer uma instância. Em vez disso, a classe será enviada automaticamente como o primeiro argumento. Um método de classe é declarado com o decorador @classmethod .

Por exemplo:

class Foo(object):
    @classmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)
Foo.hello()
-> "Hello from Foo"
Foo().hello()
-> "Hello from Foo"

Métodos de instância

Por outro lado, um método de instância requer uma instância para chamar e não requer decorador. Este é de longe o tipo mais comum de método.

class Foo(object):
    def hello(self):
        print("hello from %s" % self.__class__.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'self'

(nota: o acima é com python3; com python2 você terá um erro ligeiramente diferente)

Métodos estáticos

Um método estático é semelhante a um método de classe, mas não obtém o objeto de classe como um parâmetro automático. É criado usando o decorador @staticmethod .

class Foo(object):
    @staticmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)

Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'cls'

Links de documentação

Aqui estão os links para a documentação relevante do python3:

A documentação do modelo de dados tem a dizer sobre a diferença entre métodos de classe e métodos estáticos :

Static method objects Static method objects provide a way of defeating the transformation of function objects to method objects described above. A static method object is a wrapper around any other object, usually a user-defined method object. When a static method object is retrieved from a class or a class instance, the object actually returned is the wrapped object, which is not subject to any further transformation. Static method objects are not themselves callable, although the objects they wrap usually are. Static method objects are created by the built-in staticmethod() constructor.

Class method objects A class method object, like a static method object, is a wrapper around another object that alters the way in which that object is retrieved from classes and class instances. The behaviour of class method objects upon such retrieval is described above, under “User-defined methods”. Class method objects are created by the built-in classmethod() constructor.

Perguntas relacionadas

por 29.12.2015 / 15:57
fonte
7

What are “class methods” and “instance methods”, in Python?

  • Um "método de instância" usa as informações contidas na instância para descobrir qual valor deve ser retornado (ou qual efeito colateral deve ser feito). 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 ela faz (normalmente elas são usadas para criar novas instâncias como construtores alternativos e, portanto, não são incrivelmente comum).

  • 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 aula por conveniência. (Como tal, estes não são muito comuns também.)

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)

Implícito pelo acima exposto é que, como x pode mudar, y pode mudar quando x é alterado. Isto é o que significa quando dizemos que " y é uma função de x "

Qual será o y quando z for 1 ? %código%? %código%?

2 não é uma função de 'FooBarBaz' , então y pode ser qualquer coisa e não afeta o resultado da função assumindo que z é uma função pura. (Se ele acessa z como uma variável global, então não é uma função pura - é o que se entende por pureza funcional.)

Lembre-se disso 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 a instância implicitamente como um argumento para ela, 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'

function é chamado na instância da string e usa as informações contidas na instância para descobrir qual nova string retornar.

Métodos de aula:

Lembre-se, em Python, tudo é um objeto. Isso significa que a classe é um objeto e pode ser passada como um argumento para uma função.

Um método de classe é uma função que é uma função da classe . Aceita a classe como um argumento para ela.

Um exemplo interno é z :

>>> 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 uma nova classe 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 class usa informações sobre a classe (e não uma instância dessa classe) para afetar o tipo de classe a ser retornado.

Métodos estáticos

Você menciona um método que "não conhece sua classe" - este é um método estático no Python. É simplesmente anexado por conveniência ao objeto de classe. Poderia ser opcionalmente uma função separada em outro módulo, mas sua assinatura 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}

Tendo em conta alguns argumentos, faz um dicionário que não é uma função da sua classe.

É conveniente porque str.lower está sempre disponível no namespace global, para que você possa usá-lo facilmente com a função translate:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'

No Python 2, você precisa acessá-lo no módulo dict.fromkeys :

>>> '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 geralmente não pretende chamar o método de instância, embora se espere que ele chame 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ê teria que passar explicitamente a instância para chamar o método da instância:

>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)
    
por 29.12.2015 / 15:56
fonte
4
  • Um "método de instância" é um método que recebe o objeto da instância como seu primeiro parâmetro, que por convenção é chamado de self . Este é o padrão.

  • Um "método estático" é um método sem o parâmetro self inicial. Isso é implementado com o o @staticmethod decorator .

  • Um "método de classe" é um método em que o parâmetro inicial não é um objeto de instância, mas o objeto de classe ( veja esta parte da documentação do Python sobre o que é um" objeto de classe ", que por convenção é chamado de cls . Isso é implementado com o @classmethod decorator .

O uso típico do termo "método estático" em C / C ++ / etc aplica-se aos métodos "estático" e de "classe" do Python, já que ambos os tipos de métodos não possuem uma referência à instância. Em C / C ++ / etc, os métodos normalmente têm acesso implícito a todos os membros / métodos que não são da instância, o que provavelmente é o motivo de essa distinção existir apenas em linguagens como Python / Ruby / etc.

    
por 29.12.2015 / 17:34
fonte