What is the use of Python's property attribute?

Get into the habit of writing together! This is the 9th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the event details .

The concept of Python dynamic attributes may be asked in interviews, and it is also very practical in projects, but it will not be mentioned in general programming tutorials, so you can learn it.

Let's start with a simple example. Create a Student class, and I want to get some information about each student, including name, grades, etc., through an instance. The grade won't be available until the exam is over, so it won't be assigned a value when instantiated.

  
class Student:
    def __init__(self, name):
        self.name = name
        self.score = None

mike = Student('mike')
复制代码

After the exam, prepare to rate Mike:

  
mike.score = 999
复制代码

Here, the teacher accidentally typed an extra 9. Generally speaking, the score is 100 points. 999 is an illegal data and should not be successfully assigned. When there are more students, teachers will make more mistakes in scoring, so we must find a way to modify the program to limit the value of score to 0-100 points.

limit value

We define a method, if the input is not an integer of 0-100, let the program report an error, the data is legal, and we modify the score attribute successfully.

  
def set_score(self, new_score):
    if not isinstance(new_score, int):
        raise ValueError('score must be int')

    if 0 <= new_score <= 100:
        self.score = new_score
        return self.score
    else:
        raise ValueError('score invalid')
复制代码

In this way, we use self.score to get it every time we need to get the score, and call the function to modify it when we modify the score:

  
mike.set_score(999)
复制代码

An error will be reported after the call, because 999 is illegal data. Note that at this time I can still use self.score to set, and no error is reported:

  
self.score = 999
复制代码

This obviously doesn't work. So we need to provide a mechanism to turn score into a private property that cannot be accessed from the outside. Unfortunately, python's private properties are pseudo-private. Usually we call attributes _starting with a private attribute, but this is just a protocol and regulation. If you see attributes starting with an underscore, don't access them. You can access it if you insist, but python will not ban it.

Use @property instead.

Although the above method implements the function, it changes the way the attribute is used. It is usually used like this:

  
# 获取属性
a = mike.score
# 设置属性
mike.score = 99

@property
def score(self):
    return self._score

@score.setter
def score(self, new_score):
    if not isinstance(new_score, int):
        raise ValueError('score must be int')

        if 0 <= new_score <= 100:
            self._score = new_score
            return self._score
        else:
            raise ValueError('score invalid')
复制代码

Benefits of Dynamic Properties

  • The calling method is unified. The way self.score = 99 , not the way the function call.
  • _scoreWe will not use it directly. You can use it, but not recommended.
  • If we have a property that can only be read, just comment out the setter part.

Now let's complete the class, adding the birth and age properties:

  
from datetime import datetime

class Student:
    def __init__(self, name, birth=1920):
        self.name = name
        self._score = None
        self.birth = birth
        self.age = datetime.now().year - self.birth


mike = Student('mike')
print(mike.birth)
print(mike.age)
复制代码
  • Birth and age can be calculated from one and the other. There is a data redundancy problem.

  • The age property is problematic like this. When mike is initialized, age has already been calculated. If I access the age property next year, it will be a wrong value. This can be verified by setting age to the current number of seconds:

      
    self.age = datetime.now().second
    
    mike = Student('mike')
    time.sleep(5)
    print(mike.age)
    print(datetime.now().second)
    复制代码

Dynamic display

  
@property
def age(self):
    return datetime.now().year - self.birth
复制代码

Note, don't set @age.setter here, because it changes dynamically, and your modification will cause data inconsistency, it can only be used as a read-only property.

@property role and application scenarios:

  • @property optimizes readability of property reading and setting
  • Features that need to restrict attributes;
  • Read-only property. If the property can only be read and not written, it is very convenient to use.
  • This property changes dynamically according to a changing environment.

Guess you like

Origin juejin.im/post/7084604734471929863