Lo que me llamó la atención , proveniente de Ruby, es que el llamado método de clase y el llamado método de instancia es solo una función con significado semántico aplicado a su primer parámetro, que se pasa silenciosamente cuando la función se llama como método de un objeto (es decir obj.meth()).
Normalmente, ese objeto debe ser una instancia, pero el @classmethod decorador de métodos cambia las reglas para pasar una clase. Puede llamar a un método de clase en una instancia (es solo una función): el primer argumento será su clase.
Debido a que es solo una función , solo se puede declarar una vez en cualquier ámbito (es decir, classdefinición). Si sigue, por lo tanto, como sorpresa para un Rubyist, que no puede tener un método de clase y un método de instancia con el mismo nombre .
Considera esto:
class Foo():
def foo(x):
print(x)
Puedes llamar fooen una instancia
Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>
Pero no en una clase:
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)
Ahora agregue @classmethod:
class Foo():
@classmethod
def foo(x):
print(x)
Llamar a una instancia ahora pasa su clase:
Foo().foo()
__main__.Foo
como lo hace llamar a una clase:
Foo.foo()
__main__.Foo
Es solo la convención la que dicta que usamos selfpara ese primer argumento en un método de instancia y clsen un método de clase. No utilicé ninguno aquí para ilustrar que es solo un argumento. En Ruby, selfes una palabra clave.
Contraste con 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>
El método de clase Python es solo una función decorada y puede usar las mismas técnicas para crear sus propios decoradores . Un método decorado envuelve el método real (en el caso de @classmethodque pase el argumento de clase adicional). El método subyacente sigue ahí, oculto pero aún accesible .
nota al pie: escribí esto después de un choque de nombres entre una clase y un método de instancia despertó mi curiosidad. Estoy lejos de ser un experto en Python y me gustaría recibir comentarios si algo de esto está mal.