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