Jesu li varijable statičkog razreda moguće?

Je li moguće imati statičke varijable klase ili metode u pythonu? Koja sintaksa je potrebna za to?

1598
16 сент. postavio Andrew Walker 16 ruj. 2008-09-16 04:46 '08 u 4:46 am 2008-09-16 04:46
@ 17 odgovora

Varijable deklarirane unutar definicije klase, ali ne unutar metode, su klasa ili statične varijable:

 >>> class MyClass: ... i = 3 ... >>> MyClass.i 3 

Kao što ističe @ millerdev , to stvara varijablu klase i na razini razreda, ali se razlikuje od bilo koje varijable i na razini instance, tako da možda imate

 >>> m = MyClass() >>> mi = 4 >>> MyClass.i, mi >>> (3, 4) 

To se razlikuje od C ++ i Java, ali nije toliko različito od C #, gdje nije moguće pristupiti statičnom članu pomoću reference instance.

Pogledajte što bi Python tutorial trebao reći na temu klasa i objekata klase .

@ Steve Johnson je već odgovorio na statičke metode , također opisane u "Ugrađenim funkcijama" u referenci Python knjižnice .

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

@beidy preporučuje classmethod pomoću staticmethod, jer metoda tada dobiva tip klase kao prvi argument, ali ja sam još uvijek pomalo nejasan o prednostima ovog pristupa u odnosu na staticmethod. Ako ste i vi, onda to vjerojatno nije važno.

1575
16 сент. Odgovor dao Blair Conrad 16. rujna. 2008-09-16 04:51 '08 u 4:51 am 2008-09-16 04:51

@Blair Konrad je rekao da su statičke varijable deklarirane unutar definicije klase, ali ne unutar metode, klasa ili "statične" varijable:

 >>> class Test(object): ... i = 3 ... >>> Test.i 3 

Ovdje postoji nekoliko opcija. Izvedite gornji primjer:

 >>> t = Test() >>> ti # static variable accessed via instance 3 >>> ti = 5 # but if we assign to the instance ... >>> Test.i # we have not changed the static variable 3 >>> ti # we have overwritten Test.i on t by creating a new attribute ti 5 >>> Test.i = 6 # to change the static variable we do it by assigning to the class >>> ti 5 >>> Test.i 6 >>> u = Test() >>> ui 6 # changes to t do not affect new instances of Test # Namespaces are one honking great idea -- let do more of those! >>> Test.__dict__ {'i': 6, ...} >>> t.__dict__ {'i': 5} >>> u.__dict__ {} 

Primijetite da se varijabla instance ti nije sinkronizirala s "statičnom" varijablom klase kada je atribut i postavljen izravno na t . To je zbog činjenice da i bio ponovno vezan u prostoru imena, koji se razlikuje od prostora za imena Test . Ako želite promijeniti vrijednost "statične" varijable, morate je promijeniti unutar opsega (ili objekta) gdje je izvorno definiran. Stavio sam "static" u navodnike, jer Python doista nema statičke varijable u smislu da C ++ i Java rade.

Iako ne govori ništa konkretno o statičkim varijablama ili metodama, Pythonov vodič sadrži neke relevantne informacije o klasama i objektima klase .

border=0

@ Steve Johnson je također odgovorio statičkim metodama, također opisanim u "Inline Functions" odjeljku Python Library Reference.

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

@beid također spominje metodu klasa, koja je slična statičkom metodi. Prvi argument klase metoda je objekt klase. primjer:

 class Test(object): i = 3 # class (or static) variable @classmethod def g(cls, arg): # here we can use 'cls' instead of the class name (Test) if arg > cls.i: cls.i = arg # would the the same as Test.i = arg1 

2019

16 сент. Odgovor daje milerdev na 16 sep . 2008-09-16 06:04 '08 u 6:04 2008-09-16 06:04

Statičke i klasne metode

Kao što je navedeno u drugim odgovorima, statičke i cool metode lako se izvode pomoću ugrađenih dekoratora:

 class Test(object): # regular instance method: def MyMethod(self): pass # class method: @classmethod def MyClassMethod(klass): pass # static method: @staticmethod def MyStaticMethod(): pass 

Kao i obično, prvi argument za MyMethod() vezan je za objekt instance klase. Nasuprot tome, prvi argument za MyClassMethod() vezan je za sam predmet klase (na primjer, u ovom slučaju, Test ). Za MyStaticMethod() nijedan argument nije vezan, a argumenti su općenito neobavezni.

