Koja je razlika između @staticmethod i @classmethod?

Koja je razlika između funkcije ukrašene @staticmethod i druge @classmethod ?

2924
26 сент. postavio Daryl Spitzer 26 ruj. 2008-09-26 00:01 '08 u 0:01 2008-09-26 00:01
@ 26 odgovora

Možda će vam pomoći mali uzorci koda: zabilježite razliku u pozivima 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)"%xa=A() 

Ispod je uobičajen način na koji objektna instanca poziva metodu. Primjer objekta a implicitno je proslijeđen kao prvi argument.

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

Korištenjem metoda klasa, klasa instance objekta implicitno se prenosi kao prvi argument umjesto u self .

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

Također možete pozvati class_foo pomoću klase. Zapravo, ako definirate nešto što klasna metoda treba, to je vjerojatno zato što je namjeravate nazvati iz klase, a ne iz instance klase. A.foo(1) može nazvati TypeError, ali A.class_foo(1) funkcionira:

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

Jedna od klasnih metoda koje ljudi koriste je stvaranje naslijeđenih alternativnih konstruktora .


Kod staticmethods, ni self (objekt instance) ni cls (class) nije implicitno proslijeđen kao prvi argument. Ponašaju se kao jednostavne funkcije, osim što ih možete pozvati iz instance ili klase:

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

Statične metode se koriste za grupiranje funkcija koje imaju neku logičku vezu s klasom klase.


foo je samo funkcija, ali kada nazovete a.foo , ne dobivate samo funkciju, dobivate "djelomično primijenjenu" verziju funkcije s instancom objekta a , vezanom kao prvi argument funkcije. foo očekuje 2 argumenta, a a.foo očekuje samo jedan argument.

a vezan za foo . To je ono što izraz "povezan" znači ispod:

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

S a.class_foo , a nije vezan za class_foo , a klasa a vezana za class_foo .

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

Ovdje, koristeći staticmethod, iako je to metoda, a.static_foo jednostavno vraća dobru funkciju ole bez obvezujućih argumenata. static_foo očekuje 1 argument i a.static_foo također očekuje 1 argument.

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

I, naravno, ista stvar se događa kada pozivate static_foo s klasom a .

 print(a.static_foo) # <function static_foo at 0xb7d479cc> 
2560
03 нояб. odgovor je dat unutbu 03 Nov. 2009-11-03 22:13 '09 u 22:13 2009-11-03 22:13

Statička metoda je metoda koja ne zna ništa o klasi ili instanci na koju je pozvana. Ona jednostavno dobiva argumente koji su doneseni, ne podrazumijeva prvi argument. Ovo je beskorisno u Pythonu - jednostavno možete koristiti funkciju modula umjesto statičke metode.

S druge strane, classmethod je metoda koja prima proslijeđenu klasu na koju je pozvana, ili klasu instance kojoj je pozvana, kao prvi argument. Ovo je korisno ako želite da ova metoda bude tvornica za klasu: budući da dobiva stvarnu klasu koju je nazvala kao prvi argument, uvijek možete stvoriti instancu prave klase, čak i ako su uključeni podrazredi. Primijetite, na primjer, kako dict.fromkeys() , classmethod, vraća instancu podklase kada je pozvana u potklasu:

border=0
 >>> class DictSubclass(dict): ... def __repr__(self): ... return "DictSubclass" ... >>> dict.fromkeys("abc") {'a': None, 'c': None, 'b': None} >>> DictSubclass.fromkeys("abc") DictSubclass >>> 
708
26 сент. Odgovor dao Thomas Wouters 26. rujna 2008-09-26 00:05 '08 u 0:05 2008-09-26 00:05

U osnovi, @classmethod stvara metodu čiji je prvi argument klasa iz koje je pozvan (a ne instanca klase) @staticmethod nema implicitnih argumenata.

122
26 сент. odgovor dao Terence Simpson 26 ruj. 2008-09-26 00:07 '08 u 0:07 2008-09-26 00:07

Službeni Python dokumenti:

@classmethod

Metoda klase prima klasu kao implicitni prvi argument, kao što instanca metode prima instancu. Za deklariranje metode klase upotrijebite ovaj idiom:

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

Oblik @classmethod je funkcija dekoratera - vidi opis definicije funkcije u Definition Function .

