Ar galimi statinio klasės kintamieji?

Ar galima turėti statinius klasės kintamuosius arba metodus pythone? Kokia sintaksė reikalinga?

1598
16 сент. nustatė Andrew Walker, rugsėjo 16 d 2008-09-16 04:46 '08, 4:46, 2008-09-16 04:46
@ 17 atsakymų

Kintamieji, deklaruoti klasės apibrėžime, bet ne metode, yra klasės arba statiniai kintamieji:

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

Kaip nurodo @ millerdev , tai sukuria klasės kintamąjį i klasės lygmeniu, tačiau ji skiriasi nuo bet kokio i kintamojo lygmens, todėl jums gali būti

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

Tai skiriasi nuo „C ++“ ir „Java“, bet ne taip skiriasi nuo C #, kur neįmanoma pasiekti statinio nario, naudojant egzemplioriaus nuorodą.

Pažiūrėkite, ką Python pamoka turėtų pasakyti apie klases ir klasės objektus .

@Steve Johnson jau reagavo į statinius metodus , kurie taip pat aprašyti „Python Library Reference“ „Integruotose funkcijose“ .

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

@beidy rekomenduoja klasikinį metodą statiniu metodu, nes metodas tampa pirmuoju argumentu, tačiau aš vis dar truputį neryškus apie šio požiūrio privalumus, palyginti su statiniu metodu. Jei per daug, tai tikriausiai nesvarbu.

1575 m
16 сент. Blair Conrad atsakymas, pateiktas rugsėjo 16 d. 2008-09-16 04:51 '08 at 4:51 am 2008-09-16 04:51

@Blair Konradas sakė, kad statiniai kintamieji, deklaruoti klasės apibrėžime, bet ne metode, yra klasės arba „statiniai“ kintamieji:

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

Čia yra keletas variantų. Atlikite aukščiau pateiktą pavyzdį:

 >>> 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__ {} 

Atkreipkite dėmesį, kad pavyzdžio kintamasis ti nesinchronizavo su "statiniu" klasės kintamuoju, kai atributas i buvo nustatytas tiesiai į t . Taip yra dėl to, kad i buvau pakartotinai susietas vardų srityje t , kuri skiriasi nuo vardų erdvės Test . Jei norite keisti „statinio“ kintamojo vertę, turite ją pakeisti pagal taikymo sritį (ar objektą), kur jis buvo iš pradžių nustatytas. „Statinis“ pateikiamas kabutėse, nes „Python“ iš tikrųjų neturi statinių kintamųjų, ty C + + ir „Java“.

Nors „ Python“ vadovėlyje nėra nieko konkretaus apie statinius kintamuosius ar metodus, jame pateikiama tam tikra svarbi informacija apie klasės klases ir objektus .

border=0

@Steve Johnson taip pat reagavo į statinius metodus, taip pat aprašytus Python Library Reference skyriuje „Inline Functions“.

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

„@beid“ taip pat nurodo klasių metodą, kuris yra panašus į statinį metodą. Pirmasis klasės metodo argumentas yra klasės objektas. Pavyzdys:

 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 сент. Atsakymą 16 sekundžių pateikia milerdev . 2008-09-16 06:04 '08 at 6:04 2008-09-16 06:04

Statiniai ir klasės metodai

Kaip pažymėjo kiti atsakymai, statiniai ir atvėsti metodai lengvai atliekami naudojant įmontuotus dekoratorius:

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

Kaip įprasta, pirmasis MyMethod() argumentas MyMethod() susietas su klasės egzemplioriaus objektu. Priešingai, pirmasis „ MyClassMethod() argumentas MyClassMethod() susietas su pačiu klasės objektu (pavyzdžiui, šiuo atveju, „ Test ). MyStaticMethod() nė vienas iš argumentų nėra privalomas, o argumentai paprastai yra neprivalomi.

„Statiniai kintamieji“