"Statičke varijable"

Međutim, implementacija "statičkih varijabli" (dobro, promjenjive statičke varijable, u svakom slučaju, ako to nije proturječje u smislu ...) nije tako jednostavna. Kao što je Millerdev zabilježio u svom odgovoru , problem je u tome što atributi klase Python zapravo nisu "statičke varijable". uzeti u obzir:

 class Test(object): i = 3 # This is a class attribute x = Test() xi = 12 # Attempt to change the value of the class attribute using x instance assert xi == Test.i # ERROR assert Test.i == 3 # Test.i was not affected assert xi == 12 # xi is a different object than Test.i 

To je zbog činjenice da je linija xi = 12 dodala novi atribut instance iz i u x umjesto da mijenja vrijednost atributa Test class i .

Djelomično očekivano ponašanje statičke varijable, tj. Sinkronizacija atributa između više instanci (ali ne s samom klasom, vidi "Gotcha" u nastavku) može se postići pretvaranjem atributa klase u svojstvo:

 class Test(object): _i = 3 @property def i(self): return type(self)._i @i.setter def i(self,val): type(self)._i = val ## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ## ## (except with separate methods for getting and setting i) ## class Test(object): _i = 3 def get_i(self): return type(self)._i def set_i(self,val): type(self)._i = val i = property(get_i, set_i) 

Sada možete učiniti:

 x1 = Test() x2 = Test() x1.i = 50 assert x2.i == x1.i # no error assert x2.i == 50 # the property is synced 

Statička varijabla sada će se sinkronizirati između svih instanci klase.

(NAPOMENA. To jest, ako instanca klase ne odluči definirati vlastitu verziju _i ! Ali ako se netko odluči na to, oni zaslužuju ono što dobiju, zar ne?)

Imajte na umu da tehnički gledano, i još uvijek nije "statička varijabla"; ovo property je posebna vrsta deskriptora. Međutim, ponašanje property je sada ekvivalentno (promjenjivoj) statičkoj varijabli sinkroniziranoj u svim instancama klase.

Nepromjenjive "statičke varijable"

Da bi se statička varijabla ponašala jednostavno ispustite postavljač property :

 class Test(object): _i = 3 @property def i(self): return type(self)._i ## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ## ## (except with separate methods for getting i) ## class Test(object): _i = 3 def get_i(self): return type(self)._i i = property(get_i) 

Sada će pokušaj postavljanja atributa instance i i vratiti AttributeError :

 x = Test() assert xi == 3 # success xi = 12 # ERROR 

Jedan mora znati

Imajte na umu da gore navedene metode rade samo s instancama vašeg razreda - neće raditi kada koristite samu klasu. Na primjer:

 x = Test() assert xi == Test.i # ERROR # xi and Test.i are two different objects: type(Test.i) # class 'property' type(xi) # class 'int' 

Niz koji assert Test.i == xi uzrokuje pogrešku, budući da su atribut i Test atribut x dva različita objekta.

Mnogi ljudi će pronaći ovaj strašan. Međutim, to ne bi trebalo biti. Ako se vratimo natrag i provjerimo definiciju Test klase (druga verzija), obratit ćemo pažnju na ovu liniju:

  i = property(get_i) 

Očito, član i Test mora biti objekt property , koji je tip objekta koji vraća funkcija property .

Ako mislite da je to zbunjujuće, vjerojatno još uvijek razmišljate o tome s gledišta drugih jezika (na primjer, Java ili c ++). Morate ispitati objekt property , redoslijed kojim su Python-ovi atributi vraćeni, protokol deskriptora i redoslijed razlučivanja metoda (MRO).

Predstavljam rješenje gore navedenog "gotcha"; međutim, ja bih sugerirao - teško - tako da ne pokušavate učiniti nešto poput sljedećega, sve dok, u najmanju ruku, ne razumijete zašto assert Test.i = xi uzrokuje pogrešku.

STVARNE, Test.i == xi Statičke varijable - Test.i == xi

Predstavljam rješenje (Python 3) samo u informativne svrhe. Ne odobravam to kao "dobru odluku". Sumnjam je li u Pythonu zaista potrebno koristiti emulaciju ponašanja statičkih varijabli za druge jezike. Međutim, bez obzira je li to stvarno korisno, sljedeće bi trebalo pomoći u razumijevanju načina na koji Python funkcionira.

