Question

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

Était-ce utile?

La solution

Peut-être qu'un exemple de code aidera: remarquez la différence entre les signatures d'appel de foo, class_foo et static_foo:

class A(object):
    def foo(self, x):
        print "executing foo(%s, %s)" % (self, x)

    @classmethod
    def class_foo(cls, x):
        print "executing class_foo(%s, %s)" % (cls, x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)" % x    

a = A()

Ci-dessous, la manière habituelle dont une instance d'objet appelle une méthode. L'instance d'objet, a, est implicitement passée en tant que premier argument.

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

Avec les méthodes de classe , la classe de l'instance d'objet est implicitement passée en tant que premier argument au lieu de self.

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

Vous pouvez également appeler A.foo(1) à l'aide de la classe. En fait, si vous définissez quelque chose comme étant méthode de classe, c’est probablement parce que vous avez l’intention de l’appeler depuis la classe plutôt que depuis une instance de classe. A.class_foo(1) aurait généré une erreur TypeError, mais cls fonctionne parfaitement:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

Les utilisateurs ont trouvé une utilisation des méthodes de classe utilisée pour créer des constructeurs alternatifs héritables .

Avec staticmethods , ni a.foo (l'instance d'objet) ni a.class_foo (la classe) ne sont implicitement passés en tant que premier argument. Ils se comportent comme des fonctions simples, 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 des fonctions qui ont une connexion logique avec une classe à la classe.

A n'est qu'une fonction, mais lorsque vous appelez a.static_foo, vous n'obtenez pas simplement la fonction, vous obtenez un " partiellement appliqué " version de la fonction avec l'instance d'objet <=> liée en tant que premier argument de la fonction. <=> attend 2 arguments, alors que <=> n'attend qu'un argument.

<=> est lié à <=>. 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 <=>, <=> n'est pas lié à <=>, mais la classe <=> est liée à <=>.

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

Ici, avec une méthode statique, même s’il s’agit d’une méthode, <=> ne renvoie que une bonne 'fonction ole sans arguments liés. <=> attend 1 argument, et <=> attend 1 argument également.

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

Et bien sûr, la même chose se produit lorsque vous appelez <=> avec la classe <=> à la place.

print(A.static_foo)
# <function static_foo at 0xb7d479cc>

Autres conseils

Une méthode statique est une méthode qui ignore tout de la classe ou de l'instance pour laquelle elle a été appelée. Il récupère simplement les arguments qui ont été transmis, sans premier argument implicite. Il est pratiquement inutile en Python - vous pouvez simplement utiliser une fonction de module au lieu d’une méthode statique.

Un classmethod , en revanche, est une méthode qui transmet en tant que premier argument la classe sur laquelle il a été appelé ou la classe de l'instance sur laquelle il a été appelé. 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'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
>>> 

Fondamentalement @classmethod crée une méthode dont le premier argument est la classe à partir de laquelle elle est appelée (plutôt que l'instance de la classe), @staticmethod ne possède pas d'argument implicite.

Documents officiels en python:

@classmethod

  

Une méthode de classe reçoit la classe comme   premier argument implicite, comme un   méthode d'instance reçoit l'instance.   Pour déclarer une méthode de classe, utilisez ceci   idiome:

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

Le formulaire @classmethod est une fonction    décorateur & # 8211; voir la description de   définitions de fonctions dans Function   définitions pour plus de détails.

     

On peut l'appeler soit sur la classe   (comme C.f()) ou sur une instance   (comme C().f()). L'instance est   ignoré sauf pour sa classe. Si un   méthode de classe est appelée pour un dérivé   classe, l'objet de classe dérivé est   passé comme premier argument implicite.

     

Les méthodes de classe sont différentes de C ++   ou méthodes statiques Java. Si tu veux   voir staticmethod() dans cette page.   section.

@staticmethod

  

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

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

Le formulaire @staticmethod est une fonction    décorateur & # 8211; voir la description de   définitions de fonctions dans Function   définitions pour plus de détails.

     

On peut l'appeler soit sur la classe   (comme classmethod()) ou sur une instance   (comme <=>). L'instance est   ignoré sauf pour sa classe.

     

Les méthodes statiques en Python sont similaires   à ceux trouvés en Java ou C ++. Pour un   concept plus avancé, voir    <=> dans cette section.

Voici un bref article à ce sujet. question

  

La fonction @staticmethod n'est rien de plus qu'une fonction définie dans une classe. Il est appelable sans instancier d'abord la classe. Sa & # 8217; définition est immuable par héritage.

     

La fonction @classmethod est également appelable sans instancier la classe, mais sa définition suit la classe Sub, et non la classe Parent, via l'héritage. Cela & # 8217; s parce que le premier argument de la fonction @classmethod doit toujours être cls (classe).

Déterminer s'il faut utiliser @staticmethod ou @classmethod , vous devez consulter 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
  

Quelle est la différence entre @staticmethod et @classmethod en Python?

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 chaîne de documentation pour les expliquer:

class Foo(object):

    def a_normal_instance_method(self, arg_1, kwarg_2=None):
        '''
        Return a value that is a function of the instance with its
        attributes, and other arguments such as arg_1 and kwarg2
        '''

    @staticmethod
    def a_static_method(arg_0):
        '''
        Return a value that is a function of arg_0. It does not know the 
        instance or class it is called from.
        '''

    @classmethod
    def a_class_method(cls, arg1):
        '''
        Return a value that is a function of the class and other arguments.
        respects subclassing, it is called with the class it is called from.
        '''

La méthode d'instance normale

Je vais d'abord expliquer a_normal_instance_method. Cela s'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 globale définie pour toutes les valeurs affichées dans le code source), c'est-à-dire que, lorsqu'il est utilisé, le premier des arguments est prédéfini comme instance du objet, avec tous ses attributs donnés. L'instance de l'objet y est liée et doit être appelée à partir d'une instance de l'objet. En règle générale, il accédera à divers attributs de l'instance.

