@property
Decorator in Python
@property is a built-in decorator in python language which is used to make functions like getters and setters in a class behave as class properties.
To understand the concept in a better way, let's take an example.
Below we have a class Student
, which has 3 properties, namely fname
, lname
and fullname
, where fullname is a concatenation of the first two properties.
And we have a function too, the email()
function to generate an email address for the student using its first and last names.
class Student:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
self.fullname = self.fname +' '+ self.lname
# generate email using first and last name
def email(self):
return '{}.{}@studytonight.com'.format(self.fname, self.lname)
Let's now create a few objects and call the function email()
and doing so try a few things,
# student s1
s1 = Student('Tony', 'Stark')
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
# now updating the s1 object's first name
s1.first = 'Steve'
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
Fullname of s1 is Tony Stark
And email address = Tony.Stark@studytonight.com
Fullname of s1 is Tony Stark
And email address = Steve.Stark@studytonight.com
Now referring to the above code, in class Student
, fname(first name) and lname(last name) are the simple attributes(which are not derived from any other attributes) while fullname and email()
are the derived attributes.
Here fullname is declared as a variable and email
is declared as a function.
Now coming to the output, we can see that for a student when the first name is changed then email gets changed automatically but the fullname doesn't change because email()
is a function which is called at the time when we want the email to be returned while fullname
is set at the time of initialisation of the object.
If you want to fix the problem for fullname, it can be done by making a function similar to
email to get fullname as well. But, this will result in the overhead of changing
all the access made to fullname in all the python files which have used the Student
class.
Also, creating a function is not the pythonic way of solving this problem. But then what is?
Using @property
Decorator
Now we will use the @property
in the above program to solve the problem of fullname(which we saw above) by creating a getter function for fullname which will allow it to be used as a simple variable and will always return the updated value of fullname property.
Let's see how we can do so,
class Student:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
@property
def fullname(self):
return self.fname +' '+ self.lname
# generate email using first and last name
def email(self):
return '{}.{}@studytonight.com'.format(self.fname, self.lname)
s1 = Student('Tony', 'Stark')
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
# now updating the s1 object's first name
s1.first = 'Steve'
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
Output:-
Fullname of s1 is Tony Stark
And email address = Tony.Stark@studytonight.com
Fullname of s1 is Steve Stark
And email address = Steve.Stark@studytonight.com
In the above example, @property
decorator is used on the function named as fullname()
. Now, this function will work as a fullname attribute and also can work as a getter because of the @property
decorator attached to it.
Defining setter
and deleter
methods with @property
Decorator
Similar to the getter method(we have defined in the previous example) we can also define setter and deleter methods for any attribute which is using @property
in Python.
The setter method will set the value of the attribute and the deleter method will delete the attribute from the memory.
Let's implement a setter and deleter method for our fullname attribute. For defining a setter and deleter method, for an attribute with @property
decorator set on its getter method, we use a special syntax, where we put @ATTRIBUTE_NAME.setter
and @ATTRIBUTE_NAME.deleter
decorator on function with name same as the ATTRIBUTE_NAME. This is shown in the below example,
class Student:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
@property
def fullname(self):
return self.fname +' '+ self.lname
#setter for the fullname
@fullname.setter
def fullname(self, name):
# split the name from space
fname, lname = name.split(" ")
self.first = fname
self.last = lname
#deleter for fullname
@fullname.deleter
def fullname(self):
self.first = None
self.last = None
print('Deleted the fullname')
# generate email using first and last name
def email(self):
return '{}.{}@studytonight.com'.format(self.fname, self.lname)
s1 = Student('Tony', 'Stark')
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
# now updating the s1 object's first name
s1.first = 'Steve'
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
#setting new value of fullname
s1.fullname = 'Berry Banner'
print('New Fullname of s1 is ', s1.fullname)
#deleting the fullname
del s1.fullname
Fullname of s1 is Tony Stark
And email address = Tony.Stark@studytonight.com
Fullname of s1 is Steve Stark
And email address = Steve.Stark@studytonight.com
New fullname of s1 is Berry Banner
Deleted the fullname.
In the above example, we have successfully created getter, setter and deleter using the @property
decorator.
The simple syntax for creating setter and deleter is:
@attribute_name.(setter/getter/deleter)
The property()
function
Instead of using @property
decorator, we can use the property()
function in python to create getters, setters and deleters in python.
Syntax: property(fget, fset, fdel, doc)
Where the parameters means:
fget()
: used to get the value of attribute
fset()
: used to set the value of atrribute
fdel()
: used to delete the attribute value
doc()
: string that contains the documentation (docstring) for the attribute
return: It returns a property attribute from the given getter, setter and deleter.
Below, is an example showing the use of the property()
function for the same Student
class with the same functions defined as getter, setter and deleter.
class Student:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
self.fullname = fname+' '+lname
def fullname_getter(self):
return self.fname +' '+ self.lname
def fullname_setter(self,name):
firstname, lastname = name.split()
self.fname = firstname
self.lname = lastname
def fullname_deleter(self):
self.fname = None
self.lname = None
print('Deleted the fullname.')
def email(self):
return '{}.{}@email.com'.format(self.fname, self.lname)
fullname = property()
fullname = fullname.getter(fullname_getter)
fullname = fullname.setter(fullname_setter)
fullname = fullname.deleter(fullname_deleter)
# this can be done in a single line too
# fullname = property(fullname_getter, fullname_setter, fullname_deleter)
s1 = Student('Tony', 'Stark')
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
# now updating the s1 object's first name
s1.first = 'Steve'
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
#setting new value of fullname
s1.fullname = 'Berry Banner'
print('New Fullname of s1 is ', s1.fullname)
#deleting the fullname
del s1.fullname
Fullname of s1 is Tony Stark
And email address = Tony.Stark@studytonight.com
Fullname of s1 is Steve Stark
And email address = Steve.Stark@studytonight.com
New fullname of s1 is Berry Banner
Deleted the fullname.
In this example, either we can use property()
function and specify all the getter, setter and deleter functions as parameters in one go using the syntax described above or in multiple code lines.