Quelle est la différence entre une fonction décorée avec @staticmethod
et une autre décorée de @classmethod
?
Je ne comprends pas quel est l'intérêt d'utiliser staticmethod. Nous pouvons simplement utiliser une simple fonction hors classe.
Quelle est la différence entre une fonction décorée avec @staticmethod
et une autre décorée de @classmethod
?
Peut-être qu'un peu de code d'exemple vous aidera : Remarquez la différence dans les signatures d'appel de foo
, class_foo
y static_foo
:
class A(object):
def foo(self, x):
print(f"executing foo({self}, {x})")
@classmethod
def class_foo(cls, x):
print(f"executing class_foo({cls}, {x})")
@staticmethod
def static_foo(x):
print(f"executing static_foo({x})")
a = A()
Voici la manière habituelle dont une instance d'objet appelle une méthode. L'instance d'objet, a
est implicitement passé comme premier argument.
a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>, 1)
Avec les méthodes de classe la classe de l'instance de l'objet est implicitement passée comme premier argument au lieu de self
.
a.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)
Vous pouvez également appeler class_foo
en utilisant la classe. En fait, si vous définissez quelque chose comme étant une classmethod, c'est probablement parce que vous avez l'intention de l'appeler depuis la classe plutôt que depuis une instance de la classe. A.foo(1)
aurait soulevé une TypeError, mais A.class_foo(1)
fonctionne très bien :
A.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)
L'une des utilisations que les gens ont trouvé pour les méthodes de classe est la création de Constructeurs alternatifs héritables .
Avec les méthodes statiques ni l'un ni l'autre self
(l'instance de l'objet) ni cls
(la classe) est implicitement passée comme premier argument. Elles se comportent comme des fonctions ordinaires, sauf que vous pouvez les appeler à partir d'une instance ou de la classe :
a.static_foo(1)
# executing static_foo(1)
A.static_foo('hi')
# executing static_foo(hi)
Les méthodes statiques sont utilisées pour regrouper les fonctions qui ont un lien logique avec une classe dans cette classe.
foo
est juste une fonction, mais lorsque vous appelez a.foo
vous ne recevez pas seulement la fonction, vous obtenez une version "partiellement appliquée" de la fonction avec l'instance de l'objet. a
comme premier argument de la fonction. foo
attend 2 arguments, tandis que a.foo
n'attend qu'un seul argument.
a
est lié à foo
. C'est ce que l'on entend par le terme "lié" ci-dessous :
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
Avec a.class_foo
, a
n'est pas lié à class_foo
mais plutôt la classe A
est lié à class_foo
.
print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
Ici, avec une staticmethod, même si c'est une méthode, a.static_foo
renvoie juste une bonne vieille fonction sans arguments. static_foo
attend 1 argument, et a.static_foo
attend aussi 1 argument.
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
Et bien sûr, la même chose se produit quand on appelle static_foo
avec la classe A
à la place.
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
Je ne comprends pas quel est l'intérêt d'utiliser staticmethod. Nous pouvons simplement utiliser une simple fonction hors classe.
@Alcott : Vous pourriez vouloir déplacer une fonction dans une classe parce qu'elle appartient logiquement à la classe. Dans le code source de Python (par exemple multiprocessing, turtle, dist-packages), il est utilisé pour "cacher" les fonctions "privées" mono-underscore de l'espace de noms du module. Son utilisation, cependant, est fortement concentrée dans quelques modules seulement -- peut-être une indication que c'est principalement une chose stylistique. Bien que je n'ai pas pu trouver d'exemple de cela, @staticmethod
peut aider à organiser votre code en étant surchargée par les sous-classes. Sans cela, vous auriez des variantes de la fonction flottant dans l'espace de noms du module.
... ainsi que quelques explications sur où y pourquoi pour utiliser des méthodes d'instance, de classe ou statiques. Vous n'avez pas donné un seul mot à ce sujet, mais le PO n'a pas non plus posé de question à ce sujet.
A Méthode statique est une méthode qui ne sait rien de la classe ou de l'instance sur laquelle elle a été appelée. Elle récupère juste les arguments qui ont été passés, sans premier argument implicite. Elle est fondamentalement inutile en Python -- vous pouvez simplement utiliser une fonction de module au lieu d'une staticmethod.
A méthode de classe est une méthode à laquelle on passe la classe sur laquelle elle a été appelée, ou la classe de l'instance sur laquelle elle a été appelée, comme premier argument. C'est utile lorsque vous voulez que la méthode soit une usine pour la classe : puisqu'elle reçoit la classe réelle sur laquelle elle a été appelée comme premier argument, vous pouvez toujours instancier la bonne classe, même lorsque des sous-classes sont impliquées. Observez par exemple comment dict.fromkeys()
une classmethod, renvoie une instance de la sous-classe lorsqu'elle est appelée sur une sous-classe :
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>
Une staticmethod n'est pas inutile - c'est un moyen de placer une fonction dans une classe (parce qu'elle y appartient logiquement), tout en indiquant qu'elle ne nécessite pas d'accès à la classe.
Il n'est donc que "fondamentalement" inutile. Une telle organisation, ainsi que l'injection de dépendances, sont des utilisations valables des staticmethods, mais comme les modules, et non les classes comme en Java, sont les éléments de base de l'organisation du code en Python, leur utilisation et leur utilité sont rares.
Qu'y a-t-il de logique à définir une méthode à l'intérieur d'une classe, alors qu'elle n'a rien à voir avec la classe ou ses instances ?
Documentation officielle de python :
Une méthode de classe reçoit la classe comme premier argument implicite, tout comme une instance reçoit l'instance. Pour déclarer une méthode de classe, utilisez cet idiome :
class C: @classmethod def f(cls, arg1, arg2, ...): ...
Le site
@classmethod
la forme est une fonction décorateur - voir la description des définitions de fonctions dans Fonction définitions pour les détails.Elle peut être appelée soit sur la classe (telle que
C.f()
) ou sur une instance (telle queC().f()
). L'instance est ignorée, sauf pour sa classe. Si une méthode de est appelée pour une classe dérivée dérivée, l'objet de la classe dérivée est passé comme premier argument implicite.Les méthodes de classe sont différentes des méthodes statiques C++ ou les méthodes statiques de Java. Si vous voulez celles-ci, consultez
staticmethod()
dans cette section.
Une méthode statique ne reçoit pas de premier argument implicite. Pour déclarer une méthode méthode statique, utilisez cet idiome :
class C: @staticmethod def f(arg1, arg2, ...): ...
Le site
@staticmethod
la forme est une fonction décorateur - voir la description des définitions de fonctions dans Fonction définitions pour les détails.Elle peut être appelée soit sur la classe (telle que
C.f()
) ou sur une instance (telle queC().f()
). L'instance est ignorée, sauf pour sa classe.Les méthodes statiques en Python sont similaires à celles que l'on trouve en Java ou en C++. Pour un concept plus avancé, voir
classmethod()
dans cette section.
N'y a-t-il pas une erreur dans la documentation ? Il ne devrait pas y avoir de staticmethod : "L'instance et sa classe sont toutes deux ignorées." au lieu de "L'instance est ignorée sauf pour sa classe." ?
Aquí est un court article sur cette question
La fonction @staticmethod n'est rien d'autre qu'une fonction définie à l'intérieur d'une classe. Elle est appelable sans instancier la classe au préalable. Sa définition est immuable via l'héritage.
La fonction @classmethod peut également être appelée sans instancier la classe, mais sa définition suit la classe Sub, et non la classe Parent, via l'héritage. C'est parce que le premier argument de la fonction @classmethod doit toujours être cls (classe).
Cela signifie-t-il qu'en utilisant une staticmethod je suis toujours lié à la classe Parent et qu'avec la classmethod je suis lié à la classe dans laquelle je déclare la classmethod (dans ce cas la sous-classe) ?
Non. En utilisant une staticmethod, vous n'êtes pas du tout lié ; il n'y a pas de premier paramètre implicite. En utilisant une classmethod, vous obtenez comme premier paramètre implicite la classe sur laquelle vous avez appelé la méthode (si vous l'avez appelé directement sur une classe), ou la classe de l'instance sur laquelle vous avez appelé la méthode (si vous l'avez appelé sur une instance).
On pourrait développer un peu pour montrer que, en ayant une classe comme premier argument, les méthodes de classe ont un accès direct aux autres attributs et méthodes de classe, alors que les méthodes statiques n'en ont pas (il faudrait coder en dur MyClass.attr pour cela).
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
18 votes
En Python, il est parfois préférable que les méthodes statiques soient des fonctions de niveau module pour des raisons de propreté. Avec une fonction de module, il est plus facile d'importer uniquement la fonction dont vous avez besoin et d'éviter toute syntaxe "." inutile (je vous regarde, Objective-C). Les méthodes de classe sont plus utiles car elles peuvent être utilisées en combinaison avec le polymorphisme pour créer des fonctions de type "factory pattern".
39 votes
Tl;dr >> par rapport aux méthodes normales, les méthodes statiques et les méthodes de classe sont également accessibles en utilisant la classe, mais contrairement aux méthodes de classe, les méthodes statiques sont immuables via l'héritage.
4 votes
Exposé connexe de Raymond Hettinger sur le sujet : youtube.com/watch?v=HTLu2DFOdTg
1 votes
Plus précis youtube.com/watch?v=HTLu2DFOdTg&feature=youtu.be&t=2689 vous n'avez besoin de classmethod que pour les constructeurs alternatifs. Sinon, vous pouvez utiliser staticmethod et accéder à n'importe quel attribut de classe (via le point . /) par l'intermédiaire de l'actuel "CLASSNAME", plus informatif, au lieu de cls comme dans classmethod.