Par exemple, il s'agit d'une instance d'une chaîne:

', '

si nous utilisons la méthode de l'instance, join sur cette chaîne, pour joindre un autre itérable, il est bien évidemment fonction de l'instance, en plus d'être une fonction de la liste itérable, ['a', 'b', 'c']:

>>> ', '.join(['a', 'b', 'c'])
'a, b, c'

Méthodes liées

Les méthodes d'instance peuvent être liées via une recherche en pointillé pour une utilisation ultérieure.

Par exemple, cela lie la méthode str.join à l'instance ':':

>>> join_with_colons = ':'.join 

Et plus tard, nous pourrons utiliser cette fonction comme une fonction à laquelle le premier argument est déjà lié. De cette manière, cela fonctionne comme une fonction partielle sur l'instance:

>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'

Méthode statique

La méthode statique ne ne prend pas l'instance en argument.

Cela ressemble beaucoup à une fonction de niveau module.

Cependant, une fonction au niveau du module doit résider dans le module et être spécialement importée vers d'autres endroits où elle est utilisée.

S'il est attaché à l'objet, il le suivra facilement lors de l'importation et de l'héritage.

Un exemple de méthode statique est str.maketrans, déplacé du module string dans Python 3. Il permet à une table de traduction de pouvoir être consommée par str.translate. Cela semble plutôt ridicule quand on l'utilise depuis une instance d'une chaîne, comme illustré ci-dessous, mais importer la fonction depuis le module dict.fromkeys est plutôt maladroit, et il est agréable de pouvoir l'appeler depuis la classe, comme dans classmethod

# demonstrate same function whether called from instance or not:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}

En python 2, vous devez importer cette fonction à partir du module de chaîne de moins en moins utile:

>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'

Méthode de classe

Une méthode de classe est similaire à une méthode d’instance car elle utilise un premier argument implicite, mais au lieu de prendre l’instance, elle prend la classe. Ils sont fréquemment utilisés en tant que constructeurs alternatifs pour un meilleur usage sémantique et cela prend en charge l'héritage.

L'exemple le plus canonique d'une méthode de classe intégrée est staticmethod. Il est utilisé en tant que constructeur alternatif de dict (convient bien lorsque vous connaissez vos clés et souhaitez une valeur par défaut pour elles.)

>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}

Lorsque nous sous-classe dict, nous pouvons utiliser le même constructeur, ce qui crée une instance de la sous-classe.

>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>

Voir le code source du pandas pour des informations similaires. Vous trouverez des exemples de constructeurs alternatifs et la documentation officielle de Python à l'adresse <=> . <=> .

J'ai commencé à apprendre le langage de programmation avec C ++, puis Java, puis Python. Cette question m'a donc beaucoup ennuyée jusqu'à ce que je comprenne l'utilisation simple de chacun.

Méthode de classe: Contrairement à Java et C ++, le constructeur n'est pas surchargé. Et pour y parvenir, vous pouvez utiliser classmethod. L’exemple suivant explique cela

Considérons que nous avons une Person classe qui prend deux arguments first_name et last_name et crée l'instance de @classmethod.

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

Maintenant, si l'exigence survient lorsque vous devez créer une classe en utilisant un seul nom, il suffit d'un class name, vous ne pouvez pas faire quelque chose comme cela en Python.

Cela vous donnera une erreur lorsque vous essayez de créer un objet (instance).

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __init__(self, first_name):
        self.first_name = first_name

Cependant, vous pouvez obtenir le même résultat en utilisant <=> comme mentionné ci-dessous

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_person(cls, first_name):
        return cls(first_name, "")

