example python Quelle est la différence entre @staticmethod et @classmethod?




11 Answers

Une méthode statique est une méthode qui ignore tout de la classe ou de l'instance sur laquelle elle a été appelée. Il récupère simplement les arguments qui ont été passés, pas de premier argument implicite. Il 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 en premier argument la classe sur laquelle elle a été appelée ou la classe de l'instance sur laquelle elle a été appelée. Ceci est utile lorsque vous souhaitez que la méthode soit une fabrique pour la classe: étant donné qu'elle obtient comme premier argument la classe sur laquelle elle a été appelée, 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, renvoie une instance de la sous-classe lorsqu'il est appelé dans une sous-classe:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 
staticmethod python

Quelle est la différence entre une fonction décorée avec @staticmethod et une fonction décorée avec @classmethod ?




Documents officiels en python:

@classmethod

Une méthode de classe reçoit la classe en tant que premier argument implicite, tout comme une méthode d'instance reçoit l'instance. Pour déclarer une méthode de classe, utilisez cet idiome:

class C:
    @classmethod
    def f(cls, arg1, arg2, ...): ... 

La forme @classmethod est un decorator fonctions - voir la description des définitions de fonctions dans Définitions de fonctions pour plus de détails.

Il peut être appelé soit sur la classe (telle que Cf() ), soit sur une instance (telle que C().f() ). L'instance est ignorée à l'exception de sa classe. Si une méthode de classe est appelée pour une classe dérivée, l'objet de classe dérivée est passé en tant que premier argument implicite.

Les méthodes de classe sont différentes des méthodes statiques C ++ ou Java. Si vous voulez ceux-ci, voyez staticmethod() dans cette section.

@staticmethod

Une méthode statique ne reçoit pas de premier argument implicite. Pour déclarer une méthode statique, utilisez cet idiome:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ... 

La forme @staticmethod est un decorator fonction - voir la description des définitions de fonction dans Définitions de fonction pour plus de détails.

Il peut être appelé soit sur la classe (telle que Cf() ), soit sur une instance (telle que C().f() ). L'instance est ignorée à l'exception de sa classe.

Les méthodes statiques en Python sont similaires à celles trouvées en Java ou en C ++. Pour un concept plus avancé, consultez classmethod() dans cette section.




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 . Par contre, si votre méthode ne touche aucune autre partie de la classe, utilisez @staticmethod.

class Apple:

    _counter = 0

    @staticmethod
    def about_apple():
        print('Apple is good for you.')

        # note you can still access other member of the class
        # but you have to use the class instance 
        # which is not very nice, because you have repeat yourself
        # 
        # For example:
        # @staticmethod
        #    print('Number of apples have been juiced: %s' % Apple._counter)
        #
        # @classmethod
        #    print('Number of apples have been juiced: %s' % cls._counter)
        #
        #    @classmethod is especially useful when you move your function to other class,
        #       you don't have to rename the class reference 

    @classmethod
    def make_apple_juice(cls, number_of_apples):
        print('Make juice:')
        for i in range(number_of_apples):
            cls._juice_this(i)

    @classmethod
    def _juice_this(cls, apple):
        print('Juicing %d...' % apple)
        cls._counter += 1



@decorators ont été ajoutés à 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 fabrique (une fonction renvoyant une instance d'une implémentation différente d'une classe en fonction de l'argument qu'elle obtient), vous pouvez effectuer les opérations suivantes:

class Cluster(object):

    def _is_cluster_for(cls, name):
        """
        see if this class is the cluster with this name
        this is a classmethod
        """ 
        return cls.__name__ == name
    _is_cluster_for = classmethod(_is_cluster_for)

    #static method
    def getCluster(name):
        """
        static factory method, should be in Cluster class
        returns a cluster object for the given name
        """
        for cls in Cluster.__subclasses__():
            if cls._is_cluster_for(name):
                return cls()
    getCluster = staticmethod(getCluster)

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 méthode _is_cluster_for une classe est une méthode permettant à une sous-classe de modifier son implémentation, peut-être parce qu'elle est générique et qu'elle peut gérer plus d'un type de cluster. Le simple fait de vérifier le nom de la classe ne serait donc pas suffisant.




Méthodes statiques:

  • Fonctions simples sans argument de soi.
  • Travailler sur les attributs de classe; pas sur les attributs d'instance.
  • Peut être appelé par la classe et l'instance.
  • La fonction intégrée staticmethod () est utilisée pour les créer.

