@property in Python.
Tags: python, programming, todayilearned, tutorial
Published: 2021-01-14 16:27:53

`@property` is a popular keyword in python. In this post you'll learn how can we use it to write more pythonic code and refactor any non pythonic code we had. 

<hr>

Let's consider an hypothetical number class which only allows numbers that are greater than 23 and less than 5. A typical OOPs program for it would look like this:

```python
#python3.8
class HypotheticalNumber():

    def __init__(self, num=0):
        self.set_num(num) 

    def get_num(self):
        return self.num # notice public scope

    def set_num(self, num):
        if(num > 23 or num < 5):
            self.num = num
        else:
            self.num = 0

some_number = HypotheticalNumber(4)
print(some_number.get_num()) #4
print(some_number.num) #4
some_number.set_num(5) # sets to 0
some_number.num = 5 # sets to 5
```
As we can see, the above implementation has some major holes in it. Not only we're able to access our hypothetical number by simply referring to `some_number.num` directly, we can also change it by direct access and break the core rule that our class is based upon, i.e. assigning a value equal to 5.

<hr>

## There's a pythonic way to do it.

`@property` is a decorator that handles getting, setting and deleting of class variables, the way it was meant to be in Python. A pythonic program for the above scenario would look like:
```python
class HypotheticalNumber():

    def __init__(self, num=0):
        self.num = num

    @property
    def num(self):
        return self.__num
    
    @num.setter
    def num(self, num):
        if(num > 23 or num < 5):
            self.__num = num
        else:
            self.__num = 0
    
    @num.deleter
    def num(self):
        del self.__num

some_number = HypotheticalNumber(4)
print(some_number.num) #4
some_number.num = 5 # sets to 0
``` 
Let's take it step by step.
1. `@property` is used to create a getter like function which has the same name as the class variable itself.
2. `@num.setter` is used to create a setter like function which defines what to do while setting the variable.
3. `@num.deleter` is used to create a deleter like function which defines what to do while deleting the varible.
4. Notice that all the functions have same name. It is necessary for the program to work.

<hr>

## What if my project contains code with getter and setter methods instead of property?
Well, you can always rewrite the code, or, there's another way to refactor it. It might save some time for you. Instead of adding `@property` as a decorator, we can just add the getter and setter methods to the `property` function.

```python
#python3.8
class HypotheticalNumber():

    def __init__(self, num=0):
        self.set_num(num) 

    def get_num(self):
        return self.__num # notice dunder

    def set_num(self, num):
        if(num > 23 or num < 5):
            self.__num = num
        else:
            self.__num = 0

    num = property(get_num, set_num)

some_number = HypotheticalNumber(4)
print(some_number.get_num()) #4
print(some_number.num) #4
some_number.set_num(5) # sets to 0
some_number.num = 5 # sets to 0
```
As you can see, we just needed to change the variables and add a special line 
`num = property(get_num, set_num)`
that secured the holes we had in our initial code and saved us a lot of time!