Coming off from learning Python Decorators we know that it is a method to wrap up a function with another function that acts as a wrapper and the function inside is the actual gift, decorators are basically modifiers of an existing function which adds functionality to it. 

Moving on to the property decorator, it works in a similar manner to normal decorators, the only difference being that it has enhanced functionality, it makes the use of getter and setter methods in Python easier when it comes to object-oriented programming. A traditional approach would be to make separate getter and setter methods but the @property decorator allows the user to invoke them implicitly in Python.

A @property decorator indirectly invokes the four basic parts of the property() function which are as follows:

fget Obtains the value of the attribute in question
fset Sets the value of the attribute in question
fdel Delete the value of the attribute in question
docContains the documentation of the attribute in question. 

Let’s make a code which portrays a simple decorator:

def stat1(func): #this is a closure

   def stat2(): #This inner function contains the actual "gift" of the decorator
       print("decorator")
       func() #The function is called, this will use the actual function we will provide to the new function object
   return stat2 #this returns the actual decorator function


def norm(): #this is the function which will be decorated
   print(" normal function or the gift ")


deco1 = stat1(norm) #Similar to a closure, we have defined a function object for the decorator
deco1() #Calling the decorator function

Now that we have seen how the decorator works, let’s see how to include a getter and setter function inside our functions:

class mul1: #This is a simple multiplier class that shows the working of a getter and setter function

   def __init__(self, x): #__init__ method, takes in the value from the setter function
       self.setx(x)

   def mul2(self): #The working function which takes the value from the getter function
       return self.getx() * 10

   def getx(self): #The getter function which obtains the value from the set function
       print("getting attribute")
       return self.x

   def setx(self, x1): #The set function which includes another attribute x1 relating to the original attribute of x
       print("Setting attribute")
       self.x = x1


runner = mul1(20) #invoking the class with a class object

print(runner.mul2()) #calling the working function with a child class call.

The above mentioned code simply depicts the working of a multiplier code using the getter and setter methods. The setter method obtains the value from the user and the getter method provides it to the working function. Each of the getter and setter methods includes a print statement to indicate when each of them is executed. 

Let’s see how the property() and @property decorators work:

class mul1:  # This is a simple multiplier class that shows the working of a getter and setter function

   def __init__(self, x=0):  # __init__ method, takes in the value from the setter function
       self.x = x

   def mul2(self):  # The working function which takes the value from the getter function
       return self.x * 10

   def getx(self):  # The getter function which obtains the value from the set function and the '_' represents a private attribute
       print("getting attribute")
       return self._x

   def setx(self, x1):  # The set function which includes another attribute x1 relating to the original attribute of x, the '_' represents a private attribute
       print("Setting attribute")
       self._x = x1

   x = property(getx, setx) #property() automatically invokes the getter and setter functions in the original working functions.


runner = mul1(20)  # invoking the class with a class object

print(runner.x)
print(runner.mul2())

The last print statement will invoke the getx() function twice, as every time a change occurs or a value is updated, the getx function will be invoked.

Let’s see how the @property decorator now works.

class mul1:  # This is a simple multiplier class that shows the working of a getter and setter function

   def __init__(self, x=0):  # __init__ method, takes in the value from the setter function
       self.x = x

   def mul2(self):  # The working function which takes the value from the getter function
       return self.x * 10

   @property # This indicates the start of the property decorator
   def x(self):  # Note that we don't use the get functions now, the @property decorator automatically recognizes this as getter
       print("getting attribute")
       return self._x

   @x.setter #This determines the attribute setter
   def x(self, x1):  # Note that we don't have a specific setter method as the @x.setter invokes it implicitly
       print("Setting attribute")
       self._x = x1




runner = mul1(20)  # invoking the class with a class object

print(runner.x)
print(runner.mul2())

Categorized in: