Quel est l'avantage d'utiliser des méthodes statiques en Python?

90

J'ai rencontré une erreur de méthode non liée en python avec le code

import random

class Sample(object):
'''This class defines various methods related to the sample'''

    def drawSample(samplesize,List):
        sample=random.sample(List,samplesize)
        return sample

Choices=range(100)
print Sample.drawSample(5,Choices)

Après avoir lu de nombreux articles utiles ici, j'ai compris comment je pourrais ajouter @staticmethodci-dessus pour que le code fonctionne. Je suis un novice en python. Quelqu'un peut-il expliquer pourquoi on voudrait définir des méthodes statiques? Ou pourquoi toutes les méthodes ne sont-elles pas définies comme des méthodes statiques?

Curieux2learn
la source
1
C'est une question étrange. Les méthodes statiques sont une nécessité de conception . Ce n'est pas un "avantage". Vous les utilisez parce que vous devez. C'est une caractéristique de conception d'une classe d'avoir des méthodes statiques. Demandez-vous quelles sont les méthodes statiques en premier lieu? Je pense que la question pourrait être reformulée pour définir plus clairement ce que vous devez savoir.
S.Lott
15
Non, je ne voulais pas savoir ce qu'ils sont. Ce que je voulais savoir, c'est pourquoi est-ce une «nécessité», qui est devenue claire à partir des réponses données par d'autres. C'est à ce moment-là que vous le définiriez plutôt que les méthodes non statiques. Merci.
Curious2learn
3
@ S.Lott: Quand utiliser une méthode statique est-il une nécessité par opposition à l'utilisation d'une méthode de classe normale? Pour autant que je sache, une méthode de classe peut faire tout ce qu'une méthode statique peut faire. Staticmethod a des "avantages" énumérés ailleurs dans cet article, mais je ne vois aucune raison pour laquelle une méthode de classe ne peut pas être utilisée dans un endroit où une méthode statique peut être utilisée, ce qui en fait une nécessité.
RFV

Réponses:

128

Les méthodes statiques ont une utilisation limitée, car elles n'ont pas accès aux attributs d'une instance d'une classe (comme le fait une méthode régulière), et elles n'ont pas accès aux attributs de la classe elle-même (comme le fait une méthode de classe ).

Ils ne sont donc pas utiles pour les méthodes quotidiennes.

Cependant, ils peuvent être utiles pour regrouper une fonction utilitaire avec une classe - par exemple une simple conversion d'un type à un autre - qui n'a pas besoin d'accéder à des informations en dehors des paramètres fournis (et peut-être des attributs globaux au module. )

Ils pourraient être mis en dehors de la classe, mais les regrouper à l'intérieur de la classe peut avoir un sens là où ils ne sont applicables que là-bas.

Vous pouvez également référencer la méthode via une instance ou la classe, plutôt que le nom du module, ce qui peut aider le lecteur à comprendre à quelle instance la méthode est liée.

Pensée étrange
la source
8
@ Curious2learn: Pas toutes , mais certaines méthodes sont utiles en tant que méthodes statiques. Pensez à un exemple de Localeclasse, dont les instances seront locales (duh). Une getAvailableLocales()méthode serait un bel exemple de méthode statique d'une telle classe: elle appartient clairement à la classe Locale, tout en n'appartenant clairement à aucune instance particulière.
MestreLion
... et ce n'est pas non plus une méthode de classe, car il peut ne pas avoir besoin d'accéder aux méthodes des classes.
MestreLion
Un éditeur souligne qu'une méthode statique peut accéder aux attributs de classe, en naviguant explicitement vers le bas depuis le class_name.attribute, mais pas cls.attributeou self.attribute. Ceci est vrai pour les attributs "publics". Par convention, vous ne devriez pas accéder aux attributs masqués par un trait de soulignement, ou aux noms mutilés avec deux traits de soulignement, de cette façon. Cela signifie également que votre code sera plus fragile lorsque les attributs changeront de place dans la hiérarchie d'héritage.
Oddthinking
Une citation de Guido qui aide à décider quand utiliser les méthodes statiques (jamais): «Nous savons tous à quel point les méthodes statiques sont limitées. , Je voulais implémenter des méthodes de classe, mais au début, je ne les ai pas comprises et j'ai implémenté accidentellement des méthodes statiques en premier. Ensuite, il était trop tard pour les supprimer et ne fournir que des méthodes de classe. "
Boris Churzin
189