UPDATE: ovaj pokušaj je doista strašan ; ako inzistirate na nečemu sličnom (savjet: nemojte to činiti: Python je vrlo elegantan jezik, a cipele su da se ponaša kao drugi jezik, jednostavno nije potreban), koristite kod kao odgovor Ethanu Furmanu .

Emuliranje ponašanja statičkih varijabli u drugim jezicima pomoću metaklasa

Metaclass je klasa klase. Zadani metaklas za sve klase u Pythonu (tj. Post-Python 2,3 post-nove klase u koje vjerujem) je type . Na primjer:

 type(int) # class 'type' type(str) # class 'type' class Test(): pass type(Test) # class 'type' 

Međutim, možete definirati vlastiti metaklas kako slijedi:

 class MyMeta(type): pass 

I primijenite ga na svoju klasu kao što je ova (samo za Python 3):

 class MyClass(metaclass = MyMeta): pass type(MyClass) # class MyMeta 

Ispod je metaklas, koji sam pokušao oponašati "statičkom varijablom" ponašanja drugih jezika. U osnovi radi tako da zamijeni zadani getter, setter i deleter s verzijama koje provjeravaju je li traženi atribut "statička varijabla".

Direktorij "statičke varijable" pohranjuje se u StaticVarMeta.statics . Svi zahtjevi za atribute prvotno su pokušavali riješiti pomoću alternativnog reda za rješavanje. Ovo sam nazvao "redom statičke razlučivosti" ili "SRO". To se postiže traženjem traženog atributa u skupu "statičkih varijabli" za danu klasu (ili roditeljske klase). Ako atribut nije prikazan u "SRO", klasa će se vratiti na zadanu poziciju atributa get / set / delete (tj. "MRO").

 from functools import wraps class StaticVarsMeta(type): '''A metaclass for creating classes that emulate the "static variable" behavior of other > 
160
19 дек. Odgovor koji je dao Rick Teachey 19. prosinca 2014-12-19 18:16 '14 u 18:16 2014-12-19 18:16

Također možete dodati varijable klase u razrede u hodu.

 >>> class X: ... pass ... >>> X.bar = 0 >>> x = X() >>> x.bar 0 >>> x.foo Traceback (most recent call last): File "<interactive input>", line 1, in <module> AttributeError: X instance has no attribute 'foo' >>> X.foo = 1 >>> x.foo 1 

A instance instance mogu promijeniti varijable klase.

 class X: l = [] def __init__(self): self.l.append(1) print X().l print X().l >python test.py [1] [1, 1] 
24
17 сент. odgovor je dao Gregory 17 sep. 2008-09-17 11:06 '08 u 11:06 2008-09-17 11:06

Osobno, ja bih koristiti metodu klase kada trebam statičku metodu. Uglavnom zato što sam razred uzeo kao argument.

 class myObj(object): def myMethod(cls) ... myMethod = classmethod(myMethod) 

ili koristiti dekorater

 class myObj(object): @classmethod def myMethod(cls) 

Za statička svojstva. Svoje vrijeme možete pronaći definiciju python .. varijable uvijek može promijeniti. Postoje dvije vrste njihovih promjenjivih i nepromijenjenih. Postoje i atributi klase i atributi instance. Ništa ne izgleda poput statičkih atributa u smislu java i C ++

Zašto koristiti statičku metodu u pitonskom smislu, ako to nema nikakve veze s razredom! Da sam na tvom mjestu, koristio bih metodu klase ili definirao metodu neovisno o klasi.

14
16 сент. odgovor s emb 2008-09-16 05:02 '08 u 5:02 am 2008-09-16 05:02

Jedna napomena o statičkim i svojstvima primjera prikazana u primjeru ispod:

 class my_cls: my_prop = 0 #static property print my_cls.my_prop #--> 0 #assign value to static property my_cls.my_prop = 1 print my_cls.my_prop #--> 1 #access static property thru' instance my_inst = my_cls() print my_inst.my_prop #--> 1 #instance property is different from static property #after being assigned a value my_inst.my_prop = 2 print my_cls.my_prop #--> 1 print my_inst.my_prop #--> 2 

To znači da prije dodjeljivanja vrijednosti svojstvu instance, ako pokušamo pristupiti svojstvu kroz instancu, koristi se statička vrijednost. Svako svojstvo deklarirano u Python klasi uvijek ima utor za statičku memoriju .

13
08 марта '12 в 9:06 2012-03-08 09:06 odgovor je dao jondinham 8. ožujka 2012. u 9:06 2012-03-08 09:06

Statičke metode u pitonu nazivaju se metoda klase s. Pogledajte sljedeći kod.

 class MyClass: def myInstanceMethod(self): print 'output from an instance method' @classmethod def myStaticMethod(cls): print 'output from a static method' >>> MyClass.myInstanceMethod() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method myInstanceMethod() must be called [...] >>> MyClass.myStaticMethod() output from a static method 

Primijetite da kada zovemo metodu myInstanceMethod, dobivamo pogrešku. To je zato što zahtijeva da se metoda pozove za instancu te klase. Metoda myStaticMethod postavljena je kao metoda klase pomoću dekoratora @classmethod.

Samo iz zabave možemo nazvati myInstanceMethod za klasu, prosljeđujući instancu klase kako slijedi:

 >>> MyClass.myInstanceMethod(MyClass()) output from an instance method 
13
16 сент. odgovor dao willurd 16. rujna 2008-09-16 05:05 '08 u 5:05 am 2008-09-16 05:05

Kada se definira neka varijabla člana izvan bilo koje metode člana, varijabla može biti statična i ne-statična, ovisno o tome kako je varijabla izražena.

  • CLASSNAME.var - statička varijabla
  • INSTANCENAME.var nije statička varijabla.
  • self.var unutar klase nije statička varijabla.
  • var unutar funkcije člana klase nije definirana.

Na primjer:

 #!/usr/bin/python class A: var=1 def printvar(self): print "self.var is %d" % self.var print "A.var is %d" % A.var a = A() a.var = 2 a.printvar() A.var = 3 a.printvar() 

rezultati

 self.var is 2 A.var is 1 self.var is 2 A.var is 3 
8
26 марта '13 в 20:56 2013-03-26 20:56 odgovor je dao korisnik2209576 26. ožujka u 20:56 2013-03-26 20:56

Također možete primijeniti klasu na statičku pomoću metaclassa.

 class StaticClassError(Exception): pass class StaticClass: __metaclass__ = abc.ABCMeta def __new__(cls, *args, **kw): raise StaticClassError("%s is a static class and cannot be initiated." % cls) class MyClass(StaticClass): a = 1 b = 3 @staticmethod def add(x, y): return x+y 

Onda kad god pokušate inicijalizirati MyClass , dobit ćete StaticClassError.

6
20 нояб. odgovor daje Bartosz Ptaszynski 20 nov. 2011-11-20 15:06 '11 u 15:06 2011-11-20 15:06

Možete imati static varijable klase, ali vjerojatno ne vrijedi truda.

Evo dokaza koncepta napisanog u Pythonu 3 - ako je bilo koji točan podatak netočan, kôd se može izmijeniti tako da odgovara onome što podrazumijevate pod static variable :


 class Static: def __init__(self, value, doc=None): self.deleted = False self.value = value self.__doc__ = doc def __get__(self, inst, cls=None): if self.deleted: raise AttributeError('Attribute not set') return self.value def __set__(self, inst, value): self.deleted = False self.value = value def __delete__(self, inst): self.deleted = True class StaticType(type): def __delattr__(cls, name): obj = cls.__dict__.get(name) if isinstance(obj, Static): obj.__delete__(name) else: super(StaticType, cls).__delattr__(name) def __getattribute__(cls, *args): obj = super(StaticType, cls).__getattribute__(*args) if isinstance(obj, Static): obj = obj.__get__(cls, cls.__class__) return obj def __setattr__(cls, name, val): # check if object already exists obj = cls.__dict__.get(name) if isinstance(obj, Static): obj.__set__(name, val) else: super(StaticType, cls).__setattr__(name, val) 

i kada koristite:

 class MyStatic(metaclass=StaticType): """ Testing static vars """ a = Static(9) b = Static(12) c = 3 class YourStatic(MyStatic): d = Static('woo hoo') e = Static('doo wop') 

i neka ispitivanja:

 ms1 = MyStatic() ms2 = MyStatic() ms3 = MyStatic() assert ms1.a == ms2.a == ms3.a == MyStatic.a assert ms1.b == ms2.b == ms3.b == MyStatic.b assert ms1.c == ms2.c == ms3.c == MyStatic.c ms1.a = 77 assert ms1.a == ms2.a == ms3.a == MyStatic.a ms2.b = 99 assert ms1.b == ms2.b == ms3.b == MyStatic.b MyStatic.a = 101 assert ms1.a == ms2.a == ms3.a == MyStatic.a MyStatic.b = 139 assert ms1.b == ms2.b == ms3.b == MyStatic.b del MyStatic.b for inst in (ms1, ms2, ms3): try: getattr(inst, 'b') except AttributeError: pass else: print('AttributeError not raised on %r' % attr) ms1.c = 13 ms2.c = 17 ms3.c = 19 assert ms1.c == 13 assert ms2.c == 17 assert ms3.c == 19 MyStatic.c = 43 assert ms1.c == 13 assert ms2.c == 17 assert ms3.c == 19 ys1 = YourStatic() ys2 = YourStatic() ys3 = YourStatic() MyStatic.b = 'burgler' assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b assert ys1.d == ys2.d == ys3.d == YourStatic.d assert ys1.e == ys2.e == ys3.e == YourStatic.e ys1.a = 'blah' assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a ys2.b = 'kelp' assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b ys1.d = 'fee' assert ys1.d == ys2.d == ys3.d == YourStatic.d ys2.e = 'fie' assert ys1.e == ys2.e == ys3.e == YourStatic.e MyStatic.a = 'aargh' assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a 
5
25 марта '16 в 12:02 2016-03-25 12:02 odgovor je dao Ethan Furman 25. ožujka 2011. u 12:02 2016-03-25 12:02

Jedna vrlo zanimljiva točka u pronalaženju Python atributa je da se može koristiti za stvaranje " virtualnih varijabli":

 class A(object): label="Amazing" def __init__(self,d): self.data=d def say(self): print("%s %s!"%(self.label,self.data)) class B(A): label="Bold" # overrides A.label A(5).say() # Amazing 5! B(3).say() # Bold 3! 

Obično nakon njihovog stvaranja nema sastanaka. Imajte na umu da pregled koristi self jer iako je label statična u smislu da nije povezana s određenom instancom, vrijednost i dalje ovisi o instanci (klasi).

5
21 сент. Odgovor daje Davis Herring na 21 ruj. 2017-09-21 07:04 '17 u 7:04 2017-09-21 07:04

Najbolji način za pronalaženje drugog razreda. Možete stvoriti objekt, a zatim ga koristiti na drugim objektima.

 class staticFlag: def __init__(self): self.__success = False def isSuccess(self): return self.__success def succeed(self): self.__success = True class tryIt: def __init__(self, staticFlag): self.isSuccess = staticFlag.isSuccess self.succeed = staticFlag.succeed tryArr = [] flag = staticFlag() for i in range(10): tryArr.append(tryIt(flag)) if i == 5: tryArr[i].succeed() print tryArr[i].isSuccess() 

U gornjem primjeru sam stvorio klasu pod nazivom staticFlag .

Ova klasa bi trebala predstavljati statičku var __success (Private Static Var).

Klasa tryIt je regularna klasa koju trebamo koristiti.

Sada sam stvorio objekt za jednu zastavu ( staticFlag ). Ova oznaka bit će poslana kao veza na sve uobičajene objekte.

Svi ovi objekti se dodaju na popis tryArr .


Ovaj rezultat skripte:

 False False False False False True True True True True 
3
27 февр. Odgovor Tomeru Zaitu 27. veljače 2013-02-27 20:00 '13 u 20:00 2013-02-27 20:00

Da bi se izbjegla bilo kakva potencijalna konfuzija, željela bih se suprotstaviti statičkim varijablama i nepromjenjivim objektima.

Neke primitivne vrste objekata, kao što su cijeli brojevi, plutači, nizovi i torke, su nepromjenjivi u Pythonu. To znači da se objekt na koji upućuje ovo ime ne može promijeniti ako se odnosi na jedan od gore navedenih tipova objekata. Ime se može preraspodijeliti na drugi objekt, ali se sam objekt ne može promijeniti.

Stvaranje statičke varijable to čini i dalje, zabranjujući nazivu varijable da pokazuje na bilo koji objekt osim na koji sada pokazuje. (Napomena: ovo je opći pojam softvera i ne odnosi se na Python, pogledajte Poruke drugih korisnika za informacije o korištenju statike u Pythonu).

3
17 сент. odgovor je dan Ross 2008-09-17 07:01 '08 u 7:01 am 2008-09-17 07:01