Méthode statique: Ceci est assez simple, il n'est pas lié à une instance ou à une classe et vous pouvez simplement appeler cela à l'aide du nom de la classe.

Supposons que, dans l'exemple ci-dessus, vous avez besoin d'une validation qui <=> ne doit pas dépasser 20 caractères. Vous pouvez simplement le faire.

@staticmethod  
def validate_name(name):
    return len(name) <= 20

et vous pouvez simplement appeler en utilisant <=>

Person.validate_name("Gaurang Shah")

@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 procéder de la manière suivante:

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 classe méthode n'a besoin que d'informations sur la classe et pas d'instance d'objet.

Un autre avantage de transformer la méthode _is_cluster_for en méthode de classe est qu’une sous-classe peut décider de changer d’implémentation, peut-être parce qu’elle est assez générique et qu’elle peut gérer plus d’un type de cluster. Il suffit donc de vérifier le nom de la classe. ne pas être assez.

Je pense qu'une meilleure question est & "; Quand utiliseriez-vous @ classe \ vs classe \ 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 créer des singletons ou des classes d’usine contrôlant le nombre d’instances des objets créés.

@staticmethod fournit des gains de performances marginaux, mais je n’ai pas encore vu l’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.

Méthodes statiques:

  • Fonctions simples sans argument propre.
  • Travailler sur les attributs de classe; pas sur les attributs d'instance.
  • Peut être appelé à la fois par la classe et par 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
  • Cela déplace le code de fonction plus près de l'endroit où il est utilisé
  • Plus pratique d'importer que des fonctions au niveau du module car chaque méthode n'a pas besoin d'être spécialement importée

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

Méthodes de classe:

  • Fonctions ayant le premier argument comme nom de classe.
  • Peut être appelé à la fois par la classe et par l'instance.
  • Ils sont créés avec la fonction intégrée classmethod.

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

@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 passe une référence à la classe propriétaire en premier argument:

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

En fait, classmethod a une surcharge d’exécution, mais permet d’accéder à la classe propriétaire. Sinon, je recommande d'utiliser une métaclasse et de placer les méthodes de classe sur cette métaclasse:

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>

Le guide définitif sur l'utilisation de static, class ou des méthodes abstraites en Python est un bon lien pour cette rubrique et résumez-le comme suit.

La

@staticmethod fonction n’est rien d’autre qu’une fonction définie dans une classe. Il est appelable sans instancier d'abord la classe. Sa & # 8217; définition est immuable par héritage.

  • Python n'a pas besoin d'instancier une méthode liée pour objet.
  • Cela facilite la lisibilité du code et ne dépend pas de l'état de l'objet lui-même;
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, pouvant être remplacée par la sous-classe. Cela & # 8217; s parce que le premier argument de la <=> fonction doit toujours être cls (classe).

  • Les méthodes d'usine , 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

Laissez-moi vous 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. Dans un sens, les deux méthodes sont donc les méthodes de la classe .

Différence : une méthode de classe recevra la classe elle-même en tant que 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, elle est simplement suspendue parce qu’elle peut avoir une fonctionnalité connexe.

>>> class Klaus:
        @classmethod
        def classmthd(*args):
            return args

        @staticmethod
        def staticmthd(*args):
            return args

# 1. Call classmethod without any arg
>>> Klaus.classmthd()  
(__main__.Klaus,)  # the class gets passed as the first argument

# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')

# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()  
()

# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)

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

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

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

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

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

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 <=> dans <=>, mais vous vous répétez (si le nom de <=> change, vous devez vous rappeler de mettre à jour cette méthode <=>).

Pour moi, il s'agit d'une légère violation du principe d'ouverture / de fermeture , car une décision prise dans <=> a une incidence sur votre capacité à refactoriser le code commun dans une classe dérivée (c'est-à-dire qu'il est moins ouvert à l'extension). Si <=> était un <=> tout irait 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: <=>

Je vais essayer d'expliquer la différence fondamentale à l'aide d'un exemple.

class A(object):
    x = 0

    def say_hi(self):
        pass

    @staticmethod
    def say_hi_static():
        pass

    @classmethod
    def say_hi_class(cls):
        pass

    def run_self(self):
        self.x += 1
        print self.x # outputs 1
        self.say_hi()
        self.say_hi_static()
        self.say_hi_class()

    @staticmethod
    def run_static():
        print A.x  # outputs 0
        # A.say_hi() #  wrong
        A.say_hi_static()
        A.say_hi_class()

    @classmethod
    def run_class(cls):
        print cls.x # outputs 0
        # cls.say_hi() #  wrong
        cls.say_hi_static()
        cls.say_hi_class()

1 - nous pouvons appeler directement des méthodes statique et classmethod sans initialiser

# A.run_self() #  wrong
A.run_static()
A.run_class()

