python @property 装饰器使用方法

作者:周兵 时间:2021-04-01 00:38:05 

一、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的,此时需要对温度值进行限制, 常规方法是设置一个温度值的settergetter的方法,此时温度值存放在_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 = -300

d:\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
     20 

ValueError: 摄氏温度不可能低于 -273.15 !

可以看到此时temperature设置有限制而且获取和设置温度值的代码与初始版本一模一样,也就是说代码可以向后兼容

来源:https://zhuanlan.zhihu.com/p/358361657

标签:python,@property,装饰器
0
投稿

猜你喜欢

  • JavaScript模板入门介绍

    2024-06-21 22:06:17
  • 使用Nginx+uWsgi实现Python的Django框架站点动静分离

    2023-11-13 11:30:37
  • 在PyCharm中批量查找及替换的方法

    2023-05-29 17:15:13
  • golang中for循环遍历channel时需要注意的问题详解

    2024-04-29 13:05:16
  • delete误删数据使用SCN号恢复(推荐)

    2024-01-24 04:02:04
  • js中继承的几种用法总结(apply,call,prototype)

    2024-04-16 09:47:25
  • pyinstaller还原python代码过程图解

    2022-04-09 10:06:59
  • html静态页面调用php文件的方法

    2023-09-04 23:18:21
  • 解决Python对齐文本字符串问题

    2021-08-20 10:22:26
  • 如何使用Go语言实现远程执行命令

    2024-04-25 15:16:39
  • JS操作input标签属性checkbox全选的实现代码

    2024-04-28 09:50:56
  • Python+Opencv实现图像匹配功能(模板匹配)

    2022-06-28 08:56:35
  • python分割和拼接字符串

    2023-05-12 05:57:03
  • python中upper是做什么用的

    2023-10-30 15:53:29
  • python实现任意位置文件分割的实例

    2021-01-17 18:18:22
  • Numpy实现矩阵运算及线性代数应用

    2022-10-18 17:55:50
  • Firefox下无法正常显示年份的解决方法

    2024-04-18 09:39:50
  • 使用python PIL库实现简单验证码的去噪方法步骤

    2022-05-05 00:48:46
  • pytorch程序异常后删除占用的显存操作

    2021-04-03 22:33:38
  • Sublime Text3最新激活注册码分享适用2020最新版 亲测可用

    2023-02-03 07:18:38
  • asp之家 网络编程 m.aspxhome.com