web-dev-qa-db-fra.com

Méthodes statiques en Python?

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

ClassName.StaticMethod ( )
1606
Joan Venge

Oui, en utilisant la méthode statique 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 comme fonction plutôt que comme décorateur. Cela ne devrait être utilisé que si vous devez supporter les anciennes versions 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

C'est tout à fait identique au premier exemple (en utilisant @staticmethod), mais en n'utilisant pas la syntaxe de Nice Decorator

Enfin, utilisez staticmethod() avec parcimonie! Il existe très peu de situations dans lesquelles les méthodes statiques sont nécessaires en Python, et je les ai souvent vues utilisées pour lesquelles une fonction "de niveau supérieur" distincte aurait été plus claire.


Le texte suivant est extrait de la documentation: :

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 une fonction décorateur - voir la description des définitions de fonctions dans Définitions des fonctions pour plus de détails.

Il peut être appelé soit sur la classe (telle que C.f()), soit sur une instance (telle que C().f()). L'instance est ignorée à l'exception de 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 des types standard dans . La hiérarchie des types standard .

Nouveau dans la version 2.2.

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

1922
dbr

Je pense que Steven a effectivement raison . Pour répondre à la question initiale, pour configurer une méthode de classe, supposez simplement que le premier argument ne sera pas une instance d'appel, puis assurez-vous que vous appelez uniquement la méthode à partir 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 s'il était appelé par une instance au lieu d'une classe). Tant que "rollCall" est appelé depuis la classe plutôt que par une instance, le code fonctionnera correctement. Si nous essayons d’appeler "rollCall" à partir d’une instance, par exemple:

rex.rollCall(-1)

cependant, une exception serait déclenchée car elle enverrait deux arguments: elle-même et -1, et "rollCall" n'est défini que pour accepter un argument.

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

C’est là que la décoration entre en scène: si nous précédons la méthode "rollCall" avec

@staticmethod

ensuite, en indiquant explicitement que la méthode est statique, on peut même l'appeler à partir d'une instance. Maintenant,

rex.rollCall(-1)

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

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

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)
205
Richard Ambler

Oui, consultez le staticmethod décorateur:

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

Vous n'avez pas vraiment besoin d'utiliser le décorateur @staticmethod. Il suffit de déclarer une méthode (qui n'attend pas le paramètre self) et de l'appeler depuis la classe. Le décorateur n’est présent qu’au cas où vous souhaiteriez pouvoir l’appeler à partir d’une instance également (ce qui n’était pas ce que vous vouliez faire)

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

49
Steven

Méthodes statiques en Python?

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

ClassName.StaticMethod()

Oui, les méthodes statiques peuvent être créées comme ceci (bien que ce soit un peu plus Pythonic pour utiliser des traits de soulignement au lieu 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 de 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)

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

ClassName.static_method()

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


Une autre option qui peut être utilisée comme vous le décrivez est la variable classmethod. La différence réside dans le fait que la méthode de classe obtient la classe en tant que premier argument implicite et, si elle est sous-classe, elle 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 requis pour le premier argument, mais les codeurs les plus expérimentés Python considéreront que c'est mal fait si vous utilisez autre chose.

Ceux-ci sont généralement utilisés en tant que constructeurs alternatifs.

new_instance = ClassName.class_method()

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

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

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"

À l'aide de 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 s'appelle dogs.py. Pour les utiliser, 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 le décorateur staticmethod .

10
Matt Woelk

Mis à part les particularités de la manière dont objets de méthode statique , il existe un certain type de beauté que vous pouvez frapper avec eux lorsqu'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-documenté dans lequel certains composants sont censés être utilisés. Il convient parfaitement pour nommer des cas de test distincts et pour une approche directe de la façon dont les modules de test sont mappés aux modules réels soumis à des tests pour des puristes. .

Je trouve souvent qu'il est viable d'appliquer cette approche à l'organisation du code d'utilité d'un projet. Très souvent, les gens se précipitent immédiatement pour créer un paquetage utils et se retrouvent avec 9 modules, dont l’un a 120 LOC et le reste, au mieux, deux douzaines de LOC. Je préfère commencer par ceci 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
10
Filip Dupanović

Donc, les méthodes statiques sont les méthodes qui peuvent être appelées sans créer l'objet d'une classe. Par exemple :-

    @staticmethod
    def add(a, b):
        return a + b

b = A.add(12,12)
print b

Dans l'exemple ci-dessus, la méthode add est appelée par le nom de classe A et non par le nom de l'objet.

0
Aman Raheja