python @property 装饰器
周兵 人气:0一、property的装饰器用法
先简单上个小栗子说明:
class property(fget=None,fset=None,fdel=None,doc=None)
fget
是用于获取属性值的函数fset
是用于设置属性值的函数fdel
是用于删除属性值的函数doc
为属性对象创建文档字符串
使用property
可以讲类的方法变成同名属性,使用起来更加简洁,最后实例展示
使用时建议直接用property的装饰器用法, 比较简洁,下面是官方示例,利用@property
装饰方法x
将其变成名称相同的属性, 通过fget, fset, fdel可以控制x的读写删属性.
class C: def __init__(self): self._x = None @property def x(self): """I'm the 'x' property.""" return self._x #设置fset,注意x要与@property修饰的方法名称相同 @x.setter #这个fset名称没有限制,建议与x相同 def x(self, value): self._x = value #设置fdel @x.deleter def x(self): del self._x
话不多说, 直接上例子, 在Man这个类中设置一个可读可写的birthYear属性,一个可读gender属性,一个可读可写可删的体重属性,还有一个利用birthYear推算出的age属性
""" @property, @*.setter""" from datetime import datetime class Man: def __init__(self, birthYear=None, gender=None, weight=None): """1.使用@property可以隐藏私有属性,例如把'_birthYear'属性隐藏, 把property对象birthYear作为对外的属性""" self._birthYear = birthYear self._gender = gender self._weight = weight @property def birthYear(self): return self._birthYear @birthYear.setter def birthYear(self, value): """2.可以在setter中对属性输入进行限制或者其他操作""" assert not value > datetime.now().year, f'please input the right value!' self._birthYear = value @property """3.获取年龄直接用obj.age,而不需写成方法obj.age(), 更加自然方便""" def age(self): return datetime.now().year - self._birthYear @property def gender(self): return self._gender @property def weight(self): return self._weight @weight.setter def weight(self, value): self._weight = value @weight.deleter def weight(self): del self._weight lilei = Man(1996, 'male', 180) age = lilei.age print('Lilei今年{}岁\n'.format(age)) # 设置性别 try: lilei.gender = 'female' except: print('性别无法进行更改!\n') # 更新体重 print(f'lilei减肥前的体重:{lilei.weight}\n') lilei.weight = 200 print(f'lilei减肥后的体重:{lilei.weight}\n') print('lilei减肥失败后一气之下将体重信息删了\n') del lilei.weight try: print('lilei的体重{}'.format(lilei.weight)) except: print('找不到lilei的体重信息!')
输出结果:
Lilei今年25岁
性别无法进行更改!
lilei减肥前的体重:180
lilei减肥后的体重:200
lilei减肥失败后一气之下将体重信息删了
找不到lilei的体重信息!
二、举例说明
现在让我们直观看一下python内置property修饰器为什么会存在,可以用来解决什么问题?
先来一个具体的例子,定义一个表示摄氏度的class
并且这个类包含一个从摄氏度转换到华氏温度的方法。
1.不用setter和getter方法的实现
# 初始版本 class Celsius: def __init__(self, temperature = 0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32 # 实例化 human = Celsius() # 设置温度 human.temperature = 37 # 获取温度值 print(human.temperature) # 调用内置方法将摄氏度转化为华氏温度 print(human.to_fahrenheit())
输出结果:
37
98.60000000000001
2.使用setter和getter的实现,增加温度值输入的限制
但是如果现在有人让human.temperature = -300
, 我们知道摄氏温度是不可能低于-273.15的,此时需要对温度值进行限制, 常规方法是设置一个温度值的setter
和getter
的方法,此时温度值存放在_temperature
中
# 更新温度限制的版本 class Celsius: def __init__(self, temperature=0): self.set_temperature(temperature) def to_fahrenheit(self): return (self.get_temperature() * 1.8) + 32 # getter method def get_temperature(self): return self._temperature # setter method def set_temperature(self, value): if value < -273.15: raise ValueError("摄氏温度不可能低于 -273.15 !") self._temperature = value # 实例化 human = Celsius(37) # 使用添加的getter获取温度值 print(human.get_temperature()) # 调用内置方法将摄氏度转化为华氏温度 print(human.to_fahrenheit()) # 使用添加的setter对温度值进行设置 human.set_temperature(-300) # Get the to_fahreheit method print(human.to_fahrenheit())
毫无疑问,在设置温度值等于-300的时候肯定会报错,但是这个时候你可能发现设置和获取温度值的代码发生变化而且更复杂 并且 你需要对Celsius类的初始化函数进行更改,self.temperature = temperature
到 self.set_temperature(temperature)
, 如果现在是一个拥有很多属性的类, 一个一个去进行这样的更改是很麻烦的,而且可能会导致与这个类别相关的代码出现错误, 有没有更好的实现方式呢?这个时候就该今天的主角property装饰器出场了
3.利用property装饰器实现的版本
# 使用 @property 装饰器版本 class Celsius: def __init__(self, temperature=0): #这里的self.temperture是下面定义的property对线 temperatue #所以你会发现在初始化Celsius时, 调用了temperature.setting方法 self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32 @property def temperature(self): print("获取温度值...") return self._temperature @temperature.setter def temperature(self, value): print("设置温度值...") if value < -273.15: raise ValueError("摄氏温度不可能低于 -273.15 !") self._temperature = value # 用property的实现后获取和设置温度值与最初的版本一样! human = Celsius() # 设置温度 human.temperature = 37 # 获取温度值 print(human.temperature) # 调用内置方法将摄氏度转化为华氏温度 print(human.to_fahrenheit()) #测试温度限制功能 human.temperature = -300
输出结果:
设置温度值...
设置温度值...
获取温度值...
37
获取温度值...
98.60000000000001
设置温度值...
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
d:\2.github\python_demo\016_decorator.py in <module>
30
31 #测试温度限制功能
---> 32 human.temperature = -300d:\2.github\python_demo\016_decorator.py in temperature(self, value)
16 print("设置温度值...")
17 if value < -273.15:
---> 18 raise ValueError("摄氏温度不可能低于 -273.15 !")
19 self._temperature = value
20ValueError: 摄氏温度不可能低于 -273.15 !
可以看到此时temperature
设置有限制而且获取和设置温度值的代码与初始版本一模一样,也就是说代码可以向后兼容
加载全部内容