Jaka jest różnica między funkcją ozdobioną @staticmethod i jeden zdobiony z @classmethod?

4131
Daryl Spitzer 26 wrzesień 2008, 01:01

20 odpowiedzi

Najlepsza odpowiedź

Może trochę przykładu kodu pomoże: Zwróć uwagę na różnicę w podpisach połączeń foo, class_foo i static_foo:

class A(object):
    def foo(self, x):
        print "executing foo(%s, %s)" % (self, x)

    @classmethod
    def class_foo(cls, x):
        print "executing class_foo(%s, %s)" % (cls, x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)" % x    

a = A()

Poniżej znajduje się zwykły sposób, w jaki instancja obiektu wywołuje metodę. Instancja obiektu, a, jest niejawnie przekazywana jako pierwszy argument.

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

z klasami , klasa instancji obiektu jest niejawnie przekazywana jako pierwszy argument zamiast self.

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

Możesz także zadzwonić class_foo za pomocą klasy. W rzeczywistości, jeśli coś zdefiniujesz Classmethod, prawdopodobnie dlatego, że zamierzasz nazwać go z klasy, a nie z instancji klasy. A.foo(1) Wyniosłby typeError, ale A.class_foo(1) działa dobrze:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

One Używaj Ludzie znaleźli dla metod klasy, jest tworzenie dziedzicznych konstruktorów alternatywnych.


z statykami , ani self (instancja obiektu), ani cls (klasa) jest niejawnie przekazywana jako pierwszy argument. Zachowują się jak zwykłe funkcje, z wyjątkiem tego, że możesz nazwać je z instancji lub klasy:

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

StaticMethods służą do grupowania funkcji, które mają pewne połączenie logiczne z klasą do klasy.


foo to tylko funkcja, ale kiedy zadzwonisz a.foo nie tylko nie otrzymasz funkcji, Otrzymasz wersję funkcji "częściowo zastosowanej" z instancją obiektu a związaną jako pierwszy argument do funkcji. foo Spodziewa się 2 argumentów, podczas gdy {x4}} oczekuje tylko 1 argumentu.

a jest związany foo. Oznacza to, że termin "związany" poniżej:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

Z a a nie jest związany z class_foo, raczej klasy A jest związany z class_foo.

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

Tutaj, z statycznymetodem, mimo że jest to metoda, a.static_foo po prostu wraca Dobra "funkcja OLE bez argumentów związanych. static_foo oczekuje 1 argumentu i a.static_foo Spodziewa się 1 argument.

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

I oczywiście to samo dzieje się, gdy zadzwonisz static_foo z klasy A.

print(A.static_foo)
# <function static_foo at 0xb7d479cc>
3322
sigjuice 1 marzec 2019, 18:34

staticmethod jest metodą, która nie zna nic o klasie lub instancji, w której została wezwana. Po prostu dostaje argumenty, które zostały przekazane, nie ukryty pierwszy argument. Zasadniczo jest bezużyteczny w Pythonie - możesz użyć funkcji modułu zamiast statycznego.

Z drugiej strony ClassMethod , jest metodą, która zostanie przyjęta klasę, którą został wezwany, lub klasę instancji, w której został wezwany, jako pierwszy argument. Jest to przydatne, gdy chcesz, aby metoda była fabryką dla klasy: Ponieważ otrzymuje faktyczną klasę, nazywano go jako pierwszym argumentem, zawsze możesz instanować odpowiednią klasę, nawet gdy podklasy są zaangażowane. Obserwuj na przykład, jak dict.fromkeys(), klasa, zwraca instancję podklasy, gdy wywołano podklasę:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 
831
Brian Burns 27 maj 2018, 13:00

Zasadniczo @classmethod jest metodą, której pierwszym argumentem jest klasa, którą nazywa się (a nie instancji klasy), @staticmethod nie ma żadnych niejawnych argumentów.

162
Tadeck 8 październik 2012, 02:07

Oficjalne Dokumenty Pythona:

@classmethod

Metoda klasy otrzymuje klasę jako ukryte pierwszy argument, podobnie jak metoda instancji otrzymuje instancję. Aby zadeklarować metodę klasy, użyj tego idiomu:

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

Formularz @classmethod jest funkcją dekorator - Zobacz opis Definicje funkcji w Funkcja Definicje Szczegółowe informacje.

Można go wywołać na klasie (np. C.f()) lub na instancji (takie jak C().f()). Instancja jest ignorowane z wyjątkiem swojej klasy. Jeśli Metoda klasy nazywana jest do uzyskania klasa, obiekt klasy pochodnej jest przekazywany jako implikowany pierwszy argument.

