Les méthodes statiques en Python?

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

ClassName.StaticMethod ( )
1421
demandé sur BartoszKP 2009-04-10 01:23:19

9 réponses

Yep, à l'aide de la staticmethod décorateur

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

MyClass.the_static_method(2) # outputs 2

noter qu'un code pourrait utiliser l'ancienne méthode de définition d'une méthode statique, en utilisant staticmethod comme une fonction plutôt qu'un décorateur. Ceci ne doit ê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 pas en utilisant le décorateur de nice syntaxe

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


extrait textuel de la documentation: :

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

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

la forme @staticmethod est une fonction décorateur – 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 (comme C.f() ) ou sur une instance (comme C().f() ). Le l'instance est ignorée sauf pour sa classe.

Les méthodes statiques

en Python sont similaires à celles trouvées en Java ou en 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 type standard dans la hiérarchie de type standard .

nouveau dans la version 2.2.

modifié dans la version 2.4: ajout de la syntaxe de décorateur de fonction.

1725
répondu dbr 2015-10-15 17:10:50

je pense que Steven est en fait la droite . Pour répondre à la question d'origine, puis, afin de configurer une méthode de classe, il suffit de supposer que le premier argument ne va pas être une instance d'appel, et ensuite s'assurer que vous appelez seulement la méthode de la classe.

(notez que cette réponse se réfère à Python 3.x. En Python 2.x vous obtiendrez un TypeError pour avoir appelé 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 il le serait s'il était appelé par une instance au lieu d'une classe). Tant que" rollCall " est appelé de la classe plutôt qu'une instance, le code fonctionnera très bien. Si nous essayons d'appeler "rollCall" à partir d'une instance, par exemple:

rex.rollCall(-1)

cependant, il provoquerait une exception à être soulevé parce qu'il enverrait deux arguments: lui-même et -1, et "rollCall" est seulement défini pour accepter un argument.

soit dit en passant, rex.rollCall () enverrait le nombre correct d'arguments, mais causerait aussi une exception à être soulevée parce que maintenant n représenterait une instance Dog (i.e., rex) quand la fonction s'attend à ce que n soit numérique.

C'est ici que la décoration entre en jeu: 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)

marcherait. L'insertion de @staticmethod avant une définition de méthode, alors, empêche une instance de s'envoyer elle-même comme argument.

vous pouvez vérifier cela 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)
180
répondu Richard Ambler 2018-06-10 06:20:51

Oui, découvrez le staticmethod décorateur:

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World
74
répondu Paolo Bergantino 2009-04-09 21:24:15

Vous n'avez pas vraiment besoin d'utiliser le @staticmethod décorateur. Il suffit de déclarer une méthode (qui n'attend pas le paramètre self) et de l'appeler de la classe. Le Décorateur est seulement là au cas où vous voulez être en mesure de l'appeler d'une instance aussi bien (qui n'était pas ce que vous vouliez faire)

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

43
répondu hichris123 2015-12-14 00:29:47

méthodes Statiques en Python?

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

ClassName.StaticMethod()

Oui, les méthodes statiques peuvent être créés de cette façon (même si elle est un peu plus Pythonic à utiliser des tirets 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'''

ci-dessus utilise le décorateur de la syntaxe. 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 construit d'une méthode statique est str.maketrans() en Python 3, qui était une fonction dans le module string en Python 2.


une autre option qui peut être utilisée comme vous le décrivez est le classmethod , la différence est que la méthode classemet obtient la classe comme un premier argument implicite, et s'il est sous-classé, alors il obtient la sous-classe comme 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 la plupart des codeurs Python expérimentés considéreront qu'il est mal fait si vous utilisez autre chose.

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

new_instance = ClassName.class_method()

un exemple construit est dict.fromkeys() :

new_dict = dict.fromkeys(['key1', 'key2'])
29
répondu Aaron Hall 2015-12-26 05:30:07

outre les particularités de la façon dont les objets de la méthode statique se comportent, il y a un certain type de beauté que vous pouvez frapper avec eux quand il s'agit d'organiser votre code de niveau de 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 conçu pour être utilisé et il se décline idéalement pour nommer des cas de test distincts ainsi que d'avoir une approche simple à la façon dont les modules de test correspondent à des modules réels sous tests pour 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 et créent un paquet utils et finissent avec 9 modules dont l'un a 120 LOC et le reste sont deux douzaines de LOC au mieux. Je préfère commencer par ceci et convertissez-le en un paquet et créez 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
répondu Filip Dupanović 2015-09-23 14:42:54

peut-être l'option la plus simple est juste 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 interne de l'objet (ont des effets secondaires) peuvent être maintenues dans la classe, et les fonctions d'utilité réutilisables peuvent être déplacées à l'extérieur.

disons que ce fichier s'appelle dogs.py . Pour les utiliser, vous appelleriez dogs.barking_sound() au lieu de dogs.Dog.barking_sound .

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

9
répondu Matt Woelk 2016-01-11 15:31:57

En Python 3:

voici un autre bon à utiliser des méthodes non statiques car ils étaient des méthodes statiques.

class Account:
# here is the main class

# a non-static method
def login(self, url, email, password):
    # as a convention self is passed as a 
    # placeholder for the class Object itself

    self.login_url = url
    self.user_email = email
    self.user_password = password

    print(login_url, user_email, user_password)

Appeler un non-statique méthode statique

"""
* Referencing the Account.login(self, url, email, password)
* Just call the `Account` object as the self 
"""
Account.login(Account, "https://example.com/login", "email@example.com", "password_example")

:$ https://example.com/login email@example.com password_example
0
répondu Erisan Olasheni 2018-09-16 15:32:27

je rencontre cette question de temps en temps. Les cas d'utilisation et l'exemple que j'aime est:

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']
>>> 

il n'est pas logique de créer un objet de classe cmath, parce qu'il n'y a pas d'état dans un objet cmath. Cependant, cmath est un ensemble de méthodes qui sont tous liés d'une certaine façon. Dans mon exemple ci-dessus, toutes les fonctions de cmath agissent sur des nombres complexes d'une certaine manière.

-1
répondu user1928764 2018-01-08 09:14:29