Može se pozvati u klasi (na primjer, Cf() ) ili na instanci (na primjer, C().f() ). Primjer se zanemaruje, osim za klasu. Ako je metoda klase pozvana za izvedenu klasu, objekt izvedene klase je namijenjen prvi argument.

Metode klasa se razlikuju od C ++ ili Java statičkih metoda. Ako ih želite, pogledajte staticmethod() u ovom odjeljku.

@staticmethod

Statička metoda ne dobiva implicitni prvi argument. Da biste deklarirali statičku metodu, upotrijebite taj idiom:

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

Oblik @staticmethod je funkcija dekoratera - vidi opis definicije funkcije u Definition Function .

Može se pozvati u klasi (na primjer, Cf() ) ili na instanci (na primjer, C().f() ). Primjer se zanemaruje, osim za klasu.

Statičke metode u Pythonu slične su onima u Java ili C ++. Za napredniji koncept pogledajte classmethod() u ovom odjeljku.

82
03 нояб. Odgovor Chris B. Nov. 03. 2009-11-03 22:23 '09 u 10:23 AM 2009-11-03 22:23

Evo kratkog članka o ovoj temi.

@Staticmethod funkcija nije ništa više nego funkcija definirana unutar klase. Može se pozvati bez stvaranja instance klase. Njegova je definicija nepromjenjiva kroz nasljeđivanje.

Funkcija @classmethod može se pozvati i bez stvaranja instance klase, ali njezina definicija slijedi kroz Sub klasu, a ne u roditeljsku klasu, preko nasljeđivanja. To je zato što bi prvi argument za funkciju @classmethod uvijek trebao biti cls (class).

62
03 нояб. Odgovor je dao Tom Neyland 03 Nov. 2009-11-03 22:02 '09 u 10:02 AM 2009-11-03 22:02

Da biste odlučili želite li koristiti @staticmethod ili @classmethod, morate pogledati unutar svoje metode. Ako vaša metoda pristupa drugim varijablama / metodama u vašem razredu, koristite @classmethod . S druge strane, ako se vaša metoda ne odnosi na druge dijelove klase, koristite @staticmethod.

 class Apple: _counter = 0 @staticmethod def about_apple(): print('Apple is good for you.') # note you can still access other member of the class # but you have to use the class instance # which is not very nice, because you have repeat yourself # # For example: # @staticmethod # print('Number of apples have been juiced: %s' % Apple._counter) # # @classmethod # print('Number of apples have been juiced: %s' % cls._counter) # # @classmethod is especially useful when you move your function to other class, # you don't have to rename the class reference @classmethod def make_apple_juice(cls, number_of_apples): print('Make juice:') for i in range(number_of_apples): cls._juice_this(i) @classmethod def _juice_this(cls, apple): print('Juicing %d...' % apple) cls._counter += 1 
52
22 апр. odgovor daje Du D. 2016-04-22 18:40 '16 u 18:40 2016-04-22 18:40

Koja je razlika između @staticmethod i @classmethod u Pythonu?

Možda ste vidjeli Python kod, kao što je ovaj pseudokod, koji demonstrira potpise različitih vrsta metoda i pruža alat za objašnjenje svakog od njih:

 class Foo(object): def a_normal_instance_method(self, arg_1, kwarg_2=None): ''' Return a value that is a function of the instance with its attributes, and other arguments such as arg_1 and kwarg2 ''' @staticmethod def a_static_method(arg_0): ''' Return a value that is a function of arg_0. It does not know the instance or class it is called from. ''' @classmethod def a_class_method(cls, arg1): ''' Return a value that is a function of the class and other arguments. respects subclassing, it is called with the class it is called from. ''' 

Normalna metoda

Prvo ću objasniti a_normal_instance_method . To se upravo naziva metoda instance . Kada se koristi metoda instance, ona se koristi kao djelomična funkcija (za razliku od opće funkcije definirane za sve vrijednosti kada se gleda u izvornom kodu), koja se, kada se koristi, prvi od argumenata unaprijed definira kao objekt instance sa svim njegovim atributima. Ima instancu objekta povezanog s njom i mora biti pozvana iz instance objekta. U pravilu će se odnositi na različite atribute instance.