Tačiau "statinių kintamųjų" įgyvendinimas (gerai, keičiantys statiniai kintamieji, bet kuriuo atveju, jei tai nėra prieštaravimas dėl ...) nėra toks paprastas. Kaip Millerdevas pažymėjo savo atsakyme , problema ta, kad Python klasės atributai nėra „statiniai kintamieji“. Peržiūra:

 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 

Taip yra dėl to, kad eilutė xi = 12 pridėjo naują egzemplioriaus atributą nuo i iki x vietoj to, kad pakeistų atributo Test class i vertę.

Dalinis laukiamas statinio kintamojo elgesys, t.y. Atributo sinchronizavimą tarp kelių egzempliorių (bet ne su pačia klase, žr. „Gotcha“ žemiau) galima pasiekti keičiant klasės atributą į nuosavybę:

 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) 

Dabar galite padaryti:

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

Dabar statinis kintamasis bus sinchronizuojamas tarp visų klasės egzempliorių.

(PASTABA: tai yra, jei klasės pavyzdys _i nustatyti savo _i versijos! Bet jei kas nors nusprendžia tai padaryti, jie nusipelno to, ką jie gauna, ar ne?)

Atkreipkite dėmesį, kad techniniu požiūriu i vis dar nėra „statinis kintamasis“; ši property yra specialus deskriptoriaus tipas. Tačiau property elgesys dabar yra lygiavertis (kintamajam) statiniam kintamajam, kuris sinchronizuojamas visose klasės klasėse.

Nepakeičiami "statiniai kintamieji"

Kad statinis kintamasis elgtųsi, palikite property setter:

 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) 

Dabar bandymas nustatyti „ i atributą „ AttributeError :

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

Vienas turi žinoti

Atkreipkite dėmesį, kad minėti metodai veikia tik su jūsų klasės egzemplioriais - jie neveiks, kai naudojasi pačia klase. Taigi, pavyzdžiui:

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

Straipsnio eilutė „ assert Test.i == xi sukelia klaidą, nes „ i Test atributas ir x atributas yra du skirtingi objektai.

Daugelis žmonių ras šį nuostabų. Tačiau tai neturėtų būti. Jei grįšime ir patikrinsime Test klasės apibrėžimą (antroji versija), atkreipsime dėmesį į šią eilutę:

  i = property(get_i) 

Akivaizdu, kad „ i Test narys turi būti property objektas, kuris yra objekto, kurį grąžina property funkcija, tipas.

Jei manote, kad tai paini, greičiausiai vis tiek galvojate apie tai kitų kalbų (pvz., „Java“ arba „c ++“) požiūriu. Turite išnagrinėti property objektą, Python atributų grąžinimo tvarką, deskriptoriaus protokolą ir metodo skiriamąją tvarką (MRO).

Pateikiu aukščiau pateikto „gotcha“ sprendimą; tačiau aš norėčiau pasiūlyti, kad nesistengtumėte kažką panašaus daryti, kol bent jau suprasite, kodėl assert Test.i = xi sukelia klaidą.

REAL, ACTUAL Static Variables - Test.i == xi

Pateikiu sprendimą (Python 3) tik informaciniais tikslais. Aš tai nepritariu „geram sprendimui“. Turiu abejonių, ar iš tikrųjų reikia panaudoti kitų kalbų statinių kintamųjų elgseną Pythone. Tačiau, nepaisant to, ar tai tikrai naudinga, toliau turėtų padėti suprasti, kaip veikia „Python“.

UPDATE: šis bandymas yra labai baisus ; jei primygtinai reikalaujate kažką panašaus (užuomina: nedarykite to: „Python“ yra labai elegantiška kalba, o batai yra tokie, kad jie elgiasi kaip kita kalba, tiesiog nereikia), naudokite kodą atsakydamas į Ethan Furman .

Statinių kintamųjų elgesio kitomis kalbomis emuliavimas naudojant metaklasę

