3. Properties vs. Getters and Setters | OOP - Python Course Eu
文章推薦指數: 80 %
Unfortunately, it is widespread belief that a proper Python class should encapsulate private attributes by using getters and setters. PythonTrainingCourses LivePythonclassesbyhighlyexperiencedinstructors: Instructor-ledtrainingcoursesbyBerndKlein InthisObjectOrientedProgrammingchapter IntrotoObjectOrientedProgramming ObjectOrientedProgramming Classvs.InstanceAttributes Propertiesvs.GettersandSetters ImplementingaCustomPropertyClass IntroductiontoDescriptors Inheritance MultipleInheritance MultipleInheritance:Example MagicMethods CallableInstancesofClasses InheritanceExample Slots:AvoidingDynamicallyCreatedAttributes PolynomialClass DynamicallyCreatingClasseswithtype RoadtoMetaclasses Metaclasses CountFunctioncallswiththehelpofaMetaclass The'ABC'ofAbstractBaseClasses ClassroomTrainingCourses ThiswebsitecontainsafreeandextensiveonlinetutorialbyBerndKlein,usingmaterialfromhisclassroomPythontrainingcourses. Ifyouareinterestedinaninstructor-ledclassroomtrainingcourse,havealookatthesePythonclasses: Instructor-ledtrainingcoursebyBerndKleinatBodenseo Image©kabliczech-Fotolia.com Pageauthor ThispagewaswrittenbyBerndKlein. BerndisanexperiencedcomputerscientistwithahistoryofworkingintheeducationmanagementindustryandisskilledinPython,Perl,ComputerScience,andC++.HehasaDipl.-Informatiker/MasterDegreefocusedinComputerSciencefromSaarlandUniversity. BerndKleinonFacebook BerndKleinonLinkedIn python-courseonFacebook PDFversion PDFversionofthissite HelpNeeded Thiswebsiteisfreeofannoyingads.Wewanttokeepitlikethis.Youcanhelpwithyourdonation: Theneedfordonations 3.Propertiesvs.GettersandSetters ByBerndKlein.Lastmodified:01Feb2022. Onthispage➤ Properties Getters(alsoknownas'accessors')andsetters(aka.'mutators')areusedinmanyobjectorientedprogramminglanguagestoensuretheprincipleofdataencapsulation.Dataencapsulation-aswehavelearntinourintroductiononObjectOrientedProgrammingofourtutorial-isseenasthebundlingofdatawiththemethodsthatoperateonthem.Thesemethodsareofcoursethegetterforretrievingthedataandthesetterforchangingthedata.Accordingtothisprinciple,theattributesofaclassaremadeprivatetohideandprotectthem. Unfortunately,itiswidespreadbeliefthataproperPythonclassshouldencapsulateprivateattributesbyusinggettersandsetters.Assoonasoneoftheseprogrammersintroducesanewattribute,heorshewillmakeitaprivatevariableandcreates"automatically"agetterandasetterforthisattribute.SuchprogrammersmayevenuseaneditororanIDE,whichautomaticallycreatesgettersandsettersforallprivateattributes.Thesetoolsevenwarntheprogrammerifsheorheusesapublicattribute!Javaprogrammerswillwrinkletheirbrows,screwuptheirnoses,orevenscreamwithhorrorwhentheyreadthefollowing:ThePythonicwaytointroduceattributesistomakethempublic. Wewillexplainthislater.First,wedemonstrateinthefollowingexample,howwecandesignaclassinaJavaesquewaywithgettersandsetterstoencapsulatetheprivateattributeself.__x: classP: def__init__(self,x): self.__x=x defget_x(self): returnself.__x defset_x(self,x): self.__x=x Wecanseeinthefollowingdemosessionhowtoworkwiththisclassandthemethods: frommutatorsimportP p1=P(42) p2=P(4711) p1.get_x() OUTPUT: 42 p1.set_x(47) p1.set_x(p1.get_x()+p2.get_x()) p1.get_x() OUTPUT: 4758 Whatdoyouthinkabouttheexpression"p1.set_x(p1.get_x()+p2.get_x())"?It'sugly,isn'tit?It'saloteasiertowriteanexpressionlikethefollowing,ifwehadapublicattributex: p1.x=p1.x+p2.x SuchanassignmentiseasiertowriteandabovealleasiertoreadthantheJavaesqueexpression. Let'srewritetheclassPinaPythonicway.Nogetter,nosetterandinsteadoftheprivateattributeself.__xweuseapublicone: classP: def__init__(self,x): self.x=x Beautiful,isn'tit?Justthreelinesofcode,ifwedon'tcounttheblankline! frompimportP p1=P(42) p2=P(4711) p1.x OUTPUT: 42 p1.x=47 p1.x=p1.x+p2.x p1.x OUTPUT: 4758 "But,but,but,but,but...",wecanhearthemhowlingandscreaming,"ButthereisNOdataENCAPSULATION!"Yes,inthiscasethereisnodataencapsulation.Wedon'tneeditinthiscase.Theonlythingget_xandset_xinourstartingexampledidwas"gettingthedatathrough"withoutdoinganythingadditionally. Butwhathappensifwewanttochangetheimplementationinthefuture?Thisisaseriousargument.Let'sassumewewanttochangetheimplementationlikethis:Theattributexcanhavevaluesbetween0and1000.Ifavaluelargerthan1000isassigned,xshouldbesetto1000.Correspondingly,xshouldbesetto0,ifthevalueislessthan0. ItiseasytochangeourfirstPclasstocoverthisproblem.Wechangetheset_xmethodaccordingly: classP: def__init__(self,x): self.set_x(x) defget_x(self): returnself.__x defset_x(self,x): ifx<0: self.__x=0 elifx>1000: self.__x=1000 else: self.__x=x ThefollowingPythonsessionshowsthatitworksthewaywewantittowork: frommutators1importP p1=P(1001) p1.get_x() OUTPUT: 1000 p2=P(15) p2.get_x() OUTPUT: 15 p3=P(-1) p3.get_x() OUTPUT: 0 Butthereisacatch:Let'sassumewedesignedourclasswiththepublicattributeandnomethods: classP2: def__init__(self,x): self.x=x Peoplehavealreadyuseditalotandtheyhavewrittencodelikethis: p1=P2(42) p1.x=1001 p1.x OUTPUT: 1001 IfwewouldchangeP2nowinthewayoftheclassP,ournewclasswouldbreaktheinterface,becausetheattributexwillnotbeavailableanymore.That'swhyinJavae.g.peoplearerecommendedtouseonlyprivateattributeswithgettersandsetters,sothattheycanchangetheimplementationwithouthavingtochangetheinterface. ButPythonoffersasolutiontothisproblem.Thesolutioniscalledproperties! Theclasswithapropertylookslikethis: classP: def__init__(self,x): self.x=x @property defx(self): returnself.__x @x.setter defx(self,x): ifx<0: self.__x=0 elifx>1000: self.__x=1000 else: self.__x=x Amethodwhichisusedforgettingavalueisdecoratedwith"@property",i.e.weputthislinedirectlyinfrontoftheheader.Themethodwhichhastofunctionasthesetterisdecoratedwith"@x.setter".Ifthefunctionhadbeencalled"f",wewouldhavetodecorateitwith"@f.setter".Twothingsarenoteworthy:Wejustputthecodeline"self.x=x"inthe__init__methodandthepropertymethodxisusedtocheckthelimitsofthevalues.Thesecondinterestingthingisthatwewrote"two"methodswiththesamenameandadifferentnumberofparameters"defx(self)"and"defx(self,x)".Wehavelearnedinapreviouschapterofourcoursethatthisisnotpossible.Itworkshereduetothedecorating: fromp2importP p1=P(1001) p1.x OUTPUT: 1000 p1.x=-12 p1.x OUTPUT: 0 Alternatively,wecouldhaveusedadifferentsyntaxwithoutdecoratorstodefinetheproperty.Asyoucansee,thecodeisdefinitelylesselegantandwehavetomakesurethatweusethegetterfunctioninthe__init__methodagain: classP: def__init__(self,x): self.set_x(x) defget_x(self): returnself.__x defset_x(self,x): ifx<0: self.__x=0 elifx>1000: self.__x=1000 else: self.__x=x x=property(get_x,set_x) Thereisstillanotherprobleminthemostrecentversion.Wehavenowtwowaystoaccessorchangethevalueofx:Eitherbyusing"p1.x=42"orby"p1.set_x(42)".ThiswayweareviolatingoneofthefundamentalsofPython:"Thereshouldbeone--andpreferablyonlyone--obviouswaytodoit."(seeZenofPython) Wecaneasilyfixthisproblembyturningthegetterandthesettermethodsintoprivatemethods,whichcan'tbeaccessedanymorebytheusersofourclassP: classP: def__init__(self,x): self.__set_x(x) def__get_x(self): returnself.__x def__set_x(self,x): ifx<0: self.__x=0 elifx>1000: self.__x=1000 else: self.__x=x x=property(__get_x,__set_x) Eventhoughwefixedthisproblembyusingaprivategetterandsetter,theversionwiththedecorator"@property"isthePythonicwaytodoit! Fromwhatwehavewrittensofar,andwhatcanbeseeninotherbooksandtutorialsaswell,wecouldeasilygettheimpressionthatthereisaone-to-oneconnectionbetweenproperties(ormutatormethods)andtheattributes,i.e.thateachattributehasorshouldhaveitsownproperty(orgetter-setter-pair)andtheotherwayaround.EveninotherobjectorientedlanguagesthanPython,it'susuallynotagoodideatoimplementaclasslikethat.Themainreasonisthatmanyattributesareonlyinternallyneededandcreatinginterfacesfortheuseroftheclassincreasesunnecessarilytheusabilityoftheclass.Thepossibleuserofaclassshouldn'tbe"drowned"withumpteen-ofmainlyunnecessary-methodsorproperties! Thefollowingexampleshowsaclass,whichhasinternalattributes,whichcan'tbeaccessedfromoutside.Thesearetheprivateattributesself.__potential_physicalandself.__potential_psychic.Furthermoreweshowthatapropertycanbededucedfromthevaluesofmorethanoneattribute.Theproperty"condition"ofourexamplereturnstheconditionoftherobotinadescriptivestring.Theconditiondependsonthesumofthevaluesofthepsychicandthephysicalconditionsoftherobot. classRobot: def__init__(self,name,build_year,lk=0.5,lp=0.5): self.name=name self.build_year=build_year self.__potential_physical=lk self.__potential_psychic=lp @property defcondition(self): s=self.__potential_physical+self.__potential_psychic ifs<=-1: return"Ifeelmiserable!" elifs<=0: return"Ifeelbad!" elifs<=0.5: return"Couldbeworse!" elifs<=1: return"Seemstobeokay!" else: return"Great!" if__name__=="__main__": x=Robot("Marvin",1979,0.2,0.4) y=Robot("Caliban",1993,-0.4,0.3) print(x.condition) print(y.condition) OUTPUT: Seemstobeokay! Ifeelbad! LivePythontraining Enjoyingthispage?WeofferlivePythontrainingcoursescoveringthecontentofthissite. See:LivePythoncoursesoverview Enrolhere PublicinsteadofPrivateAttributes Let'ssummarizetheusageofprivateandpublicattributes,gettersandsetters,andproperties:Let'sassumethatwearedesigninganewclassandweponderingaboutaninstanceorclassattribute"OurAtt",whichweneedforthedesignofourclass.Wehavetoobservethefollowingissues: Willthevalueof"OurAtt"beneededbythepossibleusersofourclass? Ifnot,wecanorshouldmakeitaprivateattribute. Ifithastobeaccessed,wemakeitaccessibleasapublicattribute Wewilldefineitasaprivateattributewiththecorrespondingproperty,ifandonlyifwehavetodosomechecksortransformationofthedata.(Asanexample,youcanhavealookagainatourclassP,wheretheattributehastobeintheintervalbetween0and1000,whichisensuredbytheproperty"x") Alternatively,youcoulduseagetterandasetter,butusingapropertyisthePythonicwaytodealwithit! Let'sassumewedefined"OurAtt"asapublicattribute.Ourclasshasbeensuccessfullyusedbyotherusersforquiteawhile. classOurClass: def__init__(self,a): self.OurAtt=a x=OurClass(10) print(x.OurAtt) OUTPUT: 10 NowcomesthepointwhichfrightenssometraditionalOOPistasoutoftheirwits:Imagine"OurAtt"hasbeenusedasaninteger.Now,ourclasshastoensurethat"OurAtt"hastobeavaluebetween0and1000?Withoutproperty,thisisreallyahorriblescenario!Duetopropertiesit'seasy:Wecreateapropertyversionof"OurAtt". classOurClass: def__init__(self,a): self.OurAtt=a @property defOurAtt(self): returnself.__OurAtt @OurAtt.setter defOurAtt(self,val): ifval<0: self.__OurAtt=0 elifval>1000: self.__OurAtt=1000 else: self.__OurAtt=val x=OurClass(10) print(x.OurAtt) OUTPUT: 10 Thisisgreat,isn'tit?Youcanstartwiththesimplestimplementationimaginable,andyouarefreetolatermigratetoapropertyversionwithouthavingtochangetheinterface!Sopropertiesarenotjustareplacementforgettersandsetters! Somethingelseyoumighthavealreadynoticed:Fortheusersofaclass,propertiesaresyntacticallyidenticaltoordinaryattributes. LivePythontraining Enjoyingthispage?WeofferlivePythontrainingcoursescoveringthecontentofthissite. See:LivePythoncoursesoverview UpcomingonlineCourses IntensiveAdvancedCourse 17Oct2022to21Oct2022 ObjectOrientedProgrammingwithPython 19Oct2022to21Oct2022 Enrolhere Onthispage
延伸文章資訊
- 1[Python] setter 和getter. 從鋼彈學python 第一彈 - Medium
從鋼彈學python 第一彈. 在物件導向程式裡面,封裝是個很基本的要素.不讓外部使用者直接碰到物件的內容,而只能透過方法來修改或取用內部的屬性.
- 2Python Property vs. Getters & Setters - DataCamp
Getters: These are the methods used in Object-Oriented Programming (OOPS) which helps to access t...
- 3Python 装饰器之Property: Setter 和Getter
Unfortunately, it is widespread belief that a proper Python class should encapsulate private attr...
- 4Python 慣用語- 14 用property 取代getters, setters
寫Java 的人習慣寫一堆getX() 以及setX(),這在Python 中是不被鼓勵的,pythonic 方式是直接存取attribute ,而當你需要進一步控制時,可以使用pr...
- 5Getter and Setter in Python - Tutorialspoint
As the name suggests, getters are the methods which help access the private attributes or get the...