How to make a class property? [duplicate] - python - Stack ...

文章推薦指數: 80 %
投票人數:10人

Here's how I would do this: class ClassPropertyDescriptor(object): def __init__(self, fget, fset=None): self.fget = fget self.fset = fset ... Home Public Questions Tags Users Collectives ExploreCollectives FindaJob Jobs Companies Teams StackOverflowforTeams –Collaborateandshareknowledgewithaprivategroup. CreateafreeTeam WhatisTeams? Teams CreatefreeTeam CollectivesonStackOverflow Findcentralized,trustedcontentandcollaboratearoundthetechnologiesyouusemost. Learnmore Teams Q&Aforwork Connectandshareknowledgewithinasinglelocationthatisstructuredandeasytosearch. Learnmore Howtomakeaclassproperty?[duplicate] AskQuestion Asked 11yearsago Modified 2years,2monthsago Viewed 223ktimes 178 48 Thisquestionalreadyhasanswershere: Usingproperty()onclassmethods (19answers) Closed2yearsago. InpythonIcanaddamethodtoaclasswiththe@classmethoddecorator.Isthereasimilardecoratortoaddapropertytoaclass?IcanbettershowwhatI'mtalkingabout. classExample(object): the_I=10 def__init__(self): self.an_i=20 @property defi(self): returnself.an_i definc_i(self): self.an_i+=1 #isthisevenpossible? @classproperty defI(cls): returncls.the_I @classmethod definc_I(cls): cls.the_I+=1 e=Example() asserte.i==20 e.inc_i() asserte.i==21 assertExample.I==10 Example.inc_I() assertExample.I==11 IsthesyntaxI'veusedabovepossibleorwoulditrequiresomethingmore? ThereasonIwantclasspropertiesissoIcanlazyloadclassattributes,whichseemsreasonableenough. pythonpropertiesclass-method Share Improvethisquestion Follow editedMar25,2017at15:29 martineau 110k2323goldbadges152152silverbadges272272bronzebadges askedMar4,2011at4:34 deft_codedeft_code 54k2828goldbadges138138silverbadges220220bronzebadges 5 2 Idon'tknowpython...isthisthekindofstuffyouarelookingfor?python.org/download/releases/2.2/descrintro/#property – WhiteDragon Mar4,2011at4:40 ifi'mreadingthatright,youcancreatemethodstoactasthesetterandgetter(asinotherlanguages)soyoucanlazyloadthepropertyvalueonthefirstget...whichithinkiswhatyouwanted? – WhiteDragon Mar4,2011at4:45 3 @WhiteDragon.Thepropertyfeatureyou'relookingataddspropertiestoclassinstances,nottotheclassesthemselves.I'maskingaboutExample.Inote.i. – deft_code Mar4,2011at4:57 Here'ssolutiontocreateclasspropertyinanothertopic:stackoverflow.com/a/35640842/1113207 – MikhailGerasimov Feb26,2016at0:05 Dupe:Usingproperty()onclassmethods – wim Feb4,2019at19:44 Addacomment  |  9Answers 9 Sortedby: Resettodefault Highestscore(default) Datemodified(newestfirst) Datecreated(oldestfirst) 115 Here'showIwoulddothis: classClassPropertyDescriptor(object): def__init__(self,fget,fset=None): self.fget=fget self.fset=fset def__get__(self,obj,klass=None): ifklassisNone: klass=type(obj) returnself.fget.__get__(obj,klass)() def__set__(self,obj,value): ifnotself.fset: raiseAttributeError("can'tsetattribute") type_=type(obj) returnself.fset.__get__(obj,type_)(value) defsetter(self,func): ifnotisinstance(func,(classmethod,staticmethod)): func=classmethod(func) self.fset=func returnself defclassproperty(func): ifnotisinstance(func,(classmethod,staticmethod)): func=classmethod(func) returnClassPropertyDescriptor(func) classBar(object): _bar=1 @classproperty defbar(cls): returncls._bar @bar.setter defbar(cls,value): cls._bar=value #testinstanceinstantiation foo=Bar() assertfoo.bar==1 baz=Bar() assertbaz.bar==1 #teststaticvariable baz.bar=5 assertfoo.bar==5 #testsettingvariableontheclass Bar.bar=50 assertbaz.bar==50 assertfoo.bar==50 Thesetterdidn'tworkatthetimewecallBar.bar,becausewearecalling TypeOfBar.bar.__set__,whichisnotBar.bar.__set__. Addingametaclassdefinitionsolvesthis: classClassPropertyMetaClass(type): def__setattr__(self,key,value): ifkeyinself.__dict__: obj=self.__dict__.get(key) ifobjandtype(obj)isClassPropertyDescriptor: returnobj.__set__(self,value) returnsuper(ClassPropertyMetaClass,self).__setattr__(key,value) #andupdateclassdefine: #classBar(object): #__metaclass__=ClassPropertyMetaClass #_bar=1 #andupdateClassPropertyDescriptor.__set__ #def__set__(self,obj,value): #ifnotself.fset: #raiseAttributeError("can'tsetattribute") #ifinspect.isclass(obj): #type_=obj #obj=None #else: #type_=type(obj) #returnself.fset.__get__(obj,type_)(value) Nowallwillbefine. Share Improvethisanswer Follow editedFeb1,2018at21:37 martineau 110k2323goldbadges152152silverbadges272272bronzebadges answeredMar4,2011at8:12 MahmoudAbdelkaderMahmoudAbdelkader 20.2k55goldbadges3838silverbadges5454bronzebadges 2 3 Forthosewhousepython3,inclassdefinition,useclassBar(metaclass=ClassPropertyMetaClass):insteadof__metaclass__=ClassPropertyMetaClassinside. – Pei Sep16,2020at1:52 2 Thereisjustalittleproblemin__set__function:linetype_=type(obj)needstobefollowedwithiftype_==ClassPropertyMetaClass:type_=obj(writeitrightafterthisline).Itdoesnotworkcorrectlyontheinstancelevelotherwise.Youcanalsousepackageclassutilitiesinstead(seeitonPyPi.org)thatimplementsexactlythislogic. – EmmaBrown Jul13,2021at11:45 Addacomment  |  55 Ifyoudefineclasspropertyasfollows,thenyourexampleworksexactlyasyourequested. classclassproperty(object): def__init__(self,f): self.f=f def__get__(self,obj,owner): returnself.f(owner) Thecaveatisthatyoucan'tusethisforwritableproperties.Whilee.I=20willraiseanAttributeError,Example.I=20willoverwritethepropertyobjectitself. Share Improvethisanswer Follow answeredMar4,2011at10:13 jchljchl 6,01211goldbadge2525silverbadges5151bronzebadges Addacomment  |  41 [answerwrittenbasedonpython3.4;themetaclasssyntaxdiffersin2butIthinkthetechniquewillstillwork] Youcandothiswithametaclass...mostly.Dappawit'salmostworks,butIthinkithasaflaw: classMetaFoo(type): @property defthingy(cls): returncls._thingy classFoo(object,metaclass=MetaFoo): _thingy=23 ThisgetsyouaclasspropertyonFoo,butthere'saproblem... print("Foo.thingyis{}".format(Foo.thingy)) #Foo.thingyis23 #Yay,theclassmethod-propertyisworkingasintended! foo=Foo() ifhasattr(foo,"thingy"): print("Foo().thingyis{}".format(foo.thingy)) else: print("Fooinstancehasnoattribute'thingy'") #Fooinstancehasnoattribute'thingy' #Wha....? Whatthehellisgoingonhere?Whycan'tIreachtheclasspropertyfromaninstance? IwasbeatingmyheadonthisforquiteawhilebeforefindingwhatIbelieveistheanswer.Python@propertiesareasubsetofdescriptors,and,fromthedescriptordocumentation(emphasismine): Thedefaultbehaviorforattributeaccessistoget,set,ordeletethe attributefromanobject’sdictionary.Forinstance,a.xhasalookupchain startingwitha.__dict__['x'],thentype(a).__dict__['x'],andcontinuing throughthebaseclassesoftype(a)excludingmetaclasses. Sothemethodresolutionorderdoesn'tincludeourclassproperties(oranythingelsedefinedinthemetaclass).Itispossibletomakeasubclassofthebuilt-inpropertydecoratorthatbehavesdifferently,but(citationneeded)I'vegottentheimpressiongooglingthatthedevelopershadagoodreason(whichIdonotunderstand)fordoingitthatway. Thatdoesn'tmeanwe'reoutofluck;wecanaccessthepropertiesontheclassitselfjustfine...andwecangettheclassfromtype(self)withintheinstance,whichwecanusetomake@propertydispatchers: classFoo(object,metaclass=MetaFoo): _thingy=23 @property defthingy(self): returntype(self).thingy NowFoo().thingyworksasintendedforboththeclassandtheinstances!Itwillalsocontinuetodotherightthingifaderivedclassreplacesitsunderlying_thingy(whichistheusecasethatgotmeonthishuntoriginally). Thisisn't100%satisfyingtome--havingtodosetupinboththemetaclassandobjectclassfeelslikeitviolatestheDRYprinciple.Butthelatterisjustaone-linedispatcher;I'mmostlyokaywithitexisting,andyoucouldprobablycompactitdowntoalambdaorsomethingifyoureallywanted. Share Improvethisanswer Follow editedAug7,2016at3:42 answeredAug7,2016at3:36 AndrewAndrew 3,56544goldbadges2020silverbadges3636bronzebadges 2 3 Thisshouldbethetopanswerasitworksuniversallyandforsub-classesaswell. – geckon Mar26,2017at19:18 2 Thankyouthousandtimes!Nowitsclear!Wwhooffh! – Alper91 Dec22,2020at15:13 Addacomment  |  28 Ithinkyoumaybeabletodothiswiththemetaclass.Sincethemetaclasscanbelikeaclassfortheclass(ifthatmakessense).Iknowyoucanassigna__call__()methodtothemetaclasstooverridecallingtheclass,MyClass().Iwonderifusingthepropertydecoratoronthemetaclassoperatessimilarly.(Ihaven'ttriedthisbefore,butnowI'mcurious...) [update:] Wow,itdoeswork: classMetaClass(type): defgetfoo(self): returnself._foo foo=property(getfoo) @property defbar(self): returnself._bar classMyClass(object): __metaclass__=MetaClass _foo='abc' _bar='def' printMyClass.foo printMyClass.bar Note:ThisisinPython2.7.Python3+usesadifferenttechniquetodeclareametaclass.Use:classMyClass(metaclass=MetaClass):,remove__metaclass__,andtherestisthesame. Share Improvethisanswer Follow editedMar4,2011at4:58 answeredMar4,2011at4:44 dappawitdappawit 11.5k22goldbadges3030silverbadges2626bronzebadges 4 Soitcanbedone,butcanitbedonewithamethoddecorator? – deft_code Mar4,2011at4:53 ThereisnodecoratorI'mawareofthatyoucanusedirectlyontheclassyou'reinterestedin.However,thepropertydecoratorinthemetaclassshouldwork....I'veeditedmyanswertoincludeadecoratedmetaclassmethod. – dappawit Mar4,2011at4:57 1 Alsoseethissimilarquestionanditsanswers.Seemstobesimilar,soitmayhavesomemorehelpfulinformation:) – Abbafei Mar4,2011at4:59 2 Descriptorslikepropertyneedtobeinthetype'sdictionarytoworktheirmagic.Sothoseinaclassdefinitionprimarilyaffectthebehaviourofinstancesoftheclass,withminimaleffectonthebehaviouroftheclassitself(sincetheclassisthetypeoftheinstances).Movingthedescriptorstothemetaclassallowsthemtoworktheirmagicontheclassitself(sincethemetaclassisthetypeoftheclass). – ncoghlan Mar4,2011at8:35 Addacomment  |  24 IfyouuseDjango,ithasabuiltin@classpropertydecorator. fromdjango.utils.decoratorsimportclassproperty Share Improvethisanswer Follow editedAug10,2019at2:25 answeredJul16,2019at10:30 BarneySzabolcsBarneySzabolcs 11k1111goldbadges6060silverbadges8787bronzebadges 5 3 Justsawyouaddedtheimportline.Ahyou'reright,it'stherejustnotdocumented!Icouldn'tfindanyresultshere:docs.djangoproject.com/en/2.2/search/?q=classpropertyLooksgoodnow. – inostia Aug12,2019at16:34 1 yes,indeed,Imanagedtodigthisupbychance...IthinkIdidasearchonthelibrarycodebasewiththeideathatthisshouldhavebeenimplementedsomewhere. – BarneySzabolcs Aug15,2019at11:06 thislookslikefollowing~~~classclassproperty:def__init__(self,method=None):self.fget=methoddef__get__(self,instance,cls=None):returnself.fget(cls)defgetter(self,method):self.fget=methodreturnself~~~notsureifhelpful – wiesiu_p May18,2020at13:25 ThiswasremovedinDjango3.1andcanbefoundatthebottomofthisfileifyouwanttocopy-pastadocs.djangoproject.com/en/3.0/_modules/django/utils/decorators – FábioSantos Aug12,2020at1:27 3 Itwasnotremovedbutmovedtoanothermodule.docs.djangoproject.com/en/3.1/ref/utils/… – jadelord Aug27,2020at12:40 Addacomment  |  6 AsfarasIcantell,thereisnowaytowriteasetterforaclasspropertywithoutcreatinganewmetaclass. Ihavefoundthatthefollowingmethodworks.Defineametaclasswithalloftheclasspropertiesandsettersyouwant.IE,Iwantedaclasswithatitlepropertywithasetter.Here'swhatIwrote: classTitleMeta(type): @property deftitle(self): returngetattr(self,'_title','DefaultTitle') @title.setter deftitle(self,title): self._title=title #Dowhateverelseyouwantwhenthetitleisset... Nowmaketheactualclassyouwantasnormal,excepthaveitusethemetaclassyoucreatedabove. #Python2style: classClassWithTitle(object): __metaclass__=TitleMeta #Therestofyourclassdefinition... #Python3style: classClassWithTitle(object,metaclass=TitleMeta): #Yourclassdefinition... It'sabitweirdtodefinethismetaclassaswedidaboveifwe'llonlyeveruseitonthesingleclass.Inthatcase,ifyou'reusingthePython2style,youcanactuallydefinethemetaclassinsidetheclassbody.Thatwayit'snotdefinedinthemodulescope. Share Improvethisanswer Follow answeredFeb28,2016at20:08 ArtOfWarfareArtOfWarfare 18.9k1616goldbadges125125silverbadges183183bronzebadges Addacomment  |  2 def_create_type(meta,name,attrs): type_name=f'{name}Type' type_attrs={} fork,vinattrs.items(): iftype(v)is_ClassPropertyDescriptor: type_attrs[k]=v returntype(type_name,(meta,),type_attrs) classClassPropertyType(type): def__new__(meta,name,bases,attrs): Type=_create_type(meta,name,attrs) cls=super().__new__(meta,name,bases,attrs) cls.__class__=Type returncls class_ClassPropertyDescriptor(object): def__init__(self,fget,fset=None): self.fget=fget self.fset=fset def__get__(self,obj,owner): ifselfinobj.__dict__.values(): returnself.fget(obj) returnself.fget(owner) def__set__(self,obj,value): ifnotself.fset: raiseAttributeError("can'tsetattribute") returnself.fset(obj,value) defsetter(self,func): self.fset=func returnself defclassproperty(func): return_ClassPropertyDescriptor(func) classBar(metaclass=ClassPropertyType): __bar=1 @classproperty defbar(cls): returncls.__bar @bar.setter defbar(cls,value): cls.__bar=value bar=Bar() assertBar.bar==1 Bar.bar=2 assertbar.bar==2 nbar=Bar() assertnbar.bar==2 Share Improvethisanswer Follow editedDec29,2019at18:48 RolandPuntaier 2,8592525silverbadges3131bronzebadges answeredJul5,2019at6:31 thinker3thinker3 11.8k55goldbadges2828silverbadges3535bronzebadges Addacomment  |  1 Ifyouonlyneedlazyloading,thenyoucouldjusthaveaclassinitialisationmethod. EXAMPLE_SET=False classExample(object): @classmethod definitclass(cls): globalEXAMPLE_SET ifEXAMPLE_SET:return cls.the_I='ok' EXAMPLE_SET=True def__init__(self): Example.initclass() self.an_i=20 try: printExample.the_I exceptAttributeError: print'okclassnot"loaded"' foo=Example() printfoo.the_I printExample.the_I Butthemetaclassapproachseemscleaner,andwithmorepredictablebehavior. Perhapswhatyou'relookingforistheSingletondesignpattern.There'saniceSOQAaboutimplementingsharedstateinPython. Share Improvethisanswer Follow editedMay23,2017at12:34 CommunityBot 111silverbadge answeredMar4,2011at5:25 ApalalaApalala 8,61833goldbadges2828silverbadges4848bronzebadges Addacomment  |  1 Ihappenedtocomeupwithasolutionverysimilarto@Andrew,onlyDRY classMetaFoo(type): def__new__(mc1,name,bases,nmspc): nmspc.update({'thingy':MetaFoo.thingy}) returnsuper(MetaFoo,mc1).__new__(mc1,name,bases,nmspc) @property defthingy(cls): ifnotinspect.isclass(cls): cls=type(cls) returncls._thingy @thingy.setter defthingy(cls,value): ifnotinspect.isclass(cls): cls=type(cls) cls._thingy=value classFoo(metaclass=MetaFoo): _thingy=23 classBar(Foo) _thingy=12 Thishasthebestofallanswers: The"metaproperty"isaddedtotheclass,sothatitwillstillbeapropertyoftheinstance Don'tneedtoredefinethingyinanyoftheclasses Thepropertyworksasa"classproperty"inforbothinstanceandclass Youhavetheflexibilitytocustomizehow_thingyisinherited Inmycase,Iactuallycustomized_thingytobedifferentforeverychild,withoutdefiningitineachclass(andwithoutadefaultvalue)by: def__new__(mc1,name,bases,nmspc): nmspc.update({'thingy':MetaFoo.services,'_thingy':None}) returnsuper(MetaFoo,mc1).__new__(mc1,name,bases,nmspc) Share Improvethisanswer Follow editedJan4,2019at20:29 answeredJan4,2019at19:21 AndyAndy 2,54311goldbadge1414silverbadges2222bronzebadges Addacomment  |  Nottheansweryou'relookingfor?Browseotherquestionstaggedpythonpropertiesclass-methodoraskyourownquestion. TheOverflowBlog AIandnanotechnologyareworkingtogethertosolvereal-worldproblems GettingthroughaSOC2auditwithyournervesintact FeaturedonMeta WhatgoesintositesponsorshipsonSE? StackExchangeQ&AaccesswillnotberestrictedinRussia NewUserExperience:DeepDiveintoourResearchontheStagingGround–How... AskWizardforNewUsersFeatureTestisnowLive Linked 240 Usingproperty()onclassmethods 0 Inpythonwhichmethodhastobeoverriddentovalidatetheclassvariables 1 MemoizingstaticpropertiesinPython 0 Howtodeclareastaticattributethatpointstothesameobject/reference 1 Classpropertyderivedfrom(abstract)classproperties 1 @propertywith@staticmethodinPython3 0 Icantcreateapythonpropertyinastaticclass 1 Using@classmethodwith@property 506 Isthereasimple,elegantwaytodefinesingletons? 368 Understanding__get__and__set__andPythondescriptors Seemorelinkedquestions Related 6193 HowdoImergetwodictionariesinasingleexpression(takeunionofdictionaries)? 6563 HowdoIcheckwhetherafileexistswithoutexceptions? 5633 Howtoexecuteaprogramorcallasystemcommand? 5128 HowcanIsafelycreateanesteddirectory? 3011 Howtomakefunctiondecoratorsandchainthemtogether? 4551 Howtomakeaflatlistoutofalistoflists? 3466 HowdoIlistallfilesofadirectory? 1210 Howdoesthe@propertydecoratorworkinPython? 423 Propertyinitializationusing"bylazy"vs."lateinit" HotNetworkQuestions StopPipesFromPullingThroughTheWall WhydidYon-RoggwanttofightCaptainMarvelhand-to-handafterhecrashesonEarth? RecreateMinecraft'slighting WhatisthegeographicallocationofPython(andotheropen-sourcesoftwareprojects)? Whatisthenextmoveonthisminesweeperboard? Whatdoesthisportionofthescoremeanwherethetrebleandbassclefsintersect? EnigmarchDay1:Initial Howtogetamotorcycletoaskillstest HowcanIreplaceastringinatext? ITstaffsaidthatLinuxcannotconnecttotheschool'sInternet(EduStar)andrefusedtotry "wecouldtiptheecologyoffinawaythatwouldbereallyunfortunate" HowDoesBlackWinThisposition Whataresomegoodoptionsformuseums/memorialstolearnmoreaboutthehistoryofJimCrow/lynching Haskellcomparingtwolists'lengthsbutoneofthemisinfinite? WhydoAirForceplanesregularlyflyincircles? ConvertDateformattoinsertintoMySQLdatabase Constructiveproofofstrongnormalizationforsimplytypedlambdacalculus Spaceshipshooter FilterNotWorkingforcustomcolumnui_componentgridMagento2 Isitimpolitetosendtheprofessorapre-writtenletterofrecommendationforapproval? Inthesentence"Thetablewassetforlunch"is"set"averboranadjective? WhydosomanystandardsforJSONAPIresponseformatscontaina"success"propertyintheresponsebodyinsteadofjustusingHTTPstatuscodes? ConnectingHundredsofServersviaLocalNetwork(LAN)? Whatpeople,ifany,pushedPutinintothewarwithUkraine? morehotquestions lang-py Yourprivacy Byclicking“Acceptallcookies”,youagreeStackExchangecanstorecookiesonyourdeviceanddiscloseinformationinaccordancewithourCookiePolicy. Acceptallcookies Customizesettings  



請為這篇文章評分?