Python study notes 9: @property decorator for advanced object-oriented

I read a lot of articles about @property decorator today. My understanding of functions has been further deepened. This is also the first step for object-oriented programming to enter a higher level, and I will continue to work hard in the future.


1. @property decorator

  • We have discussed the issue of attribute and method access permissions in Python. Although we do not recommend setting the attribute as private, it is also problematic if the attribute is directly exposed to the outside world. For example, we have no way to check whether the value assigned to the attribute is valid. .
  • Our previous suggestion is to name the property with a single underscore at the beginning. In this way, it implies that the property is protected. It is not recommended to access the property directly. If you want to access the property, you can use the property’s getter (accessor) and setter (modification).器) method to perform the corresponding operation. If you want to do this, you can consider using the **@property** wrapper to wrap the getter and setter methods to make the access to the property safe and convenient.
  • The main function is to turn a method in the class into an attribute in the class, and make it easier to define attributes and modify existing attributes

Case 1:

  • Python's built-in @property decorator can disguise the method of a class as a way of calling properties .
    • That is, the calling method of Foo.func() has become the method of Foo.func.
    • Once you add a decorator @property to the function, you can call the function directly without adding parentheses when calling the function.
# 创建一个学生类
class Student:

    # 定义学生属性,初始化方法
    # name和score属于实例变量, 其中score属于私有变量
    def __init__(self, name, score):
        self.name = name
        self.__score = score

    # 利用property装饰器把函数伪装成属性
    @property
    def score(self):
        print("My name is {}, score is {}".format(self.name, self.__score))


# 实例化,创建对象
student1 = Student("AD", 3)

student1.score    # My name is AD, score is 3

Case 2:

class Student(object):

    def get_score(self):
         return self._score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')    # integer:整数
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
        
        
# 方法1:
s = Student()
s.score = 60 #实际转化为s.set_score(60)
s.score      #实际转化为s.get_score()

# 方法2:
s = Student()
s.set_score(90)
s.get_score()

s.set_score(9000)

The above code involves Pythond's built-in function isinstance():

  • isinstance(object, classinfo) function to determine whether an object is a known type, similar to type()
  • If you want to judge whether the two types are the same, it is recommended to use isinstance()
  • If the type of object is the same as the type of classinfo, it returns: True, otherwise it returns False
class Student(object):

    @property
    def birth(self):
        return self._birth

    @birth.setter          
    def birth(self, value): # birth是可读写属性
        self._birth = value

    @property
    def age(self):          # age是只读属性,因为age可以根据birth和当前时间计算出来
        return 2015 - self._birth
    """
    注意如果直接将属性名作为函数名,那么属性必须设置为私有属性,否则在用s.score时,不知道调用函数,还是调用属性,
    就会犯RecursionError: maximum recursion depth exceeded in comparison错误
    """


Case 3:

# @perproty装饰器,使得定义新属性和对现有的属性的修改变的更简单
class C(object):
       
    @property
    def x(self):
        "I am the 'x' property."
        return self._x
 
    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x
        
        
# 传统的方法绑定属性和访问属性:
class UserInfo(object):
 
    # name属于私有变量
     def get_name(self):
        """通过类的方法访问类中的属性"""
        return self.__name
 
     def set_name(self, name):
        """通过外部传参的方式绑定属性"""
        self.__name = name
 
 
if __name__ == '__main__':
    user = UserInfo()
    # 绑定name属性
    user.set_name(["AD"])
    print("My name is:", user.get_name())   # My name is: ['AD']
class UserInfo(object):
    @property
    def name(self):
         return self.__name
 
    @name.setter
    def name(self, name):
        if isinstance(name, str):
             self.__name = name
        else:
             raise TypeError("The name must be str")
 
 
if __name__ == '__main__':
    user = UserInfo()
    # 绑定属性
    user.name = "AD"
    print("My name is: ", user.name)  # My name is:  AD
    user.name = ["AD"]
    print("My name is: ", user.name)  # TypeError: The name must be str
  • After the optimized code, we can see that when the bound property is not a string type, an error will be reported, and we can directly bind the property and access the property in a similar way to access the property, which is more intuitive

Case 4:

  • Can be used to access private member properties outside the class
class UserInfo(object):
 
    def __init__(self, name, age):
        self.__name = name
        self.__age = age
 

if __name__ == '__main__':
    user = UserInfo('AD', 18)
    print(user.__name) # AttributeError: 'UserInfo' object has no attribute '__name'
# 进行优化之后:

class UserInfo(object):
 
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        """通过类的方法访问类中的私有属性"""
        return self.__name
 
if __name__ == '__main__':
    user = UserInfo('AD')
    print("获取name属性:", user.name)

* Comprehensive case 1:

class Person(object):

    def __init__(self, name, age):
        self._name = name
        self._age = age

    # 1.访问器 - getter方法:
    # name为私有变量,无法从外部进行访问
    @property
    def name(self):
        return self._name

    # 2.访问器 - getter方法:
    @property
    def age(self):
        return self._age

    # 3.修改器 - setter方法:
    @age.setter
    def age(self, age):
        self._age = age

    def play(self):
        if self._age <= 18:
            print('%s正在学Python.' % self._name)
        else:
            print('%s正在打王者.' % self._name)


def main():
    person = Person('李元芳', 17)
    person.play()			      # 李元芳正在学python.
    person.age = 22
    person.play()		          # 李元芳正在打王者.
    # person.name = '狄仁杰'       # AttributeError: can't set attribute


if __name__ == '__main__':
    main()
   

to sum up

  • 1.@property decorator can disguise the method of the class as the way of property calling, such as: Foo.func()----Foo.func
  • 2. The @property decorator can be used to access private member properties outside the class
  • have to be aware of is
    • The method decorated by this decorator cannot pass any other parameters except self
    • When using @property and @x.setter at the same time, you need to ensure that x and the method name modified by @x.setter must be consistent with the method name modified by @property

Guess you like

Origin blog.csdn.net/amyniez/article/details/104561163