What is a clean "pythonic" way to implement multiple ...

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

As far as I know, you can't have multiple __init__ functions in a Python class. So how do I solve this problem? Lessthan10daystoRSVP!Virtuallyjoinusatourinauguralconference,everyoneiswelcome. Home Public Questions Tags Users Companies Collectives ExploreCollectives Teams StackOverflowforTeams –Startcollaboratingandsharingorganizationalknowledge. CreateafreeTeam WhyTeams? Teams CreatefreeTeam Collectives™onStackOverflow Findcentralized,trustedcontentandcollaboratearoundthetechnologiesyouusemost. LearnmoreaboutCollectives Teams Q&Aforwork Connectandshareknowledgewithinasinglelocationthatisstructuredandeasytosearch. LearnmoreaboutTeams Whatisaclean"pythonic"waytoimplementmultipleconstructors? AskQuestion Asked 13years,6monthsago Modified 4monthsago Viewed 424ktimes 899 355 Ican'tfindadefinitiveanswerforthis.AsfarasIknow,youcan'thavemultiple__init__functionsinaPythonclass.SohowdoIsolvethisproblem? SupposeIhaveaclasscalledCheesewiththenumber_of_holesproperty.HowcanIhavetwowaysofcreatingcheeseobjects... Onethattakesanumberofholeslikethis:parmesan=Cheese(num_holes=15). Andonethattakesnoargumentsandjustrandomizesthenumber_of_holesproperty:gouda=Cheese(). Icanthinkofonlyonewaytodothis,butthisseemsclunky: classCheese(): def__init__(self,num_holes=0): if(num_holes==0): #Randomizenumber_of_holes else: number_of_holes=num_holes Whatdoyousay?Isthereanotherway? pythonclassconstructor Share Improvethisquestion Follow editedMar6at10:24 martineau 115k2525goldbadges160160silverbadges283283bronzebadges askedMar25,2009at17:00 winsmithwinsmith 19.9k88goldbadges3838silverbadges4848bronzebadges 3 7 Ithinkinitisnotaconstructor,itisaninitializer.newwouldbeaconstructor – fanny Feb20,2019at13:11 Related(notduplicate):HowcanIdetectduplicatemethodnamesinaPythonclass? – PeterMortensen Jan6,2021at16:12 Ithinkthatthisquestioncouldbere-titled,"HowcanIhavedefaultargumentsforaclassconstructor?" – SamuelMuldoon Aug23at23:40 Addacomment  |  14Answers 14 Sortedby: Resettodefault Highestscore(default) Trending(recentvotescountmore) Datemodified(newestfirst) Datecreated(oldestfirst) 942 ActuallyNoneismuchbetterfor"magic"values: classCheese(): def__init__(self,num_holes=None): ifnum_holesisNone: ... Nowifyouwantcompletefreedomofaddingmoreparameters: classCheese(): def__init__(self,*args,**kwargs): #args--tupleofanonymousarguments #kwargs--dictionaryofnamedarguments self.num_holes=kwargs.get('num_holes',random_holes()) Tobetterexplaintheconceptof*argsand**kwargs(youcanactuallychangethesenames): deff(*args,**kwargs): print'args:',args,'kwargs:',kwargs >>>f('a') args:('a',)kwargs:{} >>>f(ar='a') args:()kwargs:{'ar':'a'} >>>f(1,2,param=3) args:(1,2)kwargs:{'param':3} http://docs.python.org/reference/expressions.html#calls Share Improvethisanswer Follow editedMar7,2016at0:41 EliasZamaria 91.3k3131goldbadges112112silverbadges143143bronzebadges answeredMar25,2009at17:03 vartecvartec 127k3636goldbadges213213silverbadges242242bronzebadges 7 104 Forthoseinterested,kwargsstandsforkeywordarguments(seemslogiconceyouknowit).:) – tleb Aug3,2016at6:29 45 Therearemomentsthat*argsand**kwargsareanoverkill.Atmostconstructors,youwanttoknowwhatyourargumentsare. – user989762 Apr28,2018at9:26 1 @user989762Yes!Forsure! – CaptainJackSparrow Apr15,2020at0:30 8 @user989762Yeah,thisapproachisnotself-documentingatall(howmanytimeshaveyoutriedtousealibraryandtriedtointuitedtheusagefrommethodsignaturesonlytodiscoveryouhavetodoacodedivetoseewhatargumentsareexpected/allowed?)Moreover,nowyourimplementationtakesontheaddedburdenofargumentchecking,includingthechoiceofwhethertoacceptorexcept(teehee)unsupportedarguments. – GlenRSmith Jul22,2020at15:36 23 Forfolksfromgooglein2020,scrolldownthispageabit-theanswerby'Ber'furtherdownissolidandmorepythonicthanthisrouteformostscenarios. – TomH Nov12,2020at13:40  |  Show2morecomments 896 Usingnum_holes=Noneasthedefaultisfineifyouaregoingtohavejust__init__. Ifyouwantmultiple,independent"constructors",youcanprovidetheseasclassmethods.Theseareusuallycalledfactorymethods.Inthiscaseyoucouldhavethedefaultfornum_holesbe0. classCheese(object): def__init__(self,num_holes=0): "defaultstoasolidcheese" self.number_of_holes=num_holes @classmethod defrandom(cls): returncls(randint(0,100)) @classmethod defslightly_holey(cls): returncls(randint(0,33)) @classmethod defvery_holey(cls): returncls(randint(66,100)) Nowcreateobjectlikethis: gouda=Cheese() emmentaler=Cheese.random() leerdammer=Cheese.slightly_holey() Share Improvethisanswer Follow editedJan10,2019at6:08 ShadowRanger 131k1212goldbadges168168silverbadges244244bronzebadges answeredMar25,2009at17:11 BerBer 38.1k1515goldbadges6868silverbadges8282bronzebadges 19 37 @rmbianchi:Theacceptedanswermaybemoreinlinewithotherlanguages,butitisalsolesspythonic:@classmethodsarethepythonicwayofimplementingmultiplecontstructors. – EthanFurman Mar22,2012at1:34 21 @BepetersnThereareinstancemethods(thenormalones),whichhaveaninstanceobjectreferencedasself.Thenthereareclassmethods(using@classmethod)whichhaveareferencetotheclassobjectascls.Anfinallytherearestaticmethods(declaredwith@staticmethod)whichhaveneitherofthosereferences.Staticmethodsarejustlikefunctionsatmodulelevel,excepttheyliveintheclass'namespace. – Ber Apr22,2013at11:10 3 Anadvantageofthismethodovertheacceptedsolutionisthatiteasilyallowstospecifyabstractconstructorsandenforceimplementationofthem,especiallywithpython3inwhichtheusageof@abstractmethodand@classmethodonthesamefactoryfunctionispossibleandisbuiltintothelanguage.Iwouldalsoarguethatthisapproachismoreexplicit,whichgoeswithTheZenofPython. – mach Sep4,2014at13:16 4 @ashuTheotherconstructorscallthe__init__()methodbyinstantiatingtheclassviacls(...).Therefore,thenumber_of_holesisalwaysusedinthesameway. – Ber Aug23,2018at11:37 2 @RegisMay(1/2)Ratherthanhavingabunchofifsin__init__(),thetrickistohaveeachoftheuniquefactorymethodshandletheirownuniqueaspectsofinitialization,andhave__init__()acceptonlythefundamentalpiecesofdatathatdefineaninstance.Forexample,Cheesemighthaveattributesvolumeandaverage_hole_radiusinadditiontonumber_of_holes.__init__()wouldacceptthesethreevalues.Thenyoucouldhaveaclassmethodwith_density()thatrandomlychoosesthefundamentalattributestomatchagivendensity,subsequentlypassingthemonto__init__(). – NathanielJones Jun22,2020at20:28  |  Show14morecomments 64 Oneshoulddefinitelypreferthesolutionsalreadyposted,butsincenoonementionedthissolutionyet,Ithinkitisworthmentioningforcompleteness. The@classmethodapproachcanbemodifiedtoprovideanalternativeconstructorwhichdoesnotinvokethedefaultconstructor(__init__).Instead,aninstanceiscreatedusing__new__. Thiscouldbeusedifthetypeofinitializationcannotbeselectedbasedonthetypeoftheconstructorargument,andtheconstructorsdonotsharecode. Example: classMyClass(set): def__init__(self,filename): self._value=load_from_file(filename) @classmethod deffrom_somewhere(cls,somename): obj=cls.__new__(cls)#Doesnotcall__init__ super(MyClass,obj).__init__()#Don'tforgettocallanypolymorphicbaseclassinitializers obj._value=load_from_somewhere(somename) returnobj Share Improvethisanswer Follow editedMar1,2020at23:20 NeilG 31k3838goldbadges150150silverbadges250250bronzebadges answeredAug11,2016at0:20 AndrzejPronobisAndrzejPronobis 31.8k1717goldbadges7272silverbadges9090bronzebadges 3 15 Thisisthesolutionthatindeedprovidesindependentconstructorsinsteadoffiddlingwith__init__'sarguments.However,couldyouprovidesomereferences,please,thatthismethodissomehowofficiallyapprovedorsupported?Howsafeandreliableisittocalldirectly__new__method? – Alexey Feb20,2018at14:11 1 Ididthingsthiswayandthencameheretoasktheabovequestiontoseeifmywaywasright.Youstillneedtocallsuperotherwisethiswon'tworkincooperativemultipleinheritance,soIaddedthelinetoyouranswer. – NeilG Mar1,2020at23:22 1 Iwonderifonecoulddefineadecorator'constructor'(thatwrapsupthenewandsuperstuff)andthendo:@constructordefother_init(self,stuff):self.stuff=stuff – TomWinch Oct30,2020at16:36 Addacomment  |  31 Alloftheseanswersareexcellentifyouwanttouseoptionalparameters,butanotherPythonicpossibilityistouseaclassmethodtogenerateafactory-stylepseudo-constructor: def__init__(self,num_holes): #dostuffwiththenumber @classmethod deffromRandom(cls): returncls(#some-random-number) Share Improvethisanswer Follow answeredMar25,2009at17:16 Yes-thatJake.Yes-thatJake. 16.4k1414goldbadges7171silverbadges9595bronzebadges Addacomment  |  21 Whydoyouthinkyoursolutionis"clunky"?PersonallyIwouldpreferoneconstructorwithdefaultvaluesovermultipleoverloadedconstructorsinsituationslikeyours(Pythondoesnotsupportmethodoverloadinganyway): def__init__(self,num_holes=None): ifnum_holesisNone: #Constructagouda else: #customcheese #commoninitialization Forreallycomplexcaseswithlotsofdifferentconstructors,itmightbecleanertousedifferentfactoryfunctionsinstead: @classmethod defcreate_gouda(cls): c=Cheese() #... returnc @classmethod defcreate_cheddar(cls): #... InyourcheeseexampleyoumightwanttouseaGoudasubclassofCheesethough... Share Improvethisanswer Follow answeredMar25,2009at17:11 FerdinandBeyerFerdinandBeyer 62.4k1515goldbadges151151silverbadges143143bronzebadges 1 5 Factoryfunctionsusecls:useclsinsteadofCheese.Ifnot,whatisthepointofusingclassmethodsinsteadofstaticmethods? – rools Aug2,2018at11:53 Addacomment  |  19 Thosearegoodideasforyourimplementation,butifyouarepresentingacheesemakinginterfacetoauser.Theydon'tcarehowmanyholesthecheesehasorwhatinternalsgointomakingcheese.Theuserofyourcodejustwants"gouda"or"parmesean"right? Sowhynotdothis: #cheese_user.py fromcheesesimportmake_gouda,make_parmesean gouda=make_gouda() paremesean=make_parmesean() Andthenyoucanuseanyofthemethodsabovetoactuallyimplementthefunctions: #cheeses.py classCheese(object): def__init__(self,*args,**kwargs): #args--tupleofanonymousarguments #kwargs--dictionaryofnamedarguments self.num_holes=kwargs.get('num_holes',random_holes()) defmake_gouda(): returnCheese() defmake_paremesean(): returnCheese(num_holes=15) Thisisagoodencapsulationtechnique,andIthinkitismorePythonic.Tomethiswayofdoingthingsfitsmoreinlinemorewithducktyping.Youaresimplyaskingforagoudaobjectandyoudon'treallycarewhatclassitis. Share Improvethisanswer Follow answeredOct25,2011at15:06 BradCBradC 72088silverbadges1414bronzebadges 2 2 ItendtooptforthisapproachbecauseitisremarkablysimilartotheFactoryMethodpattern. – 2rs2ts May30,2013at0:21 6 make_gouda,make_parmesanshouldbeclassmethodsofclassCheese – smci Jul17,2018at23:11 Addacomment  |  11 Overview Forthespecificcheeseexample,Iagreewithmanyoftheotheranswersaboutusingdefaultvaluestosignalrandominitializationortouseastaticfactorymethod.However,theremayalsoberelatedscenariosthatyouhadinmindwherethereisvalueinhavingalternative,concisewaysofcallingtheconstructorwithouthurtingthequalityofparameternamesortypeinformation. SincePython3.8andfunctools.singledispatchmethodcanhelpaccomplishthisinmanycases(andthemoreflexiblemultimethodcanapplyinevenmorescenarios).(ThisrelatedpostdescribeshowonecouldaccomplishthesameinPython3.4withoutalibrary.)Ihaven'tseenexamplesinthedocumentationforeitherofthesethatspecificallyshowsoverloading__init__asyouaskabout,butitappearsthatthesameprinciplesforoverloadinganymembermethodapply(asshownbelow). "Singledispatch"(availableinthestandardlibrary)requiresthattherebeatleastonepositionalparameterandthatthetypeofthefirstargumentbesufficienttodistinguishamongthepossibleoverloadedoptions.ForthespecificCheeseexample,thisdoesn'tholdsinceyouwantedrandomholeswhennoparametersweregiven,butmultidispatchdoessupporttheverysamesyntaxandcanbeusedaslongaseachmethodversioncanbedistinguishbasedonthenumberandtypeofallargumentstogether. Example Hereisanexampleofhowtouseeithermethod(someofthedetailsareinordertopleasemypywhichwasmygoalwhenIfirstputthistogether): fromfunctoolsimportsingledispatchmethodasoverload #orthefollowingmoreflexiblemethodafter`pipinstallmultimethod` #frommultimethodimportmultidispatchasoverload classMyClass: @overload#type:ignore[misc] def__init__(self,a:int=0,b:str='default'): self.a=a self.b=b @__init__.register def_from_str(self,b:str,a:int=0): self.__init__(a,b)#type:ignore[misc] def__repr__(self)->str: returnf"({self.a},{self.b})" print([ MyClass(1,"test"), MyClass("test",1), MyClass("test"), MyClass(1,b="test"), MyClass("test",a=1), MyClass("test"), MyClass(1), #MyClass(),#`multidispatch`versionhandlesthese3,too. #MyClass(a=1,b="test"), #MyClass(b="test",a=1), ]) Output: [(1,test),(1,test),(0,test),(1,test),(1,test),(0,test),(1,default)] Notes: Iwouldn'tusuallymakethealiascalledoverload,butithelpedmakethediffbetweenusingthetwomethodsjustamatterofwhichimportyouuse. The#type:ignore[misc]commentsarenotnecessarytorun,butIputthemintheretopleasemypywhichdoesn'tlikedecorating__init__norcalling__init__directly. Ifyouarenewtothedecoratorsyntax,realizethatputting@overloadbeforethedefinitionof__init__isjustsugarfor__init__=overload(theoriginaldefinitionof__init__).Inthiscase,overloadisaclasssotheresulting__init__isanobjectthathasa__call__methodsothatitlookslikeafunctionbutthatalsohasa.registermethodwhichisbeingcalledlatertoaddanotheroverloadedversionof__init__.Thisisabitmessy,butitpleasemypybecuasetherearenomethodnamesbeingdefinedtwice.Ifyoudon'tcareaboutmypyandareplanningtousetheexternallibraryanyway,multimethodalsohassimpleralternativewaysofspecifyingoverloadedversions. Defining__repr__issimplytheretomaketheprintedoutputmeaningful(youdon'tneeditingeneral). Noticethatmultidispatchisabletohandlethreeadditionalinputcombinationsthatdon'thaveanypositionalparameters. Share Improvethisanswer Follow editedJun10,2021at23:35 answeredJun10,2021at19:40 teichertteichert 3,34311goldbadge2626silverbadges3535bronzebadges 1 Thankyouforthisanswerandthereferencetomultimethodpackage.Insomesituationsmultipledispatchjustfeelssonatural.HavingworkedinJuliaforawhile,itissomethingImissinPython. – Erik Sep7,2021at12:23 Addacomment  |  10 Usenum_holes=Noneasadefault,instead.Thencheckforwhethernum_holesisNone,andifso,randomize.That'swhatIgenerallysee,anyway. Moreradicallydifferentconstructionmethodsmaywarrantaclassmethodthatreturnsaninstanceofcls. Share Improvethisanswer Follow answeredMar25,2009at17:03 DevinJeanpierreDevinJeanpierre 89.8k44goldbadges5555silverbadges7979bronzebadges 1 Is"classmethod"literal?Ordoyoumeanclassmethod? – PeterMortensen Jan6,2021at0:53 Addacomment  |  9 Thebestansweristheoneaboveaboutdefaultarguments,butIhadfunwritingthis,anditcertainlydoesfitthebillfor"multipleconstructors".Useatyourownrisk. Whataboutthenewmethod. "Typicalimplementationscreateanewinstanceoftheclassbyinvokingthesuperclass’snew()methodusingsuper(currentclass,cls).new(cls[,...])withappropriateargumentsandthenmodifyingthenewly-createdinstanceasnecessarybeforereturningit." Soyoucanhavethenewmethodmodifyyourclassdefinitionbyattachingtheappropriateconstructormethod. classCheese(object): def__new__(cls,*args,**kwargs): obj=super(Cheese,cls).__new__(cls) num_holes=kwargs.get('num_holes',random_holes()) ifnum_holes==0: cls.__init__=cls.foomethod else: cls.__init__=cls.barmethod returnobj deffoomethod(self,*args,**kwargs): print"foomethodcalledas__init__forCheese" defbarmethod(self,*args,**kwargs): print"barmethodcalledas__init__forCheese" if__name__=="__main__": parm=Cheese(num_holes=5) Share Improvethisanswer Follow editedMar25,2009at19:55 answeredMar25,2009at19:48 mluebkemluebke 8,27077goldbadges3434silverbadges3131bronzebadges 4 12 Thisisthesortofcodethatgivesmenightmaresaboutworkingindynamiclanguages--nottosaythatthere'sanythinginherentlywrongwithit,onlythatitviolatessomekeyassumptionsIwouldmakeaboutaclass. – Yes-thatJake. Mar30,2009at16:07 1 @javawizardWoulditbeeasytoexplaininacommentwhatmakesitnonthread-safe,orgiveapointersoIcanreadaboutitsomewhereelse? – Reti43 Dec14,2014at9:04 12 @Reti43Saytwothreadstrytocreatecheesesatthesametime,onewithCheese(0)andonewithCheese(1).It'spossiblethatthread1mightruncls.__init__=cls.foomethod,butthenthread2mightruncls.__init__=cls.barmethodbeforethread1getsanyfurther.Boththreadswillthenendupcallingbarmethod,whichisn'twhatyouwant. – javawizard Dec14,2014at9:23 Indeed,thereisnoreasontomodifythedefinitionoftheclassjusttohandlecreationofoneinstanceoftheclass. – chepner Jul26,2020at16:55 Addacomment  |  4 I'duseinheritance.Especiallyiftherearegoingtobemoredifferencesthannumberofholes.EspeciallyifGoudawillneedtohavedifferentsetofmembersthenParmesan. classGouda(Cheese): def__init__(self): super(Gouda).__init__(num_holes=10) classParmesan(Cheese): def__init__(self): super(Parmesan).__init__(num_holes=15) Share Improvethisanswer Follow answeredApr28,2015at12:33 MichelSamiaMichelSamia 4,06322goldbadges2222silverbadges2323bronzebadges 1 Inheritancemightbeappropriate,butit'sreallyanorthogonalissuetowhatisbeingasked. – chepner Jul26,2020at16:57 Addacomment  |  3 Sincemyinitialanswerwascriticisedonthebasisthatmyspecial-purposeconstructorsdidnotcallthe(unique)defaultconstructor,Iposthereamodifiedversionthathonoursthewishesthatallconstructorsshallcallthedefaultone: classCheese: def__init__(self,*args,_initialiser="_default_init",**kwargs): """Amulti-initialiser. """ getattr(self,_initialiser)(*args,**kwargs) def_default_init(self,...): """Auser-friendlysmartorgeneral-purposeinitialiser. """ ... def_init_parmesan(self,...): """AspecialinitialiserforParmesancheese. """ ... def_init_gouda(self,...): """AspecialinitialiserforGoudacheese. """ ... @classmethod defmake_parmesan(cls,*args,**kwargs): returncls(*args,**kwargs,_initialiser="_init_parmesan") @classmethod defmake_gouda(cls,*args,**kwargs): returncls(*args,**kwargs,_initialiser="_init_gouda") Share Improvethisanswer Follow editedMay29,2019at17:02 PiCTo 91511goldbadge1111silverbadges2323bronzebadges answeredFeb14,2019at14:11 AlexeyAlexey 3,61366goldbadges2929silverbadges4242bronzebadges 1 2 Theideaofaclassmethodistoseparatecreatingaspecialinstanceintotwoindependentpieces:first,youdefineageneric__init__thatcanhandleinitializingCheesewithouthavingtoknowaboutspecialkindsofcheeses.Second,youdefineaclassmethodthatgeneratestheappropriateargumentstothegeneric__init__forcertainspecialcases.Here,youarebasicallyreinventingpartsofinheritance. – chepner Jul26,2020at17:05 Addacomment  |  3 ThisishowIsolveditforaYearQuarterclassIhadtocreate.Icreatedan__init__whichisverytoleranttoawidevarietyofinput. Youuseitlikethis: >>>fromdatetimeimportdate >>>temp1=YearQuarter(year=2017,month=12) >>>printtemp1 2017-Q4 >>>temp2=YearQuarter(temp1) >>>printtemp2 2017-Q4 >>>temp3=YearQuarter((2017,6)) >>>printtemp3 2017-Q2 >>>temp4=YearQuarter(date(2017,1,18)) >>>printtemp4 2017-Q1 >>>temp5=YearQuarter(year=2017,quarter=3) >>>printtemp5 2017-Q3 Andthisishowthe__init__andtherestoftheclasslookslike: importdatetime classYearQuarter: def__init__(self,*args,**kwargs): iflen(args)==1: [x]=args ifisinstance(x,datetime.date): self._year=int(x.year) self._quarter=(int(x.month)+2)/3 elifisinstance(x,tuple): year,month=x self._year=int(year) month=int(month) if1<=month<=12: self._quarter=(month+2)/3 else: raiseValueError elifisinstance(x,YearQuarter): self._year=x._year self._quarter=x._quarter eliflen(args)==2: year,month=args self._year=int(year) month=int(month) if1<=month<=12: self._quarter=(month+2)/3 else: raiseValueError elifkwargs: self._year=int(kwargs["year"]) if"quarter"inkwargs: quarter=int(kwargs["quarter"]) if1<=quarter<=4: self._quarter=quarter else: raiseValueError elif"month"inkwargs: month=int(kwargs["month"]) if1<=month<=12: self._quarter=(month+2)/3 else: raiseValueError def__str__(self): return'{0}-Q{1}'.format(self._year,self._quarter) Share Improvethisanswer Follow editedJul27,2020at10:20 answeredJan18,2017at12:17 Elmex80sElmex80s 3,36811goldbadge1414silverbadges2323bronzebadges 7 IhaveusedthiseffectivelybutwithclassesofmyowninsteadofPythontypes.Given__init__(self,obj)Itestinside__init__withifstr(obj.__class__.__name__)=='NameOfMyClass':...elifetc.. – MikeO'Connor Dec30,2019at22:40 Thisreallyisn'tveryPythonic.__init__shouldtakeayearandaquarterdirectly,ratherthanasinglevalueofunknowntype.Aclassmethodfrom_datecanhandleextractingayearandquarterfromadatetime.datevalue,thencallingYearQuarter(y,q).Youcoulddefineasimilarclassmethodfrom_tuple,butthathardlyseemsworthdoingsinceyoucouldsimplycallYearQuarter(*t). – chepner Jul26,2020at16:59 @chepnerIgaveitahugeupdate.Pleasetellmewhatyouthink. – Elmex80s Jul27,2020at10:16 It'sstillamess(evenmoresothanbefore)ofspecialcases.__init__shouldn'tresponsibleforanalyzingeverypossiblesetofvaluesyoumightusetocreateaninstance.def__init__(self,year,quarter):self._year=year;self._quarter=quarter:that'sit(thoughmaybewithsomerangecheckingonquarter).Otherclassmethodshandlethejobofmappingadifferentargumentorargumentstoayearandaquarterthatcanbepassedto__init__. – chepner Jul27,2020at14:18 Forexample,from_year_monthtakesamonthm,mapsittoaquarterq,thencallsYearQuarter(y,q).from_dateextractstheyearandthemonthfromthedateinstance,thencallsYearQuarter._from_year_month.Norepetition,andeachmethodisresponsibleforonespecificwayofgeneratingayearandaquartertopassto__init__. – chepner Jul27,2020at14:34  |  Show2morecomments 1 classCheese: def__init__(self,*args,**kwargs): """Auser-friendlyinitialiserforthegeneral-purposeconstructor. """ ... def_init_parmesan(self,*args,**kwargs): """AspecialinitialiserforParmesancheese. """ ... def_init_gauda(self,*args,**kwargs): """AspecialinitialiserforGaudacheese. """ ... @classmethod defmake_parmesan(cls,*args,**kwargs): new=cls.__new__(cls) new._init_parmesan(*args,**kwargs) returnnew @classmethod defmake_gauda(cls,*args,**kwargs): new=cls.__new__(cls) new._init_gauda(*args,**kwargs) returnnew Share Improvethisanswer Follow answeredFeb25,2018at21:52 AlexeyAlexey 3,61366goldbadges2929silverbadges4242bronzebadges 11 3 No.ThisisutterlyunPythonic,it'slikeJavamasqueradingbehindPythonsyntax.Youwantonesingle__init__method,andtheotherclassmethodseithercallitas-is(cleanest)orhandlespecialinitializationactionsviaanyhelperclassmethodsandsettersyouneed(ideallynone). – smci Jul17,2018at23:18 1 Idonotwantasingle__init__methodwhenIhavemultipleconstructorswithdifferentinitialisationroutines.Idonotseewhysomeonewouldwantit."theotherclassmethodseithercallitas-is"--callwhat?The__init__method?Thatwouldbestrangetocall__init__explicitelyIMO. – Alexey Jul18,2018at8:35 2 Alexey,itisutterlyunPythonictohavemultipleconstructors,asinmultiple_init...methods(seeotheranswersonthisquestion.)Worsestill,inthiscaseyoudon'tevenneedto:youhaven'tshownhowthecodefor_init_parmesan,_init_goudadiffer,sothereiszeroreasonnottocommon-casethem.Anyway,thePythonicwaytodothatistosupplynon-defaultargsto*argsor**kwargs(e.g.Cheese(...,type='gouda'...),orifthatcan'thandleeverything,putthegeneralcodein__init__andtheless-commonly-usedcodeinaclassmethodmake_whatever...andhaveitcalsetters – smci Jul18,2018at21:42 "itisutterlyunPythonictohavemultipleconstructors"--theoriginalquestionisstill"Whatisaclean,pythonicwaytohavemultipleconstructorsinPython?".Ionlyshowedhowtohavethem,notwhyiwouldwantthem. – Alexey Jul19,2018at6:48 1 Evenwhenmultipleinitialisationroutinescanbeachievedwiththesingledefaultconstructorbysome(possiblyawkward)dispatchinside__init__,iftheroutinesarecompletelyindependent,iwillcallthem_init_from_foo,_init_from_bar,etc,andcallthemfrom__init__afterdispatchingbyisinstanceorbyothertests. – Alexey Jul19,2018at7:48  |  Show6morecomments 1 Idonotseeastraightforwardanswerwithanexampleyet.Theideaissimple: use__init__asthe"basic"constructoraspythononlyallowsone__init__method use@classmethodtocreateanyotherconstructorsandcallthebasicconstructor Hereisanewtry. classPerson: def__init__(self,name,age): self.name=name self.age=age @classmethod deffromBirthYear(cls,name,birthYear): returncls(name,date.today().year-birthYear) Usage: p=Person('tim',age=18) p=Person.fromBirthYear('tim',birthYear=2004) Share Improvethisanswer Follow editedMay6at19:46 answeredMay6at19:34 TimC.TimC. 6744bronzebadges Addacomment  |  Highlyactivequestion.Earn10reputation(notcountingtheassociationbonus)inordertoanswerthisquestion.Thereputationrequirementhelpsprotectthisquestionfromspamandnon-answeractivity. Nottheansweryou'relookingfor?Browseotherquestionstaggedpythonclassconstructororaskyourownquestion. TheOverflowBlog IspenttwoyearstryingtodowhatBackstagedoesforfree Aserialentrepreneurfinallyembracesopensource(Ep.486) FeaturedonMeta PlannedmaintenancescheduledforWednesday,21September,00:30-03:00UTC... RecentColorContrastChangesandAccessibilityUpdates Revieweroverboard!Orarequesttoimprovetheonboardingguidancefornew... ShouldIexplainotherpeople'scode-onlyanswers? Linked 288 IsitnotpossibletodefinemultipleconstructorsinPython? 6 OverloadingconstructorsinPython 1 Howtouse__init__methodinPython? 0 isthisfineformultipleconstructors? -1 Pythoncallclassfunctionwithoutrefferingclassname 0 CanIusetwoconstructormethodsinPython? -2 Whatisthepythonicwaytousemultipleconstructorsforaclass? 1 InitializePythonclassfromargumentsorsameclass 0 __init__methodthattakesmultiplearguments 405 Howtooverload__init__methodbasedonargumenttype? Seemorelinkedquestions Related 2237 WhatisthebestwaytogiveaC#auto-propertyaninitialvalue? 633 Howtoiterateoveralistinchunks 390 BestwaytodomultipleconstructorsinPHP 976 Peakdetectionina2Darray 1112 Whatisacross-platformwaytogetthehomedirectory? 300 Pythonfunctionoverloading 1482 CreatingasingletoninPython 1812 HowdoIsplitthedefinitionofalongstringovermultiplelines? 586 Mostpythonicwaytodeleteafilewhichmaynotexist HotNetworkQuestions Chessetiquette:Carlsenwithdrawingfromthetournament Coniferwithredfruit Wordsforrelativeorientationofsidesofdouble-sidedpaper? SelectiveCaesarCipher Rolejustbelowroot? Sci-fihorrorshortstoryaboutalienthatwantstobeeaten Notesnotaddinguptotimesignature,withweirdwhiteovalnote 110.15High-LegMarking IsitGoodPracticetoOnlyExposeInterfaces WhywasJWSTcancelledin2011? Somethingappearsvaluableorpreciousbutitisn't,symbolicallyequivalenttoPyrite? Howtoliterallytranslatethe由人类艺术家挥笔in志愿者普遍更喜欢的作品都是由人类艺术家挥笔完成的? Whyisthe-eoptionnotinthebashcommandmanual? Howtoproperlyacknowledgeanoldfamousmathematicianinmyarticle? Whyissendingtroopsdifferentfromsendingmilitaryequipment? Whatexactlyismeantbyisotropicandanisotropicwithwordvectors HasNASAreleasedanyJWSTimagesofTrappist-1?Ifnot,why? IsEPSGdefinedseparatelyforeachgeometrycolumn? WhenpastinginTerminal.app,`00~`ispastedatthestartand`01~`attheend Howtomakedefinedlabelsontopoftheedgeinagraphwithtikz? DoesNECrequirejunctionboxestobeaccessiblewithouttools? Howtopreventhumansfrombeingkilledbyaliendiseases? Combiningalistwithacertainindexofalist Whatisthisdiskettedrive? morehotquestions Questionfeed SubscribetoRSS Questionfeed TosubscribetothisRSSfeed,copyandpastethisURLintoyourRSSreader. lang-py Yourprivacy Byclicking“Acceptallcookies”,youagreeStackExchangecanstorecookiesonyourdeviceanddiscloseinformationinaccordancewithourCookiePolicy. Acceptallcookies Customizesettings  



請為這篇文章評分?