O que me ocorreu, vindo de Ruby, é que o chamado método de classe e o chamado método de instância são apenas uma função com significado semântico aplicado ao seu primeiro parâmetro, que é passado silenciosamente quando a função é chamada como método de um objeto (ie obj.meth()
).
Normalmente esse objeto deve ser uma instância, mas o @classmethod
decorador do método altera as regras para passar uma classe. Você pode chamar um método de classe em uma instância (é apenas uma função) - o primeiro argumento será sua classe.
Por ser apenas uma função , ela só pode ser declarada uma vez em um determinado escopo (ou seja, class
definição). Se segue, portanto, como uma surpresa para um Rubyist, você não pode ter um método de classe e um método de instância com o mesmo nome .
Considere isto:
class Foo():
def foo(x):
print(x)
Você pode chamar foo
uma instância
Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>
Mas não em uma aula:
Foo.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)
Agora adicione @classmethod
:
class Foo():
@classmethod
def foo(x):
print(x)
Chamar uma instância agora passa sua classe:
Foo().foo()
__main__.Foo
assim como chamar uma classe:
Foo.foo()
__main__.Foo
É apenas a convenção que determina que usamos self
para esse primeiro argumento em um método de instância e cls
em um método de classe. Não usei nenhum aqui para ilustrar que é apenas uma discussão. Em Ruby, self
é uma palavra - chave.
Contraste com Ruby:
class Foo
def foo()
puts "instance method #{self}"
end
def self.foo()
puts "class method #{self}"
end
end
Foo.foo()
class method Foo
Foo.new.foo()
instance method #<Foo:0x000000020fe018>
O método da classe Python é apenas uma função decorada e você pode usar as mesmas técnicas para criar seus próprios decoradores . Um método decorado envolve o método real (no caso @classmethod
dele passa o argumento de classe adicional). O método subjacente ainda está lá, oculto, mas ainda acessível .
nota de rodapé: escrevi isso depois que um conflito de nome entre uma classe e um método de instância despertou minha curiosidade. Estou longe de ser um especialista em Python e gostaria de comentar se algo está errado.