Statyczne metody w Pythonie?

Czy możliwe jest posiadanie statycznych metod w Pythonie, więc mogę je wywoływać bez inicjalizacji klasy, jak:

ClassName.StaticMethod ( )
Author: BartoszKP, 2009-04-10

9 answers

Tak, za pomocą staticmethod dekorator

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

MyClass.the_static_method(2) # outputs 2

Zauważ, że niektóre kody mogą używać starej metody definiowania statycznej metody, używając staticmethod jako funkcji, a nie dekoratora. To powinno być używane tylko wtedy, gdy musisz obsługiwać starożytne wersje Pythona (2.2 i 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

Jest to całkowicie identyczne z pierwszym przykładem (używając @staticmethod), tylko nie używając ładnej składni dekoratora

Na koniec użyj staticmethod() oszczędnie! Jest bardzo niewiele sytuacji tam, gdzie metody statyczne są niezbędne w Pythonie, a widziałem je wiele razy, gdzie oddzielna funkcja "najwyższego poziomu" byłaby bardziej przejrzysta.


Poniżej znajduje się fragment dokumentacji::

Statyczna metoda nie otrzymuje pierwszego argumentu. Aby zadeklarować metodę statyczną, użyj tego idiomu:

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

Postać @staticmethod jest funkcją dekorator – zobacz opis definicji funkcji w definicje funkcji po szczegóły.

Może być wywołana albo na klasie (np. C.f()) albo na instancji(np. C().f()). Instancja jest ignorowana z wyjątkiem jej klasy.

Statyczne metody w Pythonie są podobne do tych, które można znaleźć w Javie lub C++. Aby uzyskać bardziej zaawansowaną koncepcję, zobacz classmethod().

Aby uzyskać więcej informacji na temat metod statycznych, zapoznaj się z dokumentacją standardowej hierarchii typów w typ standardowy hierarchia.

Nowość w wersji 2.2.

Zmieniono w wersji 2.4: dodano składnię dekoratora funkcji.

 1725
Author: dbr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-15 17:10:50

Myślę, że Steven ma rację. Aby odpowiedzieć na pierwotne pytanie, w celu skonfigurowania metody klasowej, po prostu Załóżmy, że pierwszy argument nie będzie instancją wywołującą, a następnie upewnij się, że wywołujesz metodę tylko z klasy.

(zauważ, że ta odpowiedź odnosi się do Pythona 3.x. w Pythonie 2.x otrzymasz TypeError za wywołanie metody na samej klasie.)

Na przykład:

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)

W tym kodzie metoda "rollCall" zakłada, że pierwszy argument nie jest instancją (tak by było, gdyby została wywołana przez instancję zamiast klasy). Tak długo, jak "rollCall" jest wywoływany z klasy, a nie instancji, kod będzie działał dobrze. Jeśli spróbujemy wywołać "rollCall" z instancji, np.:

rex.rollCall(-1)

Spowodowałoby to jednak powstanie wyjątku, ponieważ wysyłałoby dwa argumenty: sam i -1, a "rollCall" jest zdefiniowany tylko w celu zaakceptowania jednego argumentu.

Nawiasem mówiąc, rex.rollCall () wyśle poprawne liczba argumentów, ale spowodowałaby również powstanie wyjątku, ponieważ teraz n reprezentowałoby instancję psa (np. rex), gdy funkcja oczekuje, że n będzie numeryczna.

Tutaj pojawia się Dekoracja: Jeśli poprzedzimy metodę "rollCall" za pomocą

@staticmethod

Następnie, poprzez wyraźne stwierdzenie, że metoda jest statyczna, możemy nawet wywołać ją z instancji. Teraz,

rex.rollCall(-1)
Zadziałałoby. Wstawianie @staticmethod przed definicją metody zatrzymuje wystąpienie od wysłania samego siebie jako argumentu.

Możesz to zweryfikować, próbując poniższego kodu z komentowaną linią @staticmethod i bez niej.

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
Author: Richard Ambler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-10 06:20:51

Tak, sprawdź staticmethod dekorator:

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World
 74
Author: Paolo Bergantino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-09 21:24:15

