Signup/Sign In

@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.