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, class
definició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 foo
en 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 self
para ese primer argumento en un método de instancia y cls
en un método de clase. No utilicé ninguno aquí para ilustrar que es solo un argumento. En Ruby, self
es 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 @classmethod
que 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.