Na primjer, ovo je instanca niza:

 ', ' 

ako koristimo metodu instance koja se join ovoj liniji da bismo se pridružili drugom iterabilnom, ovo je očito funkcija instance, osim funkcije ponavljanja popisa, ['a', 'b', 'c'] :

 >>> ', '.join(['a', 'b', 'c']) 'a, b, c' 

Srodne metode

Metode instance se mogu povezati pomoću točkastog pretraživanja za kasnije korištenje.

Na primjer, veže metodu str.join na str.join ':' :

 >>> join_with_colons = ':'.join 

A kasnije to možemo koristiti kao funkciju koja već ima prvi argument povezan s njim. Dakle, djeluje kao djelomična funkcija instance:

 >>> join_with_colons('abcde') 'a:b:c:d:e' >>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF']) 'FF:FF:FF:FF:FF:FF' 

Statička metoda

Statička metoda ne prihvaća instancu kao argument.

Vrlo je sličan funkciji razine modula.

Međutim, funkcija na razini modula mora živjeti u modulu i biti posebno uvezena na druga mjesta gdje se koristi.

Ako je priključen na objekt, također će biti prikladno za kretanje kroz objekt kroz uvoz i nasljeđivanje.

Primjer statičke metode je str.maketrans , premještena iz string modula u Python 3. To čini tablicu prijevoda prikladnom za str.translate potrošnju. To se čini prilično glupim kada se koristi iz niza, kao što je prikazano u nastavku, ali uvoz funkcije iz string modula je prilično neugodan, i lijepo je biti u mogućnosti nazvati ga iz klase, kao u str.maketrans

 # demonstrate same function whether called from instance or not: >>> ', '.maketrans('ABC', 'abc') {65: 97, 66: 98, 67: 99} >>> str.maketrans('ABC', 'abc') {65: 97, 66: 98, 67: 99} 

U pythonu 2 morate uvesti ovu funkciju iz sve manje korisnog niza modula:

 >>> import string >>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc')) 'abcDEFG' 

Metoda klase

Metoda klase je slična metodi instance, budući da prihvaća implicitni prvi argument, ali umjesto prihvaćanja instance, prihvaća klasu. Često se koriste kao alternativni konstruktori za bolju semantičku upotrebu i podržat će nasljedstvo.

dict.fromkeys primjer ugrađene klase je dict.fromkeys . Koristi se kao alternativni dict konstruktor (prikladan za kada znate što imate i želite zadani za njih.)

 >>> dict.fromkeys(['a', 'b', 'c']) {'c': None, 'b': None, 'a': None} 

Kada podredimo dict, možemo koristiti isti konstruktor koji stvara instancu podklase.

 >>> class MyDict(dict): 'A dict subclass, use to demo classmethods' >>> md = MyDict.fromkeys(['a', 'b', 'c']) >>> md {'a': None, 'c': None, 'b': None} >>> type(md) <class '__main__.MyDict'> 

Pogledajte izvorni kod pandas za druge slične primjere alternativnih konstruktora, kao i službenu Python dokumentaciju o classmethod i staticmethod .

40
23 янв. Odgovor je dao Aaron Hall 23. siječnja. 2015-01-23 23:01 '15 u 23:01 2015-01-23 23:01

@decorators su dodani u python 2.4 Ako koristite python <2.4, možete koristiti funkcije classmethod () i staticmethod ().

Na primjer, ako želite stvoriti tvorničku metodu (funkcija koja vraća instancu druge izvedbe klase ovisno o tome koji je argument potreban), možete učiniti nešto poput:

 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) 

Također imajte na umu da je ovo dobar primjer korištenja metode klase i statičke metode.Statička metoda eksplicitno pripada klasi, jer koristi klasa klasa unutra. Klasi su potrebne samo informacije o klasi, a ne objektna instanca.

Još jedna prednost stvaranja metode _is_cluster_for classmethod je ta da podklasa može odlučiti promijeniti svoju implementaciju, možda zato što je vrlo uobičajena i može obraditi nekoliko tipova klastera, tako da samo provjera naziva klase neće biti dovoljna.

28
24 февр. Odgovor koji je dao Jens Timmerman 24. veljače. 2012-02-24 12:32 '12 u 12:32 2012-02-24 12:32

