Quelle est la différence entre une fonction décorée @staticmethod
et une décorée avec @classmethod
?
python
oop
methods
python-decorators
Daryl Spitzer
la source
la source
Réponses:
Peut-être qu'un petit exemple de code vous aidera à: remarquer la différence dans les signatures d'appel de
foo
,class_foo
etstatic_foo
:Vous trouverez ci-dessous la manière habituelle dont une instance d'objet appelle une méthode. L'instance d'objet,,
a
est implicitement passée comme premier argument.Avec les méthodes de classe, la classe de l'instance d'objet est implicitement passée comme premier argument au lieu de
self
.Vous pouvez également appeler en
class_foo
utilisant la classe. En fait, si vous définissez quelque chose comme étant une méthode de classe, c'est probablement parce que vous avez l'intention de l'appeler à partir de la classe plutôt qu'à partir d'une instance de classe.A.foo(1)
aurait déclenché une TypeError, maisA.class_foo(1)
fonctionne très bien:Une utilisation que les gens ont trouvée pour les méthodes de classe est de créer des constructeurs alternatifs héritables .
Avec les méthodes statiques , ni
self
(l'instance d'objet) nicls
(la classe) n'est implicitement passé comme premier argument. Ils se comportent comme des fonctions simples, sauf que vous pouvez les appeler à partir d'une instance ou de la classe:Les méthodes statiques sont utilisées pour regrouper des fonctions qui ont une connexion logique avec une classe à la classe.
foo
n'est qu'une fonction, mais lorsque vous appelez,a.foo
vous n'obtenez pas seulement la fonction, vous obtenez une version "partiellement appliquée" de la fonction avec l'instance d'objeta
liée comme premier argument de la fonction.foo
attend 2 arguments, alors qu'ila.foo
n'attend qu'un seul argument.a
est lié àfoo
. C'est ce que signifie le terme "lié" ci-dessous:Avec
a.class_foo
,a
n'est pas lié àclass_foo
, plutôt la classeA
est liée àclass_foo
.Ici, avec une méthode statique, même s'il s'agit d'une méthode,
a.static_foo
renvoie simplement une bonne fonction 'olé sans aucun argument lié.static_foo
attend 1 argument eta.static_foo
attend également 1 argument.Et bien sûr, la même chose se produit lorsque vous appelez
static_foo
à laA
place avec la classe .la source
@staticmethod
pourrait aider à organiser votre code en étant surchargeable par les sous-classes. Sans cela, vous auriez des variantes de la fonction flottant dans l'espace de noms du module.@staticmethod
Encore une utilisation pour - vous pouvez l'utiliser pour retirer la cruauté. J'implémente un langage de programmation en Python - les fonctions définies par la bibliothèque utilisent uneexecute
méthode statique , où les fonctions définies par l'utilisateur nécessitent des arguments d'instance (c'est-à-dire le corps de la fonction). Ce décorateur élimine les avertissements "paramètres auto non utilisés" dans l'inspecteur PyCharm.Une méthode statique est une méthode qui ne sait rien de la classe ou de l'instance à laquelle elle a été appelée. Il obtient juste les arguments qui ont été passés, pas de premier argument implicite. C'est fondamentalement inutile en Python - vous pouvez simplement utiliser une fonction de module au lieu d'une méthode statique.
Une méthode de classe , en revanche, est une méthode qui obtient la classe à laquelle elle a été appelée, ou la classe de l'instance à laquelle elle a été appelée, comme premier argument. Ceci est utile lorsque vous voulez que la méthode soit une fabrique pour la classe: puisqu'elle obtient la classe réelle à 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 méthode de classe, retourne une instance de la sous-classe lorsqu'elle est appelée sur une sous-classe:la source
Fait essentiellement
@classmethod
une méthode dont le premier argument est la classe à partir de laquelle elle est appelée (plutôt que l'instance de classe),@staticmethod
n'a pas d'arguments implicites.la source
Documents officiels sur Python:
@classmethod
@staticmethod
la source
Voici un petit article sur cette question
la source
Pour décider d'utiliser @staticmethod ou @classmethod, vous devez regarder à l'intérieur de votre méthode. Si votre méthode accède à d'autres variables / méthodes de votre classe, utilisez @classmethod . D'un autre côté, si votre méthode ne touche aucune autre partie de la classe, utilisez @staticmethod.
la source
cls._counter
serait toujourscls._counter
même si le code est placé dans une classe différente ou si le nom de la classe est modifié.Apple._counter
est spécifique à laApple
classe; pour une classe différente, ou lorsque le nom de la classe est modifié, vous devrez modifier la classe référencée.Vous avez peut-être vu du code Python comme ce pseudocode, qui illustre les signatures des différents types de méthodes et fournit une docstring pour expliquer chacun d'eux:
La méthode d'instance normale
Je vais d'abord expliquer
a_normal_instance_method
. C'est ce qu'on appelle précisément une " méthode d'instance ". Lorsqu'une méthode d'instance est utilisée, elle est utilisée comme fonction partielle (par opposition à une fonction totale, définie pour toutes les valeurs lorsqu'elle est affichée dans le code source) qui est, lorsqu'elle est utilisée, le premier des arguments est prédéfini comme l'instance de la objet, avec tous ses attributs donnés. Il a l'instance de l'objet qui lui est liée et doit être appelée à partir d'une instance de l'objet. En règle générale, il accède à divers attributs de l'instance.Par exemple, ceci est une instance d'une chaîne:
si nous utilisons la méthode d'instance,
join
sur cette chaîne, pour rejoindre un autre itératives, il est bien évidemment fonction de l'instance, en plus d'être une fonction de la liste itératives,['a', 'b', 'c']
:Méthodes liées
Les méthodes d'instance peuvent être liées via une recherche en pointillés pour une utilisation ultérieure.
Par exemple, cela lie la
str.join
méthode à l'':'
instance:Et plus tard, nous pouvons l'utiliser comme une fonction qui a déjà le premier argument lié. De cette façon, cela fonctionne comme une fonction partielle sur l'instance:
Méthode statique
La méthode statique ne prend pas l'instance comme argument.
Elle est très similaire à une fonction de niveau module.
Cependant, une fonction de niveau module doit vivre dans le module et être spécialement importée vers d'autres endroits où elle est utilisée.
S'il est attaché à l'objet, cependant, il suivra également l'objet de manière pratique à travers l'importation et l'héritage.
Un exemple de méthode statique est
str.maketrans
, déplacé dustring
module en Python 3. Il rend une table de traduction adaptée à la consommation destr.translate
. Cela semble plutôt idiot lorsqu'il est utilisé à partir d'une instance d'une chaîne, comme illustré ci-dessous, mais l'importation de la fonction depuis lestring
module est plutôt maladroite, et il est agréable de pouvoir l'appeler à partir de la classe, comme dansstr.maketrans
En python 2, vous devez importer cette fonction à partir du module de chaîne de moins en moins utile:
Méthode de classe
Une méthode de classe est similaire à une méthode d'instance en ce qu'elle prend un premier argument implicite, mais au lieu de prendre l'instance, elle prend la classe. Ils sont fréquemment utilisés comme constructeurs alternatifs pour une meilleure utilisation sémantique et prendront en charge l'héritage.
L'exemple le plus canonique d'une méthode de classe intégrée est
dict.fromkeys
. Il est utilisé comme un constructeur alternatif de dict, (bien adapté lorsque vous savez quelles sont vos clés et que vous voulez une valeur par défaut pour elles.)Lorsque nous sous-classons dict, nous pouvons utiliser le même constructeur, ce qui crée une instance de la sous-classe.
Voir le code source pandas pour d'autres exemples similaires de constructeurs alternatifs, et voir également la documentation officielle de Python sur
classmethod
etstaticmethod
.la source
J'ai commencé à apprendre le langage de programmation avec C ++, puis Java et ensuite Python et cette question m'a donc beaucoup dérangé, jusqu'à ce que je comprenne l'utilisation simple de chacun.
Méthode de classe: Python contrairement à Java et C ++ n'a pas de surcharge de constructeur. Et pour cela, vous pouvez utiliser
classmethod
. L'exemple suivant explique celaConsidérons que nous avons une
Person
classe qui prend deux argumentsfirst_name
etlast_name
et crée l'instance dePerson
.Maintenant, si l'exigence vient où vous devez créer une classe en utilisant un seul nom, juste un
first_name
, vous ne pouvez pas faire quelque chose comme ça en Python.Cela vous donnera une erreur lorsque vous essaierez de créer un objet (instance).
Cependant, vous pouvez réaliser la même chose en utilisant
@classmethod
comme mentionné ci-dessousMéthode statique: c'est assez simple, ce n'est pas lié à une instance ou à une classe et vous pouvez simplement l'appeler en utilisant le nom de la classe.
Disons donc que dans l'exemple ci-dessus, vous avez besoin d'une validation qui
first_name
ne doit pas dépasser 20 caractères, vous pouvez simplement le faire.et vous pouvez simplement appeler en utilisant
class name
la source
def __init__(self, first_name, last_name="")
place de classmethodget_person
. Le résultat sera également exactement le même dans ce cas.Je pense qu'une meilleure question est "Quand utiliseriez-vous @classmethod vs @staticmethod?"
@classmethod vous permet d'accéder facilement aux membres privés associés à la définition de classe. c'est un excellent moyen de faire des singletons ou des classes d'usine qui contrôlent le nombre d'instances des objets créés.
@staticmethod fournit des gains de performances marginaux, mais je n'ai pas encore vu une utilisation productive d'une méthode statique dans une classe qui ne pourrait pas être réalisée en tant que fonction autonome en dehors de la classe.
la source
@decorators ont été ajoutés en python 2.4 Si vous utilisez python <2.4, vous pouvez utiliser les fonctions classmethod () et staticmethod ().
Par exemple, si vous souhaitez créer une méthode d'usine (une fonction renvoyant une instance d'une implémentation différente d'une classe en fonction de l'argument qu'elle obtient), vous pouvez faire quelque chose comme:
Notez également qu'il s'agit d'un bon exemple d'utilisation d'une méthode de classe et d'une méthode statique. La méthode statique appartient clairement à la classe, car elle utilise la classe Cluster en interne. La méthode de classe n'a besoin que d'informations sur la classe et pas d'instance de l'objet.
Un autre avantage de faire de la
_is_cluster_for
méthode une méthode de classe est qu'une sous-classe peut décider de modifier son implémentation, peut-être parce qu'elle est assez générique et peut gérer plus d'un type de cluster, donc il ne suffit pas de vérifier le nom de la classe.la source
Méthodes statiques:
Avantages des méthodes statiques:
Plus pratique pour importer que pour les fonctions au niveau du module car chaque méthode n'a pas besoin d'être spécialement importée
Méthodes de classe:
Ils sont créés avec la fonction intégrée classmethod.
la source
@staticmethod
désactive simplement la fonction par défaut en tant que descripteur de méthode. classmethod enveloppe votre fonction dans un conteneur appelable qui transmet une référence à la classe propriétaire comme premier argument:En fait,
classmethod
a une surcharge d'exécution mais permet d'accéder à la classe propriétaire. Alternativement, je recommande d'utiliser une métaclasse et de mettre les méthodes de classe sur cette métaclasse:la source
c = C(); c.foo()
soulève AttributeError, vous auriez à fairetype(c).foo()
. Cela pourrait également être considéré comme une fonctionnalité - je ne vois pas pourquoi vous voudriez le faire.Le guide définitif sur la façon d'utiliser des méthodes statiques, de classe ou abstraites en Python est un bon lien pour cette rubrique, et résumez-le comme suit.
@staticmethod
fonction n'est rien de plus qu'une fonction définie à l'intérieur d'une classe. Il peut être appelé sans instancier la classe en premier. Sa définition est immuable via l'héritage.@classmethod
La fonction peut également être appelée sans instancier la classe, mais sa définition suit la sous-classe, pas la classe parent, via l'héritage, peut être remplacée par la sous-classe. C'est parce que le premier argument pour la@classmethod
fonction doit toujours être cls (classe).la source
Seul le premier argument diffère :
Plus en détail...
méthode normale
Lorsque la méthode d'un objet est appelée, il reçoit automatiquement un argument supplémentaire
self
comme premier argument. Autrement dit, la méthodedoit être appelé avec 2 arguments.
self
est automatiquement passé, et c'est l'objet lui-même .méthode de classe
Quand la méthode est décorée
l'argument fourni automatiquement n'est pas
self
, mais la classe deself
.méthode statique
Quand la méthode est décorée
la méthode ne reçoit aucun argument automatique. Il ne reçoit que les paramètres avec lesquels il est appelé.
coutumes
classmethod
est principalement utilisé pour les constructeurs alternatifs.staticmethod
n'utilise pas l'état de l'objet. Il pourrait s'agir d'une fonction externe à une classe. Il n'est mis à l'intérieur de la classe que pour regrouper des fonctions avec des fonctionnalités similaires (par exemple, commeMath
les méthodes statiques de classe Java )la source
Permettez-moi de dire la similitude entre une méthode décorée avec @classmethod vs @staticmethod en premier.
Similarité: deux peuvent être appelés sur la classe elle-même, plutôt que sur l' instance de la classe. Donc, les deux sont en quelque sorte des méthodes de classe .
Différence: une méthode de classe recevra la classe elle-même comme premier argument, contrairement à une méthode statique.
Ainsi, une méthode statique n'est pas, en un sens, liée à la classe elle-même et ne fait que s'y accrocher juste parce qu'elle peut avoir une fonctionnalité associée.
la source
Une autre considération concernant la méthode statique par rapport à la méthode de classe concerne l'héritage. Disons que vous avez la classe suivante:
Et vous souhaitez ensuite remplacer
bar()
dans une classe enfant:Cela fonctionne, mais notez que maintenant l'
bar()
implémentation dans la classe enfant (Foo2
) ne peut plus profiter de quelque chose de spécifique à cette classe. Par exemple, supposons que vous disposiez d'Foo2
une méthode appeléemagic()
que vous souhaitez utiliser dans leFoo2
implémentation debar()
:La solution de contournement ici serait d'appeler
Foo2.magic()
àbar()
, mais vous vous répétez (si le nom desFoo2
modifications, vous devez vous rappeler de mettre à jour cettebar()
méthode).Pour moi, c'est une légère violation du principe ouvert / fermé , car une décision prise dans
Foo
impacte votre capacité à refactoriser le code commun dans une classe dérivée (c'est-à-dire qu'il est moins ouvert à l'extension). Sibar()
c'était un,classmethod
ça irait:Donne:
In Foo2 MAGIC
la source
Je vais essayer d'expliquer la différence de base en utilisant un exemple.
1 - on peut appeler directement des méthodes statiques et de classe sans initialiser
2- La méthode statique ne peut pas appeler la méthode self mais peut appeler d'autres méthodes statiques et de classe
3- La méthode statique appartient à la classe et n'utilisera pas du tout d'objet.
4- Les méthodes de classe ne sont pas liées à un objet mais à une classe.
la source
@classmethod: peut être utilisé pour créer un accès global partagé à toutes les instances créées de cette classe ..... comme la mise à jour d'un enregistrement par plusieurs utilisateurs .... Je l'ai particulièrement trouvé utile lors de la création de singletons également ..: )
@static, méthode: n'a rien à voir avec la classe ou l'instance associée à ... mais pour la lisibilité peut utiliser une méthode statique
la source
Vous voudrez peut-être considérer la différence entre:
et
Cela a changé entre python2 et python3:
python2:
python3:
Ainsi, l'utilisation
@staticmethod
de méthodes for appelées uniquement directement à partir de la classe est devenue facultative en python3. Si vous souhaitez les appeler à la fois de la classe et de l'instance, vous devez toujours utiliser le@staticmethod
décorateur.Les autres cas ont été bien couverts par la réponse unutbus.
la source
Une méthode de classe reçoit la classe comme premier argument implicite, tout comme une méthode d'instance reçoit l'instance. C'est une méthode qui est liée à la classe et non à l'objet de la classe. Elle a accès à l'état de la classe car elle prend un paramètre de classe qui pointe vers la classe et non l'instance d'objet. Il peut modifier un état de classe qui s'appliquerait à toutes les instances de la classe. Par exemple, il peut modifier une variable de classe qui sera applicable à toutes les instances.
En revanche, une méthode statique ne reçoit pas de premier argument implicite, par rapport aux méthodes de classe ou aux méthodes d'instance. Et ne peut pas accéder ou modifier l'état de classe. Il n'appartient qu'à la classe car du point de vue de la conception, c'est la bonne façon. Mais en termes de fonctionnalité n'est pas lié, lors de l'exécution, à la classe.
à titre indicatif, utilisez des méthodes statiques comme utilitaires, utilisez des méthodes de classe par exemple comme usine. Ou peut-être pour définir un singleton. Et utilisez des méthodes d'instance pour modéliser l'état et le comportement des instances.
J'espère que j'étais clair!
la source
Ma contribution démontre la différence entre
@classmethod
,@staticmethod
et les méthodes d'instance, y compris comment une instance peut indirectement appeler@staticmethod
. Mais au lieu d'appeler indirectement un@staticmethod
depuis une instance, le rendre privé peut être plus "pythonique". Obtenir quelque chose à partir d'une méthode privée n'est pas démontré ici, mais c'est fondamentalement le même concept.la source
Les méthodes de classe, comme son nom l'indique, sont utilisées pour apporter des modifications aux classes et non aux objets. Pour apporter des modifications aux classes, ils modifieront les attributs de classe (pas les attributs d'objet), car c'est ainsi que vous mettez à jour les classes. C'est la raison pour laquelle les méthodes de classe prennent la classe (classiquement désignée par «cls») comme premier argument.
Les méthodes statiques, d'autre part, sont utilisées pour effectuer des fonctionnalités qui ne sont pas liées à la classe, c'est-à-dire qu'elles ne liront ni n'écriront pas de variables de classe. Par conséquent, les méthodes statiques ne prennent pas les classes en argument. Ils sont utilisés pour que les classes puissent exécuter des fonctionnalités qui ne sont pas directement liées à l'objectif de la classe.
la source
Analysez littéralement @staticmethod fournissant des informations différentes.
Une méthode normale d'une classe est une méthode dynamique implicite qui prend l'instance comme premier argument.
En revanche, une méthode statique ne prend pas l'instance comme premier argument, elle est donc appelée «statique» .
Une méthode statique est en effet une fonction aussi normale que celles qui sont en dehors d'une définition de classe.
Heureusement, il est regroupé dans la classe afin de se rapprocher de l'endroit où il est appliqué, ou vous pouvez faire défiler pour le trouver.
la source
Je pense que donner une version purement Python
staticmethod
etclassmethod
aiderait à comprendre la différence entre eux au niveau du langage.Les deux sont des descripteurs non liés aux données (il serait plus facile de les comprendre si vous connaissez d' abord les descripteurs ).
la source
staticmethod n'a pas accès aux attributs de l'objet, de la classe ou des classes parentes dans la hiérarchie d'héritage. Il peut être appelé directement à la classe (sans créer d'objet).
classmethod n'a pas accès aux attributs de l'objet. Il peut cependant accéder aux attributs de la classe et des classes parentes dans la hiérarchie d'héritage. Il peut être appelé directement à la classe (sans créer d'objet). Si elle est appelée sur l'objet, elle est identique à la méthode normale qui n'accède pas
self.<attribute(s)>
et accèdeself.__class__.<attribute(s)>
uniquement.Pensez que nous avons une classe avec
b=2
, nous allons créer un objet et le réinitialiserb=4
dedans. Staticmethod ne peut accéder à rien de ce qui précède. Classmethod ne peut accéder.b==2
qu'à, viacls.b
. La méthode normale peut accéder à la fois:.b==4
viaself.b
et.b==2
viaself.__class__.b
.Nous pourrions suivre le style KISS (garder les choses simples, stupides): n'utilisez pas de méthodes statiques et de méthodes de classe, n'utilisez pas de classes sans les instancier, accédez uniquement aux attributs de l'objet
self.attribute(s)
. Il y a des langues où la POO est implémentée de cette façon et je pense que ce n'est pas une mauvaise idée. :)la source
Un hack-up rapide de méthodes identiques dans iPython révèle que cela
@staticmethod
donne des gains de performances marginaux (en nanosecondes), mais sinon il ne semble pas avoir de fonction. En outre, tout gain de performances sera probablement annulé par le travail supplémentaire de traitement de la méthode viastaticmethod()
pendant la compilation (qui se produit avant toute exécution de code lorsque vous exécutez un script).Par souci de lisibilité du code, j'éviterais à
@staticmethod
moins que votre méthode ne soit utilisée pour des charges de travail, où les nanosecondes comptent.la source