Metaclass yra klasės klasė. Numatytasis metaklasas visoms Python klasėms (t. Y. Post-Python 2.3 po naujų klasių, kurias aš tikiu) yra type . Pavyzdžiui:

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

Tačiau galite nustatyti savo metaklasę taip:

 class MyMeta(type): pass 

Ir naudokite ją savo klasėje, kaip tai (tik „Python 3“):

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

Žemiau yra metaklasė, kurią bandžiau sekti kitų kalbų „statinį kintamąjį“ elgesį. Tai iš esmės veikia pakeičiant numatytąjį „getter“, „seter“ ir „deleter“ su versijomis, kurios tikrina, ar prašomas atributas yra „statinis kintamasis“.

„Statinis kintamųjų“ katalogas yra saugomas „ StaticVarMeta.statics . Visi atributų prašymai buvo iš pradžių bandyti išspręsti naudojant alternatyvią rezoliuciją. Aš tai pavadinau „statine raiška“ arba „SRO“. Tai daroma ieškant reikalaujamo atributo „statinių kintamųjų“ rinkinyje tam tikrai klasei (arba jos tėvų klasėms). Jei atributas „SRO“ nerodomas, klasė grįš į numatytąją „get / set / delete“ atributo poziciją (ty „MRO“).

 from functools import wraps class StaticVarsMeta(type): '''A metaclass for creating classes that emulate the "static variable" behavior of other > 
160
19 дек. Atsakymas, kurį pateikė Rick Teachey 19 d 2014-12-19 18:16 '14, 18:16 2014-12-19 18:16

Taip pat galite priskirti klasių kintamuosius klasėms skrydžio metu.

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

Ir egzempliorių pavyzdžiai gali pakeisti klasės kintamuosius.

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

Asmeniškai norėčiau naudoti klasės metodą, kai man reikia statinio metodo. Dažniausiai todėl, kad klasę ginu kaip argumentą.

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

arba naudokite dekoratorių

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

Dėl statinių savybių. Jo metu galite rasti python apibrėžimą .. kintamasis visada gali keistis. Yra dviejų tipų jų keičiamos ir nepakitusios. Taip pat yra klasės atributų ir pavyzdžių atributai. Niekas atrodo kaip statiniai atributai java ir C ++ prasme

Kodėl naudoti statinį metodą pythonine prasme, jei jis neturi nieko bendro su klase! Jei aš buvau tavęs, naudoju klasės metodą arba apibrėžčiau metodą, nepriklausomą nuo klasės.

14
16 сент. atsakymas duotas emb 16 Sep 2008-09-16 05:02 '08 at 5:02 am 2008-09-16 05:02

Viena pastaba apie statinio ir pavyzdžio ypatybes, pateiktas toliau pateiktame pavyzdyje:

 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 

Tai reiškia, kad prieš priskiriant vertę egzemplioriaus nuosavybei, jei bandome pasiekti turinį per pavyzdį, naudojama statinė vertė. Kiekviena savybė, deklaruota „python“ klasėje, visada turi statinį atminties lizdą .

13
08 марта '12 в 9:06 2012-03-08 09:06 atsakymą pateikė „ jondinham “ kovo 8 d. 12 val. 9:06 2012-03-08 09:06

Statiniai pythono metodai vadinami klasių metodais . Pažvelkite į šį 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 

Atkreipkite dėmesį, kad kai mes vadiname myInstanceMethod metodu, gauname klaidą. Taip yra todėl, kad reikalaujama, kad metodas būtų vadinamas šios klasės pavyzdžiu. MyStaticMethod metodas nustatytas kaip klasės metodas, naudojant @classmethod dekoratorių .

Tiesiog linksmam, mes galime skambinti „myInstanceMethod“ klasei, perduodami klasės egzempliorių taip:

 >>> MyClass.myInstanceMethod(MyClass()) output from an instance method 
13
16 сент. atsakymas, kurį pateikė testamentas rugsėjo 16 d 2008-09-16 05:05 '08, 5:05 am. 2008-09-16 05:05

Apibrėžiant tam tikrą nario kintamąjį už bet kurio metodo ribų, kintamasis gali būti ir statinis, ir ne statinis, priklausomai nuo to, kaip kintamasis išreiškiamas.

  • CLASSNAME.var - statinis kintamasis
  • INSTANCENAME.var nėra statinis kintamasis.
  • savarankiška klasė nėra statinis kintamasis.
  • var viduje nario funkcijos nėra apibrėžta.

Pavyzdžiui:

 #!/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() 

Rezultatai

 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 atsakymą pateikė vartotojo2209576 kovo 26 d. , 13:20, 2013-03-26 20:56

Taip pat galite taikyti klasę statinei, naudodami metaklasę.

 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 

Tada, kai bandysite inicijuoti „ MyClass“ , gausite „StaticClassError“.

6
20 нояб. atsakymą pateikė Bartosz Ptaszynski 20 nov. 2011-11-20 15:06 '11, 15:06, 2011-11-20 15:06

Jūs galite turėti klasių kintamuosius static , bet tikriausiai ne verta pastangų.

Čia pateikiamas „Python 3“ parašytos koncepcijos įrodymas - jei kuri nors iš tikslų duomenų yra neteisinga, kodas gali būti pakeistas, kad atitiktų 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) 

ir naudojant:

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

ir kai kurie bandymai:

 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 atsakymą pateikė Ethan Furman , kovo 25 d. 16, 12:02 2016-03-25 12:02

Vienas labai įdomus dalykas ieškant Python atributų yra tas, kad jis gali būti naudojamas „ virtualiems kintamiesiems“ kurti:

 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! 

Paprastai po jų sukūrimo nėra paskyrimų. Atkreipkite dėmesį, kad peržvalga naudoja self nes nors label statinė, nes nėra susieta su konkrečiu atveju, vertė vis dar priklauso nuo egzemplioriaus (klasės).

5
21 сент. Atsakymą davė Davis Herring 21 sep. 2017-09-21 07:04 '17, 07:04 2017-09-21 07:04

Geriausias būdas rasti kitą klasę. Galite sukurti objektą ir tada jį naudoti kituose objektuose.

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

Pirmiau pateiktame pavyzdyje sukūriau klasę, pavadintą staticFlag .

Ši klasė turėtų pateikti statinį var __success (Private Static Var).

tryIt klasė yra įprastinė klasė, kurią turime naudoti.

Dabar sukūriau vieną vėliavos objektą ( staticFlag ). Ši vėliava bus siunčiama kaip nuoroda į visus įprastus objektus.

Visi šie objektai pridedami prie tryArr sąrašo.


Šis scenarijaus rezultatas:

 False False False False False True True True True True 
3
27 февр. Atsakymas Tomer Zait 27 vas 2013-02-27 20:00 '13 20:00 val. 2013-02-27 20:00

Norint išvengti galimo painiavos, norėčiau kovoti su statiniais kintamaisiais ir nekintamais objektais.

Kai kurie primityvūs objektų tipai, pvz., Sveikieji skaičiai, plūdės, stygos ir eilutės, Python yra nekeičiami. Tai reiškia, kad objektas, kuriuo remiasi šis pavadinimas, negali keistis, jei jis susijęs su vienu iš pirmiau nurodytų objektų tipų. Pavadinimą galima perkelti į kitą objektą, tačiau pats objektas negali būti pakeistas.

Statinio kintamojo sukūrimas tai dar labiau uždraudžia kintamojo pavadinimą nukreipti į bet kurį kitą objektą, išskyrus tą, kurį jis dabar nurodo. (Pastaba: tai yra bendra programinės įrangos koncepcija ir netaikoma „Python“, žr. „Kitų naudotojų pranešimai“, kaip gauti informaciją apie statikos naudojimą „Python“).

3
ответ дан Ross 17 сент. '08 в 7:01 2008-09-17 07:01