This article is participating in Python Theme Month. See the link for details

In general, when we need to privatize sensitive properties of objects or properties that we do not want external direct access to, but sometimes we need to modify these private properties, what should we do?

1. Several concepts

  • _a(preceded by a single underscore), this property represents only private by convention, not true private.
  • __a(leading double underscore), which means private and cannot be accessed externally.
  • _a_(double underscore), which identifies system attributes. (optional)
  • A_ (followed by a single underscore) is used to avoid conflicts with reserved keywords. (optional)

2. Take an example

Define a class:

class Student(object) :

    _sex='male'

    __age=0
Copy the code

Execution :(private attributes cannot be accessed externally)

>>> stu = Student()
>>> stu._sex
'male'
>>> stu.__age
Traceback (most recent call last):
  File "<stdin>", line 1.in <module>
AttributeError: 'Student' object has no attribute '__age'
>>>
Copy the code

3. Solve problems

As we can see from the above class, private attributes cannot be accessed in the class instance. What should we do? When we need to query and modify a class’s private __age attribute, we define get_age and set_age.

class Student(object) :

    _sex='male'

    __age=0

    def get_age(self) :
        return self.__age

    def set_age(self,age) :
        self.__age = age
Copy the code

Perform:

>>> stu = Student()
>>> stu.get_age()   
0
>>> stu.set_age(18) 
>>> stu.get_age()   
18
>>>
Copy the code

4. Change your approach

However, this approach is a bit complicated and is not suitable for classes with more private attributes, so we expected to find a simpler way to solve this problem, such as converting this private attribute to another attribute. Good news for you, Python already does that for us, and that’s at sign property.

class Student(object) :

    _sex='male'

    __age=0

    def get_age(self) :
        return self.__age

    def set_age(self,age) :
        self.__age = age
    
    @property
    def age(self) :
        return self.__age
Copy the code

Perform:

>>> from payhlib import Student
>>> s = Student()
>>> s.age
0
>>> s.set_age(19)
>>> s.age
19
>>
Copy the code

Above we converted the __age private property to the age property. You might be wondering, since the private property was converted to the property, can we change it directly? The answer is no, because property converts __age to a property, but it doesn’t have setters and needs to be added.

>>> from payhlib import Student
>>> s = Student()
>>> s.age  
0
>>> s.age=20
Traceback (most recent call last):
  File "<stdin>", line 1.in <module>
AttributeError: can't set attribute
>>>
Copy the code

Add setter methods

class Student(object) :

    _sex='male'

    __age=0

    def get_age(self) :
        return self.__age

    def set_age(self,age) :
        self.__age = age
    
    @property
    def age(self) :
        return self.__age
    
    @age.setter
    def age(self,value) :
        self.__age=value
Copy the code

Perform:

>>> from payhlib import Student
>>> s = Student()
>>> s.age
0
>>> s.age=20
>>> s.age    
20
>>>
Copy the code

Here, @peoperty share finished, about its implementation principle you can view the source code for research. The picture