Nie musisz używać dekoratora. Wystarczy zadeklarować metodę (która nie oczekuje parametru self) i wywołać ją z klasy. Dekorator jest tam tylko w przypadku, gdy chcesz być w stanie wywołać go z instancji, jak również (co nie było to, co chciałeś zrobić)

Głównie jednak używasz tylko funkcji...

 43
Author: hichris123,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-14 00:29:47

Statyczne metody w Pythonie?

Czy jest możliwe posiadanie statycznych metod w Pythonie, żebym mógł je wywoływać bez inicjalizacji klasy, jak:

ClassName.StaticMethod()

Tak, statyczne metody mogą być tworzone w ten sposób (chociaż jest trochę bardziej Pythonic aby używać podkreślników zamiast CamelCase dla metod):

class ClassName(object):

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

Powyższe używa składni dekoratora. Składnia ta jest równoważna

class ClassName(object):

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

    static_method = staticmethod(static_method)

To może być używane tak jak ty opisany:

ClassName.static_method()

Wbudowanym przykładem statycznej metody jest str.maketrans() w Pythonie 3, która była funkcją w module string w Pythonie 2.


Inną opcją, która może być użyta tak jak opisujesz, jest classmethod, różnica polega na tym, że classmethod otrzymuje klasę jako domyślny pierwszy argument, a jeśli jest podklasowana, to otrzymuje podklasę jako domyślny pierwszy argument.

class ClassName(object):

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

Zauważ, że cls nie jest nazwą wymaganą dla pierwszego argumentu, ale najbardziej doświadczeni Programiści Pythona uznają to za źle zrobione, jeśli użyjesz czegokolwiek innego.

Są one zwykle używane jako alternatywne konstruktory.

new_instance = ClassName.class_method()

Przykładem jest dict.fromkeys():

new_dict = dict.fromkeys(['key1', 'key2'])
 29
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-26 05:30:07

Pomijając specyfikę zachowania się obiektów metody statycznej, istnieje pewien rodzaj piękna, który możesz z nich wydobyć, jeśli chodzi o organizowanie kodu na poziomie modułów.

# 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

Staje się teraz nieco bardziej intuicyjny i samodokumentujący, w jakim kontekście mają być używane określone komponenty i idealnie nadaje się do nazywania odrębnych przypadków testowych, a także do prostego podejścia do jak moduły testowe mapują do rzeczywistych modułów w ramach testów dla purystów.

Często uważam, że warto zastosować to podejście do organizowania kodu użytkowego projektu. Dość często ludzie natychmiast pobiegają i tworzą pakiet utils i kończą z 9 modułami, z których jeden ma 120 LOC, a reszta to najwyżej dwa tuziny LOC. Wolę zacząć od tego i przekonwertować go na pakiet i tworzyć moduły tylko dla bestii, które naprawdę na nie zasługują: {]}

# 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
Author: Filip Dupanović,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-23 14:42:54

Być może najprostszą opcją jest po prostu umieszczenie tych funkcji poza klasą:

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"

Za pomocą tej metody, funkcje, które modyfikują lub używają wewnętrznego stanu obiektu (mają skutki uboczne) mogą być przechowywane w klasie, A funkcje wielokrotnego użytku mogą być przeniesione na zewnątrz.

Załóżmy, że ten plik nazywa się dogs.py. Aby ich użyć, należy zadzwonić dogs.barking_sound() zamiast dogs.Dog.barking_sound.

Jeśli naprawdę potrzebujesz statycznej metody, aby być częścią klasy, możesz użyć staticmethod dekorator.

 9
Author: Matt Woelk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-11 15:31:57

W Pythonie 3:

Tutaj jest jeszcze jeden dobry używać niestatycznych metod, jak były metody statyczne.

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)

Wywołaj metodę niestatyczną jako statyczną

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

:$ https://example.com/login [email protected] password_example
 0
Author: Erisan Olasheni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-16 15:32:27

Od czasu do czasu spotykam się z tym pytaniem. Przykład użycia i przykład, który lubię to:

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

Tworzenie obiektu klasy cmath nie ma sensu, ponieważ w obiekcie cmath nie ma stanu. Jednak cmath jest zbiorem metod, które są ze sobą w jakiś sposób powiązane. W moim przykładzie powyżej, wszystkie funkcje w cmath działają w jakiś sposób na liczby złożone.

 -1
Author: user1928764,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-08 09:14:29