Avantages des méthodes statiques:

  • Il localise le nom de la fonction dans le classscope
  • Il déplace le code de fonction plus près de l'endroit où il est utilisé
  • Plus pratique d’importer que des fonctions de niveau module puisque chaque méthode n’a pas besoin d’être importée spécialement

    @staticmethod
    def some_static_method(*args, **kwds):
        pass
    

Méthodes de classe:

  • Fonctions dont le premier argument est classname.
  • Peut être appelé à la fois par la classe et par l'instance.
  • Ceux-ci sont créés avec la fonction intégrée classmethod.

     @classmethod
     def some_class_method(cls, *args, **kwds):
         pass
    



Le guide définitif sur l’utilisation 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 @staticmethod n'est rien d'autre qu'une fonction définie dans une classe. Il est appelable sans instancier d'abord la classe. Sa définition est immuable par héritage.

  • Python n'a pas besoin d'instancier une méthode liée pour object.
  • Cela facilite la lisibilité du code et ne dépend pas de l'état de l'objet lui-même;

@classmethod fonction @classmethod é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, pouvant être remplacée par la sous-classe. En effet, le premier argument de la fonction @classmethod doit toujours être cls (classe).

  • Les méthodes d'usine , qui sont utilisées pour créer une instance pour une classe en utilisant par exemple une sorte de pré-traitement.
  • Méthodes statiques appelant des méthodes statiques : si vous divisez une méthode statique en plusieurs méthodes statiques, vous ne devez pas coder en dur le nom de la classe, mais utiliser des méthodes de classe.



Un autre élément à prendre en compte, méthode statique vs méthode méthode, est l'héritage. Disons que vous avez la classe suivante:

class Foo(object):
    @staticmethod
    def bar():
        return "In Foo"

Et vous voulez ensuite remplacer bar() dans une classe enfant:

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"

Cela fonctionne, mais notez que maintenant, l'implémentation de bar() dans la classe enfant ( Foo2 ) ne peut plus tirer parti de quoi que ce soit spécifique à cette classe. Par exemple, supposons que Foo2 une méthode appelée magic() que vous souhaitez utiliser dans l'implémentation Foo2 de bar() :

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"
    @staticmethod
    def magic():
        return "Something useful you'd like to use in bar, but now can't" 

La solution consiste à appeler Foo2.magic() dans bar() , mais vous vous répétez (si le nom de Foo2 change, vous devez vous rappeler de mettre à jour cette méthode bar() ).

Pour moi, c'est une légère violation du principe d'ouverture / fermeture , car une décision prise dans Foo affecte votre capacité à refactoriser le code commun dans une classe dérivée (c'est-à-dire qu'il est moins ouvert à l'extension). Si bar() était une classmethod bien:

class Foo(object):
    @classmethod
    def bar(cls):
        return "In Foo"

class Foo2(Foo):
    @classmethod
    def bar(cls):
        return "In Foo2 " + cls.magic()
    @classmethod
    def magic(cls):
        return "MAGIC"

print Foo2().bar()

Donne: In Foo2 MAGIC




Permettez-moi de dire la similitude entre une méthode décorée avec @classmethod vs @staticmethod en premier.

Similarité: les deux peuvent être appelés sur la classe elle-même, plutôt que simplement sur l' instance de la classe. Donc, les deux sont en un sens les méthodes de Class .

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, dans un sens, pas liée à la classe elle-même et reste suspendue simplement parce qu’elle peut avoir une fonctionnalité connexe.

class C(object):
    @classmethod
    def fun(cls, arg1, arg2, ...):
       ....

fun: function that needs to be converted into a class method
returns: a class method for function.



@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 .... )

Méthode @static: n'a rien à voir avec la classe ou l'instance associée à ... mais pour des raisons de lisibilité, vous pouvez utiliser la méthode statique




Les méthodes de classe, comme leur nom l'indique, sont utilisées pour modifier les classes et non les objets. Pour modifier les 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 (généralement désignée par 'cls') comme premier argument.

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

Les méthodes statiques, quant à elles, permettent d’exécuter des fonctionnalités qui ne sont pas liées à la classe, c’est-à-dire qu’elles ne liront ni n’écriront de variables de classe. Par conséquent, les méthodes statiques ne prennent pas les classes comme arguments. 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.

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."



#!/usr/bin/python
#coding:utf-8

class Demo(object):
    def __init__(self,x):
        self.x = x

    @classmethod
    def addone(self, x):
        return x+1

    @staticmethod
    def addtwo(x):
        return x+2

    def addthree(self, x):
        return x+3

def main():
    print Demo.addone(2)
    print Demo.addtwo(2)

    #print Demo.addthree(2) #Error
    demo = Demo(2)
    print demo.addthree(2)


if __name__ == '__main__':
    main()



Related