Question Méthodes statiques en Python?


Est-il possible d'avoir des méthodes statiques en Python afin que je puisse les appeler sans initialiser une classe, comme:

ClassName.StaticMethod ( )

1391
2018-04-09 21:23


origine


Réponses:


Ouais, en utilisant le staticmethod décorateur

class MyClass(object):
    @staticmethod
    def the_static_method(x):
        print x

MyClass.the_static_method(2) # outputs 2

Notez que certains codes peuvent utiliser l'ancienne méthode de définition d'une méthode statique, en utilisant staticmethod en tant que fonction plutôt que d'un décorateur. Cela ne devrait être utilisé que si vous devez supporter des versions anciennes de Python (2.2 et 2.3)

class MyClass(object):
    def the_static_method(x):
        print x
    the_static_method = staticmethod(the_static_method)

MyClass.the_static_method(2) # outputs 2

Ceci est entièrement identique au premier exemple (en utilisant @staticmethod), n'utilisant pas la belle syntaxe du décorateur

Enfin, utilisez staticmethod() avec parcimonie! Il y a très peu de situations où les méthodes statiques sont nécessaires en Python, et je les ai vues utilisées plusieurs fois où une fonction séparée de «premier niveau» aurait été plus claire.


Ce qui suit est mot pour mot de la documentation::

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

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

La forme @staticmethod est une fonction décorateur - Voir la description des définitions de fonctions dans Définitions de fonction pour plus de détails.

Il peut être appelé soit sur la classe (comme C.f()) ou sur une instance (telle que C().f()). L'instance est ignorée sauf pour sa classe.

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

Pour plus d'informations sur les méthodes statiques, consultez la documentation sur la hiérarchie de types standard dans La hiérarchie de types standard.

Nouveau dans la version 2.2.

Modifié dans la version 2.4: Ajout de la syntaxe du décorateur de fonction.


1696
2018-04-09 21:24



je pense que Steven a raison. Pour répondre à la question d'origine, alors, afin de mettre en place une méthode de classe, supposons simplement que le premier argument ne sera pas une instance d'appel, puis assurez-vous que vous n'appelez que la méthode de la classe.

(Notez que cette réponse fait référence à Python 3.x. Dans Python 2.x, vous obtiendrez un TypeError pour appeler la méthode sur la classe elle-même.)

Par exemple:

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    def rollCall(n): #this is implicitly a class method (see comments below)
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))

fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)

Dans ce code, la méthode "rollCall" suppose que le premier argument n'est pas une instance (comme ce serait le cas si elle était appelée par une instance au lieu d'une classe). Tant que "rollCall" est appelé à partir de la classe plutôt que d'une instance, le code fonctionnera correctement. Si nous essayons d'appeler "rollCall" à partir d'une instance, par exemple:

rex.rollCall(-1)

cependant, cela entraînerait une exception car il enverrait deux arguments: lui-même et -1, et "rollCall" est seulement défini pour accepter un argument.

Par ailleurs, rex.rollCall () enverrait le nombre correct d'arguments, mais provoquerait également une exception, car maintenant n représenterait une instance Dog (c'est-à-dire, rex) lorsque la fonction s'attend à ce que n soit numérique.

C'est là que la décoration vient: Si nous précédons la méthode "rollCall" avec

@staticmethod

puis, en indiquant explicitement que la méthode est statique, nous pouvons même l'appeler à partir d'une instance. À présent,

rex.rollCall(-1)

travaillerait. L'insertion de @staticmethod avant une définition de méthode empêche alors une instance de s'envoyer elle-même en tant qu'argument.

Vous pouvez le vérifier en essayant le code suivant avec et sans la ligne @staticmethod commentée.

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    @staticmethod
    def rollCall(n):
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))


fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)

176
2018-04-18 09:16



Oui, consultez le staticmethod décorateur:

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World

74
2018-04-09 21:24



