Ce qui vient de me frapper, venant de Ruby, est qu'une méthode dite de classe et une méthode dite d' instance sont juste une fonction avec une signification sémantique appliquée à son premier paramètre, qui est silencieusement transmise lorsque la fonction est appelée comme méthode de un objet (ie obj.meth()
).
Normalement, cet objet doit être une instance mais le @classmethod
décorateur de méthode modifie les règles pour passer une classe. Vous pouvez appeler une méthode de classe sur une instance (c'est juste une fonction) - le premier argument sera sa classe.
Parce que c'est juste une fonction , elle ne peut être déclarée qu'une seule fois dans une portée donnée (c'est-à-dire une class
définition). Il s'ensuit donc, comme une surprise pour un Rubyist, que vous ne pouvez pas avoir une méthode de classe et une méthode d'instance du même nom .
Considère ceci:
class Foo():
def foo(x):
print(x)
Vous pouvez faire appel foo
à une instance
Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>
Mais pas en classe:
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)
Ajoutez maintenant @classmethod
:
class Foo():
@classmethod
def foo(x):
print(x)
L'appel à une instance passe désormais sa classe:
Foo().foo()
__main__.Foo
tout comme faire appel à une classe:
Foo.foo()
__main__.Foo
C'est seulement la convention qui dicte que nous utilisons self
pour ce premier argument une méthode d'instance et cls
une méthode de classe. Je n'ai utilisé ni l'un ni l'autre ici pour illustrer que ce n'est qu'un argument. En Ruby, self
est un mot - clé.
Contraste avec 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>
La méthode de classe Python n'est qu'une fonction décorée et vous pouvez utiliser les mêmes techniques pour créer vos propres décorateurs . Une méthode décorée enveloppe la méthode réelle (dans le cas où @classmethod
elle passe l'argument de classe supplémentaire). La méthode sous-jacente est toujours là, cachée mais toujours accessible .
note de bas de page: j'ai écrit ceci après qu'un conflit de noms entre une classe et une méthode d'instance a piqué ma curiosité. Je suis loin d'être un expert Python et j'aimerais avoir des commentaires si tout cela est faux.