Consultez cet article pour une explication détaillée.

TL; DR

1.Il élimine l'utilisation de l' selfargument.

Cela réduit l'utilisation de la mémoire car Python n'a pas besoin d'instancier une méthode liée pour chaque objet instiantié:

>>>RandomClass().regular_method is RandomClass().regular_method
False
>>>RandomClass().static_method is RandomClass().static_method
True
>>>RandomClass.static_method is RandomClass().static_method
True

3. Il améliore la lisibilité du code, ce qui signifie que la méthode ne dépend pas de l'état de l'objet lui-même.

4.Il permet le remplacement de méthode en ce que si la méthode était définie au niveau du module (c'est-à-dire en dehors de la classe), une sous-classe ne serait pas en mesure de remplacer cette méthode.

zanetu
la source
3
Cela devrait être la réponse acceptée. Le fait que la méthode statique sur toutes les instances et la classe elle-même soient le même objet est un réel avantage, en particulier lorsque vous avez beaucoup d'instances (par exemple, chaque instance pour un enregistrement de base de données mutable).
Zhuoyun Wei
+1 et d'accord avec @ZhuoyunWei. Seule réponse qui explique les quelques raisons pour lesquelles une méthode statique est parfois préférable à une méthode de classe (bien que 1 et 3 soient vraiment la même raison).
Alex
1
La meilleure réponse à "pourquoi la méthode statique", mais la question originale posée également "pourquoi toutes les méthodes ne sont-elles pas statiques?". Un court "pas d'accès aux attributs d'instance" couvrirait cela aussi.
Exu
IMO le seul véritable avantage est que vous pouvez le remplacer dans une sous-classe, mais même cela donne l'impression que vous faites quelque chose de mal en termes de POO, dans quel cas d'utilisation feriez-vous cela?
Boris Churzin le
23

Ce n'est pas tout à fait au point de votre question réelle, mais puisque vous avez dit que vous êtes un débutant en python, cela sera peut-être utile, et personne d'autre ne l'a dit explicitement.

Je n'aurais jamais corrigé le code ci-dessus en faisant de la méthode une méthode statique. J'aurais soit abandonné la classe et juste écrit une fonction:

def drawSample(samplesize,List):
    sample=random.sample(List,samplesize)
    return sample

Choices=range(100)
print drawSample(5,Choices)

Si vous avez de nombreuses fonctions associées, vous pouvez les regrouper dans un module - c'est-à-dire les mettre toutes dans le même fichier, nommé sample.pypar exemple; puis

import sample

Choices=range(100)
print sample.drawSample(5,Choices)

Ou j'aurais ajouté une __init__méthode à la classe et créé une instance qui avait des méthodes utiles:

class Sample(object):
'''This class defines various methods related to the sample'''

    def __init__(self, thelist):
        self.list = thelist

    def draw_sample(self, samplesize):
        sample=random.sample(self.list,samplesize)
        return sample

choices=Sample(range(100))
print choices.draw_sample(5)

(J'ai également modifié les conventions de casse dans l'exemple ci-dessus pour qu'elles correspondent au style recommandé par PEP 8.)

L'un des avantages de Python est qu'il ne vous oblige pas à utiliser des classes pour tout. Vous ne pouvez les utiliser que lorsqu'il y a des données ou un état qui doivent être associés aux méthodes, ce à quoi servent les classes. Sinon, vous pouvez utiliser des fonctions, à quoi servent les fonctions.

Vicki Laidler
la source
Merci pour le commentaire. J'ai eu besoin d'une classe dans ce cas parce que je veux travailler avec l'échantillon dessiné. Non, je n'ai pas utilisé de méthode statique, mais je voulais en savoir plus, car je suis tombé sur le terme en recherchant des informations sur le message d'erreur que j'ai reçu. Mais vos conseils sur la collecte des fonctions dans un module sans définir de classe seraient utiles pour d'autres fonctions dont j'ai besoin. Donc merci.
Curious2learn
4
+1: C'était une belle explication sur certaines idées fausses du PO. Et vous avez été très honnête de dire, dès le départ, que vous ne répondiez pas réellement à sa question sur les méthodes statiques, mais que vous avez plutôt donné une bien meilleure solution en disant que son problème ne nécessite pas du tout de cours.
MestreLion
22

Pourquoi voudrait-on définir des méthodes statiques ?

Supposons que nous ayons un classappelé Mathalors

personne ne voudra créer un objet class Math
et ensuite invoquer des méthodes comme ceilet flooret fabssur lui.

Alors nous les fabriquons static.

Par exemple faire

>> Math.floor(3.14)

est bien mieux que

>> mymath = Math()
>> mymath.floor(3.14)

Ils sont donc utiles d'une certaine manière. Vous n'avez pas besoin de créer une instance d'une classe pour les utiliser.

Pourquoi toutes les méthodes ne sont-elles pas définies comme des méthodes statiques ?

Ils n'ont pas accès aux variables d'instance.

class Foo(object):
    def __init__(self):
        self.bar = 'bar'

    def too(self):
        print self.bar

    @staticmethod
    def foo():
        print self.bar

Foo().too() # works
Foo.foo() # doesn't work

C'est pourquoi nous ne rendons pas toutes les méthodes statiques.

Pratik Deoghare
la source
10
Mais pourquoi pas un package mathématique? Python a des packages pour cela, vous n'avez pas besoin d' une définition de classe pour créer un espace de noms.
extraneon
6
@extraneon: Ouais mec, je le sais mais je voulais avoir quelque chose de simple et familier pour l'explication, alors j'ai utilisé Math. C'est pourquoi j'ai capitalisé M.
Pratik Deoghare
6
Le PO n'a pas demandé ce que sont les méthodes statiques. Il a demandé quel était leur avantage. Vous expliquez comment les utiliser, pas en quoi sont-ils utiles. Dans votre exemple particulier, un espace de noms aurait beaucoup plus de sens.
Javier
4
-1: Explication bonne et correcte, mais un exemple très mal choisi: il n'y a aucune raison pour que vous Mathsoyez une classe en premier lieu, un module conviendrait mieux. Essayez de trouver un exemple de classe qui a du sens en tant que classe, pas une classe dont "personne ne voudra créer un objet" .
MestreLion
3
Et puis donnez un exemple de cas d'utilisation légitime pour qu'une (ou certaines ) méthodes des classes soient statiques, mais pas toutes . Si toutes les méthodes d'une classe sont statiques, la classe doit être un module. Si aucun n'est statique, vous ne répondez pas à la question.
MestreLion
13

Lorsque vous appelez un objet fonction à partir d'une instance d'objet, il devient une «méthode liée» et obtient que l'objet d'instance lui-même est passé en tant que premier argument.

Lorsque vous appelez un classmethodobjet (qui encapsule un objet fonction) sur une instance d'objet, la classe de l'objet instance est transmise comme premier argument.

Lorsque vous appelez un staticmethodobjet (qui encapsule un objet fonction), aucun premier argument implicite n'est utilisé.

class Foo(object):

    def bar(*args):
        print args

    @classmethod
    def baaz(*args):
        print args

    @staticmethod
    def quux(*args):
        print args

>>> foo = Foo()

>>> Foo.bar(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got int instance instead)
>>> Foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> Foo.quux(1,2,3)
(1, 2, 3)

>>> foo.bar(1,2,3)
(<Foo object at 0x1004a4510>, 1, 2, 3)
>>> foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> foo.quux(1,2,3)
(1, 2, 3)
Matt Anderson
la source
3
+1: Enfin une excellente explication sur ce que sont les méthodes statiques et les méthodes de classe. Bien que vous n'ayez pas expliqué pourquoi on voudrait un jour utiliser une méthode statique, au moins vous avez clairement expliqué dans un exemple simple ce que les deux sont bien meilleurs que les documents officiels.
MestreLion
3

Les méthodes statiques sont excellentes car vous n'avez pas à déclarer une instance de l'objet auquel appartient la méthode.

Le site de python a une excellente documentation sur les méthodes statiques ici:
http://docs.python.org/library/functions.html#staticmethod

David Fox
la source
Merci David. Mais pourquoi alors ne pas définir chaque méthode comme une méthode statique, puisqu'elles fonctionnent également sur des instances. Y a-t-il des inconvénients à le faire?
Curious2learn
4
@ Curious2learn: Non, avec les méthodes statiques, vous n'avez pas accès à l'instance: l'instance est ignorée sauf pour sa classe.
Felix Kling
4
Cet argument serait vrai en Java, où les fonctions ne peuvent pas vivre par elles-mêmes mais sont toujours définies dans le contexte d'une classe. Mais en Python, vous pouvez avoir des fonctions et des fonctions de classe statiques. Cette réponse ne montre pas vraiment pourquoi choisir une méthode statique au lieu d'une méthode n'appartenant pas à une classe.
extraneon
1
@extraneon - c'est plus une question de préférences d'organisation du code; avoir des méthodes statiques donne une option supplémentaire.
Charles Duffy
@Felix - Merci. Cela clarifie pourquoi chaque méthode ne doit pas être une méthode statique.
Curious2learn
3

Les alternatives à une staticmethodsont: classmethod, instancemethodet function. Si vous ne savez pas ce que c'est, faites défiler jusqu'à la dernière section. Si a staticmethodest meilleur que l'une de ces alternatives, cela dépend de l'objectif dans lequel il est écrit.

avantages de la méthode statique Python

  • Si vous n'avez pas besoin d'accéder aux attributs ou aux méthodes de la classe ou de l'instance, a staticmethodvaut mieux que classmethodou instancemethod. De cette façon, il est clair (d'après le @staticmethoddécorateur) que l'état de la classe et de l'instance n'est ni lu ni modifié. Cependant, l'utilisation d'un functionrend cette distinction encore plus claire (voir les inconvénients).
  • La signature d'appel de a staticmethodest la même que celle de a classmethodou instancemethod, à savoir <instance>.<method>(<arguments>). Par conséquent, il peut facilement être remplacé par l'un des trois si cela est nécessaire plus tard ou dans une classe dérivée. Vous ne pouvez pas faire ça avec un simplefunction .
  • A staticmethodpeut être utilisé à la place de a functionpour indiquer clairement qu'il appartient subjectivement à une classe et pour éviter les conflits d'espace de noms.

inconvénients de la méthode statique Python

  • Il ne peut pas accéder aux attributs ou aux méthodes de l'instance ou de la classe.
  • La signature d'appel de a staticmethodest la même que celle de a classmethodou instancemethod. Cela masque le fait que le staticmethodne lit ni ne modifie réellement aucune information d'objet. Cela rend le code plus difficile à lire. Pourquoi ne pas simplement utiliser un function?
  • A staticmethodest difficile à réutiliser si jamais vous avez besoin de l'appeler depuis l'extérieur de la classe / instance où il a été défini. S'il existe un potentiel de réutilisation, a functionest le meilleur choix.
  • Le staticmethodest rarement utilisé, donc les personnes qui lisent du code qui en contient un peuvent prendre un peu plus de temps à le lire.

alternatives à une méthode statique en Python

Pour discuter des avantages du staticmethod, nous devons savoir quelles sont les alternatives et en quoi elles diffèrent les unes des autres.

  • Le staticmethodappartient à une classe mais ne peut accéder ni modifier les informations d'instance ou de classe.

Il existe trois alternatives:

  • Le classmethoda accès à la classe de l'appelant.
  • Le instancemethoda accès à l'instance de l'appelant et à sa classe.
  • Le functionn'a rien à voir avec les cours. C'est le plus proche en capacité du staticmethod.

Voici à quoi cela ressemble dans le code:

# function
# has nothing to do with a class
def make_cat_noise(asker_name):
    print('Hi %s, mieets mieets!' % asker_name)

# Yey, we can make cat noises before we've even defined what a cat is!
make_cat_noise('JOey')  # just a function

class Cat:
    number_of_legs = 4

    # special instance method __init__
    def __init__(self, name):
        self.name = name

    # instancemethod
    # the instance (e.g. Cat('Kitty')) is passed as the first method argument
    def tell_me_about_this_animal(self, asker_name):
        print('Hi %s, This cat has %d legs and is called %s'
              % (asker_name, self.number_of_legs, self.name))

    # classmethod
    # the class (e.g. Cat) is passed as the first method argument
    # by convention we call that argument cls
    @classmethod
    def tell_me_about_cats(cls, asker_name):
        print("Hi %s, cats have %d legs."
              % (asker_name, cls.number_of_legs))
        # cls.name  # AttributeError because only the instance has .name
        # self.name  # NameError because self isn't defined in this namespace

    # staticmethod
    # no information about the class or the instance is passed to the method
    @staticmethod
    def make_noise(asker_name):
        print('Hi %s, meooow!' % asker_name)
        # class and instance are not accessible from here

# one more time for fun!
make_cat_noise('JOey')  # just a function

# We just need the class to call a classmethod or staticmethod:
Cat.make_noise('JOey')  # staticmethod
Cat.tell_me_about_cats('JOey')  # classmethod
# Cat.tell_me_about_this_animal('JOey')  # instancemethod -> TypeError

# With an instance we can use instancemethod, classmethod or staticmethod
mycat = Cat('Kitty')  # mycat is an instance of the class Cat
mycat.make_noise('JOey')  # staticmethod
mycat.tell_me_about_cats('JOey')  # classmethod
mycat.tell_me_about_this_animal('JOey')  # instancemethod
Joooeey
la source
1

Parce que les fonctions d'espacement de noms sont agréables (comme cela a été souligné précédemment):

  1. Lorsque je veux être explicite sur les méthodes qui ne changent pas l'état de l'objet, j'utilise des méthodes statiques. Cela décourage les membres de mon équipe de commencer à modifier les attributs de l'objet dans ces méthodes.

  2. Quand je refactorise du code vraiment pourri, je commence par essayer de créer autant de méthodes @staticmethodque possible. Cela me permet ensuite d'extraire ces méthodes dans une classe - bien que je sois d'accord, c'est rarement quelque chose que j'utilise, cela m'a été utile à quelques reprises.

vlad-ardelean
la source
1

À mon avis, il n'y a pas un seul avantage en termes de performances à utiliser @staticmethods par rapport à la simple définition de la fonction en dehors de et distincte de la classe dont elle serait autrement une @staticmethod.

La seule chose que je dirais justifie leur existence, c'est la commodité. Les méthodes statiques sont courantes dans d'autres langages de programmation populaires, alors pourquoi pas python? Si vous souhaitez créer une fonction avec un comportement qui est très étroitement associé à la classe pour laquelle vous la créez mais qu'elle n'accède pas / ne modifie pas réellement les données internes d'une instance de la classe d'une manière qui justifie sa conceptualisation méthode de cette classe puis gifler un@staticmethod au dessus et toute personne lisant votre code en apprendra immédiatement beaucoup sur la nature de la méthode et sa relation avec la classe.

Une chose que j'aime parfois faire est de placer des fonctionnalités que ma classe utilise beaucoup en interne dans des @staticmethods privés . De cette façon, je n'encombre pas l'API exposée par mon module avec des méthodes que personne qui utilise mon module n'aurait jamais besoin de voir et encore moins d'utiliser.

Garrett Gutierrez
la source
0

Les méthodes statiques n'ont presque aucune raison d'être en Python. Vous utilisez des méthodes d'instance ou des méthodes de classe.

def method(self, args):
    self.member = something

@classmethod
def method(cls, args):
    cls.member = something

@staticmethod
def method(args):
    MyClass.member = something
    # The above isn't really working
    # if you have a subclass
Georg Schölly
la source
Vous avez dit «presque». Y a-t-il un endroit où ils peuvent être meilleurs que les alternatives?
Javier
@Javier: Je ne peux pas penser à un, mais il y en a probablement un, pourquoi cette méthode serait-elle incluse dans la bibliothèque Python autrement?
Georg Schölly
1
@Javier, @Georg: Vous êtes convaincu que le corpus Python n'a pas de cruauté.
Charles Merriam
-1: Cette réponse ne présente aucun cas d'utilisation staticmethodni aucune explication de ce qu'est un classmethodou pourquoi et en quoi il est "meilleur" que les statiques.
MestreLion
@CharlesMerriam: Bien sûr, les méthodes statiques ont leur utilisation, sinon elles auraient été abandonnées ou obsolètes dans Python 3 (où la plupart des anciens cruft ont été supprimés). Il n'y a pas un seul mot contre staticmethoddans les documents pour soutenir votre affirmation selon laquelle c'est cruel, ou l'affirmation de Georg qui classmethoddevrait être utilisée à la place).
MestreLion