Vous n'avez pas vraiment besoin d'utiliser le @staticmethod décorateur. Déclarer simplement une méthode (qui n'attend pas le paramètre self) et l'appeler depuis la classe. Le décorateur n'est là que si vous voulez pouvoir l'appeler depuis une instance (ce qui n'était pas ce que vous vouliez faire)

La plupart du temps, vous n'utilisez que des fonctions ...


43
2018-04-10 16:00



Méthodes statiques en Python?

Est-il possible d'avoir des méthodes statiques en Python afin que je puisse les appeler   sans initialiser une classe, comme:

ClassName.StaticMethod()

Oui, des méthodes statiques peuvent être créées comme ça (même si c'est un peu plus Pythonic utiliser des underscores à la place de CamelCase pour les méthodes):

class ClassName(object):

    @staticmethod
    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

Ce qui précède utilise la syntaxe du décorateur. Cette syntaxe est équivalente à

class ClassName(object):

    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

    static_method = staticmethod(static_method)

Cela peut être utilisé comme vous l'avez décrit:

ClassName.static_method()

Un exemple intégré d'une méthode statique est str.maketrans() en Python 3, qui était une fonction dans le string module dans Python 2.


Une autre option que vous pouvez utiliser est la suivante: classmethod, la différence est que classmethod obtient la classe en tant que premier argument implicite, et s'il est sous-classé, il obtient la sous-classe en tant que premier argument implicite.

class ClassName(object):

    @classmethod
    def class_method(cls, kwarg1=None):
        '''return a value that is a function of the class and kwarg1'''

Notez que cls n'est pas un nom obligatoire pour le premier argument, mais la plupart des codeurs Python expérimentés le considéreront mal si vous utilisez autre chose.

Ceux-ci sont généralement utilisés comme constructeurs alternatifs.

new_instance = ClassName.class_method()

Un exemple intégré est dict.fromkeys():

new_dict = dict.fromkeys(['key1', 'key2'])

28
2018-01-24 04:34



Mis à part les particularités de comment objets de méthode statique se comporter, il y a un certain type de beauté que vous pouvez frapper avec eux quand il s'agit d'organiser votre code au niveau du module.

# garden.py
def trim(a):
    pass

def strip(a):
    pass

def bunch(a, b):
    pass

def _foo(foo):
    pass

class powertools(object):
    """
    Provides much regarded gardening power tools.
    """
    @staticmethod
    def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
        return 42

    @staticmethod
    def random():
        return 13

    @staticmethod
    def promise():
        return True

def _bar(baz, quux):
    pass

class _Dice(object):
    pass

class _6d(_Dice):
    pass

class _12d(_Dice):
    pass

class _Smarter:
    pass

class _MagicalPonies:
    pass

class _Samurai:
    pass

class Foo(_6d, _Samurai):
    pass

class Bar(_12d, _Smarter, _MagicalPonies):
    pass

...

# tests.py
import unittest
import garden

class GardenTests(unittest.TestCase):
    pass

class PowertoolsTests(unittest.TestCase):
    pass

class FooTests(unittest.TestCase):
    pass

class BarTests(unittest.TestCase):
    pass

...

# interactive.py
from garden import trim, bunch, Foo

f = trim(Foo())
bunch(f, Foo())

...

# my_garden.py
import garden
from garden import powertools

class _Cowboy(garden._Samurai):
    def hit():
        return powertools.promise() and powertools.random() or 0

class Foo(_Cowboy, garden.Foo):
    pass

Il devient maintenant un peu plus intuitif et auto-documentant dans quel contexte certains composants sont destinés à être utilisés et il idéalement pour nommer des cas de test distincts ainsi que d'avoir une approche directe de la cartographie des modules de test aux modules réels pour les puristes .

Je trouve souvent viable d'appliquer cette approche à l'organisation du code d'utilité d'un projet. Assez souvent, les gens se précipitent et créent un utils paquet et se retrouver avec 9 modules dont un a 120 LOC et le reste sont deux douzaines LOC au mieux. Je préfère commencer par cela et le convertir en un paquet et créer des modules uniquement pour les bêtes qui les méritent vraiment:

# utils.py
class socket(object):
    @staticmethod
    def check_if_port_available(port):
        pass

    @staticmethod
    def get_free_port(port)
        pass

class image(object):
    @staticmethod
    def to_rgb(image):
        pass

    @staticmethod
    def to_cmyk(image):
        pass

9
2017-12-29 19:47



L'option la plus simple est peut-être simplement de mettre ces fonctions en dehors de la classe:

class Dog(object):
    def __init__(self, name):
        self.name = name

    def bark(self):
        if self.name == "Doggy":
            return barking_sound()
        else:
            return "yip yip"

def barking_sound():
    return "woof woof"

En utilisant cette méthode, les fonctions qui modifient ou utilisent l'état d'objet interne (ont des effets secondaires) peuvent être conservées dans la classe, et les fonctions utilitaires réutilisables peuvent être déplacées à l'extérieur.

Disons que ce fichier est appelé dogs.py. Pour les utiliser, vous appelez dogs.barking_sound() au lieu de dogs.Dog.barking_sound.

Si vous avez vraiment besoin d'une méthode statique pour faire partie de la classe, vous pouvez utiliser staticmethod décorateur.


7
2017-07-30 16:10



Je rencontre cette question de temps en temps. Le cas d'utilisation et l'exemple que j'aime:

jeffs@jeffs-desktop:/home/jeffs  $ python36
Python 3.6.1 (default, Sep  7 2017, 16:36:03) 
[GCC 6.3.0 20170406] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> print(cmath.sqrt(-4))
2j
>>>
>>> dir(cmath)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
>>> 

Cela n'a aucun sens de créer un objet de classe cmath, car il n'y a pas d'état dans un objet cmath. Cependant, cmath est une collection de méthodes qui sont toutes liées d'une manière ou d'une autre. Dans mon exemple ci-dessus, toutes les fonctions de cmath agissent sur des nombres complexes d'une manière ou d'une autre.


-1
2018-01-08 06:53