2- La méthode statique ne peut pas appeler la méthode auto, mais peut appeler d'autres méthodes statiques et méthodes de classe

3- Les méthodes statiques appartiennent à la classe et n'utiliseront pas d'objet du tout.

4- Les méthodes de classe ne sont pas liées à un objet mais à une classe.

@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 .... J'ai particulièrement trouvé utile de créer des singletons ..:)

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

Ma contribution montre la différence entre les méthodes @classmethod, @staticmethod et d'instance, notamment la manière dont une instance peut appeler indirectement un <=>. Mais au lieu d'appeler indirectement un <=> depuis une instance, le rendre privé peut être plus & "Pythonique. &"; Obtenir quelque chose d'une méthode privée n'est pas démontré ici mais c'est fondamentalement le même concept.

#!python3

from os import system
system('cls')
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

class DemoClass(object):
    # instance methods need a class instance and
    # can access the instance through 'self'
    def instance_method_1(self):
        return 'called from inside the instance_method_1()'

    def instance_method_2(self):
        # an instance outside the class indirectly calls the static_method
        return self.static_method() + ' via instance_method_2()'

    # class methods don't need a class instance, they can't access the
    # instance (self) but they have access to the class itself via 'cls'
    @classmethod
    def class_method(cls):
        return 'called from inside the class_method()'

    # static methods don't have access to 'cls' or 'self', they work like
    # regular functions but belong to the class' namespace
    @staticmethod
    def static_method():
        return 'called from inside the static_method()'
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''

# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()

# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''

# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''

# call class_method()
print(democlassObj.class_method() + '\n')
'''  called from inside the class_method() '''

# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''

"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""

Comme son nom l'indique, les méthodes de classe sont utilisées pour modifier les classes et non les objets. Pour modifier les classes, ils modifieront les attributs de classe (et non 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, d’autre part, sont utilisées pour 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."

Vous pouvez envisager la différence entre:

Class A:
    def foo():  # no self parameter, no decorator
        pass

et

Class B:
    @staticmethod
    def foo():  # no self parameter
        pass

Cela a changé entre python2 et python3:

python2:

>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

python3:

>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

L'utilisation de @staticmethod pour les méthodes appelées directement à partir de la classe est donc devenue facultative en python3. Si vous souhaitez les appeler à la fois en classe et en instance, vous devez toujours utiliser le <=> décorateur.

Les autres cas ont été bien couverts par la réponse unutbus.

Analysez @staticmethod littéralement en fournissant des informations différentes.

Une méthode normale d'une classe est une méthode dynamique implicite qui prend l'instance en 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 celle utilisée en dehors d'une définition de classe.
Il est heureusement regroupé dans la classe afin de rester plus près de l'endroit où il est appliqué, ou vous pouvez faire défiler pour le trouver.

Réponse courte. Le premier argument:

  • méthode normale: le premier argument est l'objet actuel
  • classmethod: le premier argument est la classe de l'objet actuel
  • staticmethod: le premier argument est supprimé

Réponse plus longue:

méthode normale

Lorsque la méthode d'un objet est appelée, un argument supplémentaire self lui est automatiquement attribué en tant que premier argument. C'est la méthode

def f(self, x, y)

doit être appelé avec 2 arguments. classmethod est automatiquement transmis et il s'agit de l'objet lui-même .

méthode de classe

Lorsque la méthode est décorée

@classmethod
def f(cls, x, y)

l'argument fourni automatiquement n'est pas staticmethod, mais la classe de Math.

méthode statique

Lorsque la méthode est décorée

@staticmethod
def f(x, y)

la méthode ne reçoit aucun argument automatique. Il n’est donné que les paramètres avec lesquels il est appelé.

usages

  • <=> est principalement utilisé pour les constructeurs alternatifs.
  • <=> n'utilise pas l'état de l'objet. Ce pourrait être une fonction externe à une classe. Il ne place dans la classe que le regroupement de fonctions ayant des fonctionnalités similaires (par exemple, comme les méthodes statiques <=> class de Java)
class Point
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def frompolar(cls, radius, angle):
        """The `cls` argument is the `Point` class itself"""
        return cls(radius * cos(angle), radius * sin(angle))

    @staticmethod
    def angle(x, y):
        return atan(y, x)


p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)

angle = Point.angle(3, 2)

Un rapide coup d'œil à d'autres méthodes identiques dans iPython révèle que @staticmethod génère des gains de performance marginaux (en nanosecondes), mais sinon, il semble ne pas servir à rien. En outre, les gains de performances seront probablement annulés par le travail supplémentaire de traitement de la méthode via staticmethod() lors de la compilation (ce qui se produit avant toute exécution de code lorsque vous exécutez un script).

Par souci de lisibilité du code, j’éviterais <=> que votre méthode ne soit utilisée que pour des charges de travail où le nombre de nanosecondes est compté.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top