Metody klasy są różne niż C ++ lub statyczne metody Java. Jeśli chcesz Te, patrz {x0}} w tym Sekcja.

@staticmethod

Metoda statyczna nie otrzymuje niejawnego pierwszego argumentu. Aby zadeklarować metodę statyczną, użyj tego idiomu:

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

Formularz @staticmethod jest funkcją dekorator - Zobacz opis Definicje funkcji w Funkcja Definicje Szczegółowe informacje.

Można go wywołać na klasie (np. C.f()) lub na instancji (takie jak C().f()). Instancja jest ignorowane z wyjątkiem swojej klasy.

Metody statyczne w Pythonie są podobne do tych znalezionych w Javie lub C ++. Dla Więcej zaawansowanych koncepcji, zobacz classmethod() W tej sekcji.

110
me_and 11 grudzień 2012, 09:56

Oto jest krótkim artykułem na tym pytaniu

@staticMethod Funkcja jest niczym więcej niż funkcją zdefiniowaną wewnątrz klasy. Jest wywołany bez instancji najpierw klasy. Definicja jest niezmienna za pośrednictwem dziedziczenia.

@ClassMethod Funkcja również wywołany bez instancji klasy, ale jego definicja następuje pod uwagę klasy, a nie klasę rodzicielską, poprzez dziedziczenie. To dlatego, że pierwszy argument dla funkcji @Classmethod musi zawsze być CLS (klasa).

86
Community 20 czerwiec 2020, 09:12

Aby zdecydować, czy używać @staticMethod lub

Du D. 5 luty 2018, 14:45

Zacząłem nauczyć się języka programowania z C ++, a następnie Java, a następnie Python, więc to pytanie bardzo mnie niepokoiło, dopóki nie zrozumiałem prostego użycia każdej.

Metoda klasy: Python W przeciwieństwie do Java i C ++ nie ma przeciążenia konstruktora. I tak, aby to osiągnąć, możesz użyć classmethod. Następujący przykład to wyjaśni

Rozważmy, mamy klasę Person, która bierze dwa argumenty first_name i last_name i tworzy instancję Person.

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

Teraz, jeśli wymóg pojawia się, w którym musisz utworzyć klasę, używając tylko pojedynczej nazwy, tylko first_name, ty nie może Zrób coś w ten sposób w Pythonie.

Daje to błąd, gdy spróbujesz utworzyć obiekt (instancja).

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __init__(self, first_name):
        self.first_name = first_name

Jednak można osiągnąć to samo za pomocą @classmethod, jak wspomniano poniżej

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_person(cls, first_name):
        return cls(first_name, "")

Metoda statyczna: Jest to raczej proste, nie jest to związane z instancją lub klasą, a możesz po prostu zadzwonić do używania nazwy klasy.

Powiedzmy więc w powyższym przykładzie, potrzebujesz walidacji, że first_name nie powinien przekraczać 20 znaków, możesz po prostu to zrobić.

@staticmethod  
def validate_name(name):
    return len(name) <= 20

I możesz po prostu zadzwonić za pomocą class name

Person.validate_name("Gaurang Shah")
48
Mui Vsky 16 kwiecień 2019, 14:21

Myślę, że lepsze pytanie brzmi: "Kiedy użyłeś @Classmethod vs @staticmethod?"

@ClassMethod umożliwia łatwy dostęp do prywatnych członków, które są powiązane z definicją klasy. Jest to świetny sposób na wykonanie singletonów lub klas fabrycznych, które kontrolują liczbę instancji utworzonych obiektów istniejących.

@staticMethod zapewnia marginalną wydajność, ale jeszcze nie widziałem produktywnego stosowania metody statycznej w klasie, która nie została osiągnięta jako samodzielna funkcja poza klasą.

36
joel 13 sierpień 2020, 21:32

@Decoratorów dodano w Pythonie 2.4 Jeśli używasz Pythona <2.4, możesz użyć funkcji ClassMethod () i StaticMethod ().

Na przykład, jeśli chcesz utworzyć metodę fabryki (funkcja zwracająca instancję innej implementacji klasy w zależności od tego, jakiego argumentu) możesz zrobić coś w rodzaju:

class Cluster(object):

    def _is_cluster_for(cls, name):
        """
        see if this class is the cluster with this name
        this is a classmethod
        """ 
        return cls.__name__ == name
    _is_cluster_for = classmethod(_is_cluster_for)

    #static method
    def getCluster(name):
        """
        static factory method, should be in Cluster class
        returns a cluster object for the given name
        """
        for cls in Cluster.__subclasses__():
            if cls._is_cluster_for(name):
                return cls()
    getCluster = staticmethod(getCluster)