Mislim da je najbolje pitanje: "Kada ćete koristiti @classmethod vs @staticmethod?"

@classmethod omogućuje vam jednostavan pristup privatnim članovima koji su povezani s definicijom klase. Ovo je sjajan način izrade pojedinačnih ili tvorničkih klasa koje kontroliraju broj instanci stvorenih objekata.

@staticmethod osigurava marginalne poboljšanja performansi, ali još uvijek moram vidjeti produktivnu uporabu statičke metode unutar klase koja se ne može izvesti kao autonomna funkcija izvan klase.

27
19 мая '15 в 18:27 2015-05-19 18:27 Odgovor daje Nathan Tregillus 19. svibnja '15. U 18:27 2015-05-19 18:27

Statičke metode:

  • Jednostavne funkcije bez argumenata.
  • Rad na atributima klase; ne atributi instance.
  • Možete nazvati kroz klasu i instancu.
  • Za njihovu izradu koristi se ugrađena funkcija staticmethod ().

Prednosti statičkih metoda:

  • On lokalizira naziv funkcije za klasu.
  • Pomiče kod funkcije bliže mjestu uporabe.
  • Praktičnije je uvesti funkcije na razini modula, jer svaka metoda ne mora biti posebno uvezena

     @staticmethod def some_static_method(*args, **kwds): pass 

Klasne metode:

  • Funkcije koje imaju prvi argument kao ime klase.
  • Možete nazvati kroz klasu i instancu.
  • Stvorene su s ugrađenom funkcijom klase.

      @classmethod def some_class_method(cls, *args, **kwds): pass 
26
03 окт. Odgovori Laxmi Oct 03. 2016-10-03 13:41 '16 u 13:41 2016-10-03 13:41

@staticmethod jednostavno onemogućuje zadanu funkciju kao metodu. Klasni metod obavija vašu funkciju u kontejneru koji se zove referenca na vlastitu klasu kao prvi argument:

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

Zapravo, classmethod ima servisne podatke u vrijeme izvođenja, ali dopušta pristup vlasničkoj klasi. Alternativno, preporučujem korištenje metaklasa i stavljanja klasnih metoda na ovaj metaklas:

 >>> class CMeta(type): ... def foo(cls): ... print cls ... >>> class C(object): ... __metaclass__ = CMeta ... >>> C.foo() <class '__main__.C'> 
21
26 сент. odgovor daje Armin Ronacher 26 sep . 2008-09-26 00:24 '08 u 0:24 2008-09-26 00:24

Konačni vodič za korištenje statičkih, hladnih ili apstraktnih metoda u Pythonu je jedan od dobrih linkova za ovu temu i reducira ih na sljedeće.

@staticmethod funkcija nije ništa više nego funkcija definirana unutar klase. Može se pozvati bez stvaranja instance klase. Njegova je definicija nepromjenjiva kroz nasljeđivanje.

  • Python ne bi trebao instancirati vezanu metodu za objekt.
  • To čini kod lakšim za čitanje i ne ovisi o stanju samog objekta;

Funkcija @classmethod biti i @classmethod bez instanciranja klase, ali njegova definicija slijedi sub potklasu, a ne može se redefinirati podklasa roditeljska klasa, putem nasljeđivanja. To je zato što bi prvi argument za funkciju @classmethod uvijek @classmethod biti cls (class).

  • Tvorničke metode koje se koriste za stvaranje instance za klasu koja koristi, primjerice, neku predobradu.
  • Statičke metode koje pozivaju statičke metode: ako razbijete statičke metode s nekoliko statičkih metoda, ne biste trebali tvrdo kodirati ime klase, ali koristite metode razreda
18
16 нояб. Odgovor je dan zangw 16 Nov. 2015-11-16 05:00 '15 u 5:00 sati 2015-11-16 05:00

Počeo sam učiti programski jezik s C ++-om, a zatim s Java-om, a zatim s Python-om, pa me je to pitanje također uznemirilo dok nisam shvatio jednostavnu uporabu svakog od njih.

Metoda klase: Python, za razliku od Java i C ++, nema preopterećenje konstruktora. Stoga, da bi se to postiglo, možete koristiti classmethod . Sljedeći primjer će objasniti ovo.

