A decorator function is basically a function that adds new functionality to a function that is passed as argument. Using a decorator function is ...
Search
Submityoursearchquery
Forum
Donate
Learntocode—free3,000-hourcurriculum
EstefaniaCassingenaNavone
🔹MeetPropertiesWelcome!Inthisarticle,youwilllearnhowtoworkwiththe@propertydecoratorinPython.Youwilllearn:TheadvantagesofworkingwithpropertiesinPython.Thebasicsofdecoratorfunctions:[email protected]@propertytodefinegetters,setters,anddeleters.1️⃣AdvantagesofPropertiesinPythonLet'sstartwithalittlebitofcontext.WhywouldyouusepropertiesinPython?Propertiescanbeconsideredthe"Pythonic"wayofworkingwithattributesbecause:Thesyntaxusedtodefinepropertiesisveryconciseandreadable.Youcanaccessinstanceattributesexactlyasiftheywerepublicattributeswhileusingthe"magic"ofintermediaries(gettersandsetters)tovalidatenewvaluesandtoavoidaccessingormodifyingthedatadirectly.Byusing@property,youcan"reuse"thenameofapropertytoavoidcreatingnewnamesforthegetters,setters,anddeleters.Theseadvantagesmakepropertiesareallyawesometooltohelpyouwritemoreconciseandreadablecode.?2️⃣IntrotoDecoratorsAdecoratorfunctionisbasicallyafunctionthataddsnewfunctionalitytoafunctionthatispassedasargument.Usingadecoratorfunctionislikeaddingchocolatesprinklestoanicecream?.Itletsusaddnewfunctionalitytoanexistingfunctionwithoutmodifyingit.Intheexamplebelow,youcanseewhatatypicaldecoratorfunctionlookslikeinPython:defdecorator(f):
defnew_function():
print("ExtraFunctionality")
f()
returnnew_function
@decorator
definitial_function():
print("InitialFunctionality")
initial_function()Let'sanalyzetheseelementsindetail:Wefirstfindthedecoratorfunctiondefdecorator(f)(thesprinkles✨)thattakesafunctionfasanargument.defdecorator(f):
defnew_function():
print("ExtraFunctionality")
f()
returnnew_functionThisdecoratorfunctionhasannestedfunction,new_function.Noticehowfiscalledinsidenew_functiontoachievethesamefunctionalitywhileaddingnewfunctionalitybeforethefunctioncall(wecouldalsoaddnewfunctionalityafterthefunctioncall).Thedecoratorfunctionitselfreturnsthenestedfunctionnew_function.Then(below),wefindthefunctionthatwillbedecorated(theicecream?)initial_function.Noticetheverypeculiarsyntax(@decorator)abovethefunctionheader.@decorator
definitial_function():
print("InitialFunctionality")
initial_function()Ifwerunthecode,weseethisoutput:ExtraFunctionality
InitialFunctionalityNoticehowthedecoratorfunctionrunsevenifweareonlycallinginitial_function().Thisisthemagicofadding@decorator?.💡Note:Ingeneral,wewouldwrite@,replacingthenameofthedecoratorfunctionafterthe@symbol.Iknowyoumaybeasking:howisthisrelatedtothe@property?The@propertyisabuilt-indecoratorfortheproperty()functioninPython.Itisusedtogive"special"functionalitytocertainmethodstomakethemactasgetters,setters,ordeleterswhenwedefinepropertiesinaclass.Nowthatyouarefamiliarwithdecorators,let'sseearealscenariooftheuseof@property!🔸Real-WorldScenario:@propertyLet'ssaythatthisclassispartofyourprogram.YouaremodelingahousewithaHouseclass(atthemoment,theclassonlyhasapriceinstanceattributedefined):classHouse:
def__init__(self,price):
self.price=priceThisinstanceattributeispublicbecauseitsnamedoesn'thavealeadingunderscore.Sincetheattributeiscurrentlypublic,itisverylikelythatyouandotherdevelopersinyourteamaccessedandmodifiedtheattributedirectlyinotherpartsoftheprogramusingdotnotation,likethis:#Accessvalue
obj.price
#Modifyvalue
obj.price=40000💡Tip:objrepresentsavariablethatreferencesaninstanceofHouse.Sofareverythingisworkinggreat,right?Butlet'ssaythatyouareaskedtomakethisattributeprotected(non-public)andvalidatethenewvaluebeforeassigningit.Specifically,youneedtocheckifthevalueisapositivefloat.Howwouldyoudothat?Let'ssee.ChangingyourCodeAtthispoint,ifyoudecidetoaddgettersandsetters,youandyourteamwillprobablypanic?.Thisisbecauseeachlineofcodethataccessesormodifiesthevalueoftheattributewillhavetobemodifiedtocallthegetterorsetter,respectively.Otherwise,thecodewillbreak⚠️.#Changedfromobj.price
obj.get_price()
#Changedfromobj.price=40000
obj.set_price(40000)But...Propertiescometotherescue!With@property,youandyourteamwillnotneedtomodifyanyofthoselinesbecauseyouwillabletoaddgettersandsetters"behindthescenes"withoutaffectingthesyntaxthatyouusedtoaccessormodifytheattributewhenitwaspublic.Awesome,right? 🔹@property:SyntaxandLogicIfyoudecidetouse@property,yourclasswilllookliketheexamplebelow:classHouse:
def__init__(self,price):
self._price=price
@property
defprice(self):
returnself._price
@price.setter
defprice(self,new_price):
ifnew_price>0andisinstance(new_price,float):
self._price=new_price
else:
print("Pleaseenteravalidprice")
@price.deleter
defprice(self):
delself._priceSpecifically,youcandefinethreemethodsforaproperty:Agetter-toaccessthevalueoftheattribute.Asetter-tosetthevalueoftheattribute.Adeleter-todeletetheinstanceattribute.Priceisnow"Protected"Pleasenotethatthepriceattributeisnowconsidered"protected"becauseweaddedaleadingunderscoretoitsnameinself._price:self._price=priceInPython,byconvention,whenyouaddaleadingunderscoretoaname,youaretellingotherdevelopersthatitshouldnotbeaccessedormodifieddirectlyoutsideoftheclass.Itshouldonlybeaccessedthroughintermediaries(gettersandsetters)iftheyareavailable.🔸GetterHerewehavethegettermethod:@property
defprice(self):
returnself._priceNoticethesyntax:@property-Usedtoindicatethatwearegoingtodefineaproperty.Noticehowthisimmediatelyimprovesreadabilitybecausewecanclearlyseethepurposeofthismethod.defprice(self)-Theheader.Noticehowthegetterisnamedexactlylikethepropertythatwearedefining:price.Thisisthenamethatwewillusetoaccessandmodifytheattributeoutsideoftheclass.Themethodonlytakesoneformalparameter,self,whichisareferencetotheinstance.returnself._price-Thislineisexactlywhatyouwouldexpectinaregulargetter.Thevalueoftheprotectedattributeisreturned.Hereisanexampleoftheuseofthegettermethod:>>>house=House(50000.0)#Createinstance
>>>house.price#Accessvalue
50000.0Noticehowweaccessthepriceattributeasifitwereapublicattribute.Wearenotchangingthesyntaxatall,butweareactuallyusingthegetterasanintermediarytoavoidaccessingthedatadirectly.🔹SetterNowwehavethesettermethod:@price.setter
defprice(self,new_price):
ifnew_price>0andisinstance(new_price,float):
self._price=new_price
else:
print("Pleaseenteravalidprice")Noticethesyntax:@price.setter-Usedtoindicatethatthisisthesettermethodforthepriceproperty.Noticethatwearenotusing@property.setter,weareusing@price.setter.Thenameofthepropertyisincludedbefore.setter.defprice(self,new_price):-Theheaderandthelistofparameters.Noticehowthenameofthepropertyisusedasthenameofthesetter.Wealsohaveasecondformalparameter(new_price),whichisthenewvaluethatwillbeassignedtothepriceattribute(ifitisvalid).Finally,wehavethebodyofthesetterwherewevalidatetheargumenttocheckifitisapositivefloatandthen,iftheargumentisvalid,weupdatethevalueoftheattribute.Ifthevalueisnotvalid,adescriptivemessageisprinted.Youcanchoosehowtohandleinvalidvaluesaccordingtheneedsofyourprogram.Thisisanexampleoftheuseofthesettermethodwith@property:>>>house=House(50000.0)#Createinstance
>>>house.price=45000.0#Updatevalue
>>>house.price#Accessvalue
45000.0Noticehowwearenotchangingthesyntax,butnowweareusinganintermediary(thesetter)tovalidatetheargumentbeforeassigningit.Thenewvalue(45000.0)ispassedasanargumenttothesetter:house.price=45000.0Ifwetrytoassignaninvalidvalue,weseethedescriptivemessage.Wecanalsocheckthatthevaluewasnotupdated:>>>house=House(50000.0)
>>>house.price=-50
Pleaseenteravalidprice
>>>house.price
50000.0💡Tip:Thisprovesthatthesettermethodisworkingasanintermediary.Itisbeingcalled"behindthescenes"whenwetrytoupdatethevalue,sothedescriptivemessageisdisplayedwhenthevalueisnotvalid.🔸DeleterFinally,wehavethedeletermethod:@price.deleter
defprice(self):
delself._priceNoticethesyntax:@price.deleter-Usedtoindicatethatthisisthedeletermethodforthepriceproperty.Noticethatthislineisverysimilarto@price.setter,butnowwearedefiningthedeletermethod,[email protected](self):-Theheader.Thismethodonlyhasoneformalparameterdefined,self.delself._price-Thebody,wherewedeletetheinstanceattribute.💡Tip:Noticethatthenameofthepropertyis"reused"forallthreemethods.Thisisanexampleoftheuseofthedeletermethodwith@property:#Createinstance
>>>house=House(50000.0)
#Theinstanceattributeexists
>>>house.price
50000.0
#Deletetheinstanceattribute
>>>delhouse.price
#Theinstanceattributedoesn'texist
>>>house.price
Traceback(mostrecentcalllast):
File"",line1,in
house.price
File"",line8,inprice
returnself._price
AttributeError:'House'objecthasnoattribute'_price'Theinstanceattributewasdeletedsuccessfully?.Whenwetrytoaccessitagain,anerroristhrownbecausetheattributedoesn'texistanymore.🔹SomefinalTipsYoudon'tnecessarilyhavetodefineallthreemethodsforeveryproperty.Youcandefineread-onlypropertiesbyonlyincludingagettermethod.Youcouldalsochoosetodefineagetterandsetterwithoutadeleter.Ifyouthinkthatanattributeshouldonlybesetwhentheinstanceiscreatedorthatitshouldonlybemodifiedinternallywithintheclass,youcanomitthesetter.Youcanchoosewhichmethodstoincludedependingonthecontextthatyouareworkingwith.🔸InSummaryYoucandefinepropertieswiththe@propertysyntax,whichismorecompactandreadable.@propertycanbeconsideredthe"pythonic"wayofdefininggetters,setters,anddeleters.Bydefiningproperties,youcanchangetheinternalimplementationofaclasswithoutaffectingtheprogram,soyoucanaddgetters,setters,anddeletersthatactasintermediaries"behindthescenes"toavoidaccessingormodifyingthedatadirectly.Ireallyhopeyoulikedmyarticleandfoundithelpful.TolearnmoreaboutPropertiesandObjectOrientedProgramminginPython,checkoutmyonlinecourse,whichincludes6+hoursofvideolectures,codingexercises,andminiprojects.
EstefaniaCassingenaNavone
I'madeveloper,writer,[email protected]ñolYouTubechannel.
Ifyoureadthisfar,tweettotheauthortoshowthemyoucare.Tweetathanks
Learntocodeforfree.freeCodeCamp'sopensourcecurriculumhashelpedmorethan40,000peoplegetjobsasdevelopers.Getstarted