Należy również zauważyć, że jest to dobry przykład do korzystania z klasyfikacji i metody statycznej, metoda statyczna wyraźnie należy do klasy, ponieważ używa klastra klasy wewnętrznie. ClassMethod potrzebuje tylko informacji o klasie i żadnej instancji obiektu.

Kolejną korzyścią na temat dokonywania metody _is_cluster_for A Classmethod jest więc podklasa może zdecydować się na zmianę jego implementacji, może dlatego jest dość rodzajowy i może obsługiwać więcej niż jeden rodzaj klastra, więc po prostu sprawdzanie nazwy klasy nie byłoby być wystarczającym.

32
Jens Timmerman 20 luty 2017, 15:34

Powiem najpierw podobieństwo między metodą zdobioną @Classmethod vs @staticMethod.

Podobieństwo: Oba mogą być wywoływane na samej klasie , a nie tylko instance klasy. Tak więc oba w sensie są Metody klasy .

Różnica: Classmethod otrzyma klasę jako pierwszy argument, podczas gdy statyczny nie.

Tak więc metoda statyczna jest w pewnym sensie, nie związana z samą klasą i po prostu wisi tam tylko dlatego, że może mieć powiązaną funkcjonalność.

>>> class Klaus:
        @classmethod
        def classmthd(*args):
            return args

        @staticmethod
        def staticmthd(*args):
            return args

# 1. Call classmethod without any arg
>>> Klaus.classmthd()  
(__main__.Klaus,)  # the class gets passed as the first argument

# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')

# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()  
()

# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)
25
Pang 8 listopad 2018, 03:36

@staticmethod Wystarczy wyłączyć domyślną funkcję jako deskryptor metody. Classmethod Okłada funkcję w kontenerze Wywołany, który przekazuje odniesienie do klasy posiadania jako pierwszego argumentu:

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

W rzeczywistości classmethod ma nad głową, ale umożliwia dostęp do klasy użytkowania. Alternatywnie zalecam używanie metaklasu i umieszczenie metod klasy na temat tego metaklasu:

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>
24
Armin Ronacher 25 wrzesień 2008, 21:24

Spróbuję wyjaśnić podstawową różnicę za pomocą przykładu.

class A(object):
    x = 0

    def say_hi(self):
        pass

    @staticmethod
    def say_hi_static():
        pass

    @classmethod
    def say_hi_class(cls):
        pass

    def run_self(self):
        self.x += 1
        print self.x # outputs 1
        self.say_hi()
        self.say_hi_static()
        self.say_hi_class()

    @staticmethod
    def run_static():
        print A.x  # outputs 0
        # A.say_hi() #  wrong
        A.say_hi_static()
        A.say_hi_class()

    @classmethod
    def run_class(cls):
        print cls.x # outputs 0
        # cls.say_hi() #  wrong
        cls.say_hi_static()
        cls.say_hi_class()

1 - Możemy bezpośrednio zadzwonić do statycznych i klasyfikacji bez inicjalizacji

# A.run_self() #  wrong
A.run_static()
A.run_class()

2- Metoda statyczna nie może nazywać się własną metodą, ale może nazywać inne statyczne i klasyczne

3- Metoda statyczna należą do klasy i nie użyje obiektu w ogóle.

Metoda 4 klasy nie jest związana z obiektem, ale do klasy.

8
Rizwan Mumtaz 20 wrzesień 2016, 09:03

@Classmethod: Można użyć do stworzenia wspólnego globalnego dostępu do wszystkich instancji utworzonych z tej klasy ..... jak aktualizowanie zapisu przez wielu użytkowników ... )

Metoda @static: nie ma nic wspólnego z klasą lub instancją, która jest związana z ... ale dla czytelności może używać metody statycznej

7
vijay 20 wrzesień 2017, 17:07

Mój wkład demonstruje różnicę wśród @classmethod, @staticmethod i metodami instancji, w tym sposobu, w jaki instancja może pośrednio zadzwonić do @staticmethod. Ale zamiast pośrednio wywołując @staticmethod z instancji, dzięki czemu jest prywatny może być bardziej "Pythonic". Zdobycie czegoś z metody prywatnej nie jest tutaj wykazane, ale jest zasadniczo taką samą koncepcją.

#!python3

from os import system
system('cls')
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