Razmotrimo da imamo klasu Person koja uzima dva argumenta, first_name i last_name i kreira instancu Person.

 class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name 

Sada, ako se pojavi zahtjev gdje trebate stvoriti klasu koja koristi samo jedno ime, samo first_name , ne možete učiniti nešto poput ovoga u pythonu.

To će vam dati pogrešku kada pokušate stvoriti objekt (primjer).

 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 

Međutim, isto možete postići pomoću @classmethod kako slijedi.

 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, "") 

Statička metoda :: Prilično je jednostavna, nije vezana za instancu ili klasu, a jednostavno je možete nazvati pomoću naziva klase.

Tako, na primjer, u gornjem primjeru, morate provjeriti da first_name ne smije prelaziti 20 znakova, možete to učiniti.

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

i možete nazvati samo pomoću naziva klase

 Person.validate_name("Gaurang Shah") 
17
10 окт. Odgovoriti Gaurang Shah listopad 10 2017-10-10 13:10 '17 u 13:10 2017-10-10 13:10

@classmethod znači : kada pozivate ovu metodu, proslijedimo klasu kao prvi argument umjesto instance te klase (kao što to obično činimo s metodama). To znači da možete koristiti klasu i njezina svojstva unutar ove metode, a ne određenu instancu.

@staticmethod znači: kada se ova metoda nazove, ne dajemo joj instancu klase (kao što je obično slučaj s metodama). To znači da možete staviti funkciju unutar klase, ali ne možete pristupiti instanci ove klase (to je korisno kada metoda ne koristi instancu).

16
13 дек. Odgovor je dao Tushar.PUCSD 13. prosinca. 2015-12-13 22:37 '15 u 22:37 sati 2015-12-13 22:37

Još jedno razmatranje u vezi s metodom statičke metode u odnosu na klasnu metodu odnosi se na nasljeđivanje. Recimo da imate sljedeću klasu:

 class Foo(object): @staticmethod def bar(): return "In Foo" 

A onda želite nadjačati bar() u podređenoj klasi:

 class Foo2(Foo): @staticmethod def bar(): return "In Foo2" 

Ovo radi, ali imajte na umu da sada implementacija bar() u podređenoj klasi ( Foo2 ) više ne može koristiti ništa specifično za ovu klasu. Na primjer, recimo da je Foo2 imao magic() metodu koju želite koristiti u implementaciji bar() Foo2 bar() :

 class Foo2(Foo): @staticmethod def bar(): return "In Foo2" @staticmethod def magic(): return "Something useful you'd like to use in bar, but now can't" 

Foo2.magic() rješenje ovdje bi bilo nazvati Foo2.magic() u bar() , ali onda ponovite (ako se promijeni ime Foo2 , morat ćete zapamtiti ovu bar() metode bar() ).

Za mene, ovo je mala povreda načela otvoreno / zatvoreno , jer odluka donesena u Foo utječe na sposobnost zajedničkog koda refaktora u izvedenoj klasi (tj. Manje je otvorena za ekspanziju). Ako je bar() classmethod , bilo bi dobro:

 class Foo(object): @classmethod def bar(cls): return "In Foo" class Foo2(Foo): @classmethod def bar(cls): return "In Foo2 " + cls.magic() @classmethod def magic(cls): return "MAGIC" print Foo2().bar() 

Daje: In Foo2 MAGIC

10
29 сент. Odgovor daje Adam Parkin 29. rujna. 2016-09-29 20:02 '16 u 20:02 2016-09-29 20:02

Dopustite mi da prvo govorim o sličnosti metode, ukrašene @classmethod vs @staticmethod.

Sličnost: obje se mogu pozvati na samu klasu, a ne samo na instancu klase. Dakle, oboje su, u određenom smislu, klasne metode.

Razlika: metoda klase primit će samu klasu kao prvi argument, ali statička metoda neće.

Dakle, statička metoda, u određenom smislu, nije povezana sa samom klasom i samo visi tamo samo zato što može imati povezanu funkcionalnost.

 >>> 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',) 
10
14 янв. Odgovor je dao Selva 14. siječnja. 2018-01-14 17:07 '18 u 17:07 2018-01-14 17:07

Pokušat ću objasniti glavnu razliku s primjerom.

 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 Ax # 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()