class DemoClass(object):
    # instance methods need a class instance and
    # can access the instance through 'self'
    def instance_method_1(self):
        return 'called from inside the instance_method_1()'

    def instance_method_2(self):
        # an instance outside the class indirectly calls the static_method
        return self.static_method() + ' via instance_method_2()'

    # class methods don't need a class instance, they can't access the
    # instance (self) but they have access to the class itself via 'cls'
    @classmethod
    def class_method(cls):
        return 'called from inside the class_method()'

    # static methods don't have access to 'cls' or 'self', they work like
    # regular functions but belong to the class' namespace
    @staticmethod
    def static_method():
        return 'called from inside the static_method()'
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''

# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()

# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''

# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''

# call class_method()
print(democlassObj.class_method() + '\n')
'''  called from inside the class_method() '''

# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''

"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""
5
Michael Swartz 25 czerwiec 2018, 02:38

Analizuj @staticMethod dosłownie , zapewniając różne spostrzeżenia.

Normalna metoda klasy jest ukrytą metodą dynamiczną , która przyjmuje instancję jako pierwszy argument.
W przeciwieństwie do tego, StaticMethod nie bierze instancji jako pierwszego argumentu, więc nazywa się "statyczna" .

StaticMethod jest rzeczywiście tak normalna funkcja taka sama jak te poza definicją klasy.
Jest on na szczęście pogrupowany w klasę, aby stać bliżej, gdzie jest stosowany, albo możesz przewijać, aby go znaleźć.

3
Calculus 12 grudzień 2017, 11:18

Myślę, że dając czysto Python wersji staticmethod i classmethod pomogłoby zrozumieć różnicę między nimi na poziomie języka.

Oba są deskryptrowonami bez danych (łatwiej byłoby zrozumieć je, jeśli znasz Najpierw pierwszy).

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f


class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, cls=None):
        def inner(*args, **kwargs):
            if cls is None:
                cls = type(obj)
            return self.f(cls, *args, **kwargs)
        return inner
3
Jacky1205 20 listopad 2019, 09:50

Metody klasy, jak sugeruje nazwę, są używane do wprowadzania zmian w klasach, a nie obiekty. Aby wprowadzić zmiany w klasach, zmieniają atrybuty klasy (atrybuty nie obiektów), ponieważ właśnie aktualizujesz zajęcia. Z tego powodu metody klasy biorą klasę (konwencjonalnie oznaczane przez "CLS") jako pierwszy argument.

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

Z drugiej strony stosowane są metody statyczne, służą do wykonywania funkcjonalności, które nie są związane z klasą I.e nie będą one odczytywane ani nie zapisują zmiennych klasy. Stąd metody statyczne nie biorą zajęć jako argumentów. Są one używane tak, że klasy mogą wykonywać funkcjonalności, które nie są bezpośrednio związane z celami klasy.

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."
2
Tushar Vazirani 1 grudzień 2017, 10:38

Szybki hack-up Identyczne metody w Ipython ujawnia, że @staticmethod daje marginalną wydajność (w nanosekundach), ale w przeciwnym razie wydaje się, że nie ma funkcji. Ponadto wszelkie zyski wydajności prawdopodobnie zostaną wymazane przez dodatkowe prace przetwarzania metody za pomocą staticmethod() podczas kompilacji (co dzieje się przed wykonaniem kodu podczas uruchamiania skryptu).

Ze względu na czytelność kodu uniknąłbym @staticmethod, chyba że metoda będzie używana do ładunków pracy, gdzie liczba nanosekundów.

-4
Keith Pinson 17 grudzień 2012, 19:10

Metoda klasy otrzymuje klasę jako ukryte pierwszy argument, podobnie jak metoda instancji otrzymuje instancję. Jest to metoda, która jest związana z klasą, a nie przedmiotem klasy Może modyfikować stan klasy, który zastosowałby wszystkie instancje klasy. Na przykład może modyfikować zmienną klasową, która będzie miała zastosowanie do wszystkich instancji.

Z drugiej strony, metoda statyczna nie otrzymuje niejawnego pierwszego argumentu, w porównaniu z metodami klasy lub metodami instancji. I nie można uzyskać dostępu ani modyfikowania stanu klasy. Należy tylko do klasy, ponieważ od punktu widzenia projektu, który jest właściwy sposób. Ale pod względem funkcjonalności nie jest związany, w czasie wykonywania, do klasy.

Jako wytyczne stosować metody statyczne jako narzędzia, stosować metody klasy na przykład jako fabrycznie. A może zdefiniować singleton. I użyj metod instancji, aby modelować stan i zachowanie instancji.

Mam nadzieję, że byłem jasny!

6
Nicolae Petridean 20 listopad 2019, 11:48