亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> Python
Python @property 装饰器

Python @property 装饰器

在本教程中,您将学习 Python @property 装饰器;在面向对象编程中使用 getter 和 setter 的 Pythonic 方式。

Python 编程为我们提供了一个内置的@property 装饰器,它使得在面向对象编程中更容易使用 getter 和 setter。

在详细介绍什么 @property 之前 装饰器是,让我们首先建立一个关于为什么首先需要它的直觉。


没有 Getter 和 Setter 的类

让我们假设我们决定创建一个以摄氏度为单位存储温度的类。它还将实现一种将温度转换为华氏度的方法。一种方法如下:

classCelsius:def __init__(self, temperature =0):self.temperature =temperature def to_fahrenheit(self):return (self.temperature * 1.8) + 32 

我们可以用这个类制作对象并操纵温度 我们希望的属性:

# Pythonclass中设置和获取属性的基本方法Celsius:def __init__(self, temperature=0):self.temperature =temperature def to_fahrenheit(self):return (self. temperature * 1.8) + 32# 创建一个新对象human =Citizen()# 设置温度human.temperature =37# 获取温度属性print(human.temperature)# 获取to_fahrenheit 方法print(human.to_fahrenheit()) 

输出


3798.60000000000001
 

转换为华氏度时的额外小数位是由于浮点算术错误造成的。要了解更多信息,请访问 Python 浮点运算错误。

每当我们分配或检索任何对象属性时,例如 temperature 如上所示,Python在对象的内置__dict__中搜索 字典属性。

>>> human.__dict__{'temperature':37} 

因此,man.temperature 内部变成man.__dict__['temperature'] .


使用 Getter 和 Setter

假设我们想要扩展 Celsius 的可用性 上面定义的类。我们知道任何物体的温度都不能低于-273.15摄氏度(热力学中的绝对零)

让我们更新我们的代码来实现这个值约束。

上述限制的一个明显解决方案是隐藏属性 temperature (将其设为私有)并定义新的 getter 和 setter 方法来操作它。这可以按如下方式完成:

# 制作 Getters 和 Setter 方法类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 

可以看到,上面的方法引入了两个新的get_temperature()set_temperature() 方法。

此外,温度 被替换为 _temperature .下划线 _ 开头用于表示Python中的私有变量。


现在,让我们使用这个实现:

# 制作 Getters 和 Setter 方法类Celsius:def __init__(self, temperature=0):self.set_temperature(temperature) def to_fahrenheit(self):return (self.get_temperature() * 1.8) + 32 # getter 方法 def get_temperature(self):return self._temperature # setter 方法 def set_temperature(self, value):if value <-273.15:raise ValueError("温度低于 -273.15 是不可能的。") self ._temperature =value#创建一个新对象,set_temperature()被__init__human内部调用=Celsius(37)#通过getterprint(human.get_temperature())获取温度属性#获取to_fahrenheit方法,get_temperature()方法调用自身print(human.to_fahrenheit())#新约束实现human.set_temperature(-300)#获取to_fahreheit方法print(human.to_fahrenheit()) 

输出


3798.60000000000001Traceback(最近一次调用最后一次):文件“”,第 30 行,在  文件“”,第 16 行,在 set_temperatureValueError 中:温度低于 -273.15 是不可能的。 
 

此更新成功实施了新限制。我们不再允许设置低于-273.15摄氏度的温度。

注意 :私有变量实际上并不存在于 Python 中。只需遵循一些规范即可。语言本身没有任何限制。

>>> human._temperature =-300>>> human.get_temperature()-300 

然而,上述更新的更大问题是所有实现我们之前类的程序都必须从 obj.temperature 修改它们的代码 obj.get_temperature() 以及像 obj.temperature =val 这样的所有表达式 obj.set_temperature(val) .

在处理数十万行代码时,这种重构可能会导致问题。

总而言之,我们的新更新不向后兼容。这是@property 来救援。


属性类

处理上述问题的pythonic方法是使用property 班级。以下是我们如何更新我们的代码:

# using property classclassCelsius:def __init__(self, temperature=0):self.temperature =temperature def to_fahrenheit(self):return (self.temperature * 1.8) + 32 # getter def get_temperature(self) :print("Getting value...") return self._temperature # setter def set_temperature(self, value):print("Setting value...") if value <-273.15:raise ValueError("Temperature below -273.15 is不可能") self._temperature =value # 创建一个属性对象 temperature =property(get_temperature, set_temperature) 

我们添加了一个 print() get_temperature() 内的函数 和 set_temperature() 清楚地观察到它们正在被执行。

最后一行代码制作了一个属性对象temperature .简单的说,property 附加了一些代码(get_temperatureset_temperature ) 到成员属性访问 (温度 ).

让我们使用这个更新代码:

# using property classclassCelsius:def __init__(self, temperature=0):self.temperature =temperature def to_fahrenheit(self):return (self.temperature * 1.8) + 32 # getter def get_temperature(self):print("Getting value...") return self._temperature # setter def set_temperature(self, value):print("Setting value...") if value <-273.15:raise ValueError (“温度低于-273.15 是不可能的”) self._temperature =value # 创建一个属性对象温度 =property(get_temperature, set_temperature)human =摄氏度(37)print(human.temperature)print(human.to_fahrenheit())human .温度 =-300 

输出


设置值...正在获取值...37正在获取值...98.60000000000001正在设置值...回溯(最近一次调用最后一次):文件“”,第 31 行,在  文件中“”,第 18 行,在 set_temperatureValueError 中:温度低于 -273 是不可能的
 

如我们所见,任何检索温度值的代码 会自动调用get_temperature() 而不是字典(__dict__)查找。类似地,任何给温度赋值的代码 会自动调用set_temperature() .

我们甚至可以在上面看到 set_temperature() 即使在我们创建对象时也被调用。

>>> human =Celsius(37)设置值... 

你能猜出为什么吗?

原因是在创建对象时,__init__() 方法被调用。这个方法有一行 self.temperature =temperature .这个表达式会自动调用set_temperature() .

类似地,任何像 c.temperature 这样的访问 自动调用get_temperature() .这就是财产的作用。这里再举几个例子。

>>> human.temperatureGetting value37>>> human.temperature =37Setting value>>> c.to_fahrenheit()Getting value98.60000000000001 

通过使用 property ,我们可以看到在值约束的实现中不需要修改。因此,我们的实现是向后兼容的。

注意 :实际温度值存储在私有_temperature 多变的。 温度 attribute 是一个属性对象,它为这个私有变量提供了一个接口。


@property 装饰器

在 Python 中,property() 是一个内置函数,它创建并返回一个 property 目的。这个函数的语法是:

property(fget=None, fset=None, fdel=None, doc=None) 

其中,

从实现中可以看出,这些函数参数是可选的。因此,可以简单地创建一个属性对象,如下所示。

>>> property()<0x00000000003239B38处的属性对象> 

一个属性对象有三个方法,getter() , setter() , 和 deleter() 指定 fget , fsetfdel 稍后。这意味着,该行:

温度 =属性(获取温度,设置温度) 

可以分解为:

# make empty propertytemperature =property()#assign fgettemperature =temperature.getter(get_temperature)#assign fsettemperature =temperature.setter(set_temperature) 

这两段代码是等价的。

熟悉 Python 装饰器的程序员可以认识到,上述构造可以实现为装饰器。

我们甚至不能定义名称 get_temperatureset_temperature 因为它们是不必要的并且会污染类命名空间。

为此,我们重用了温度 在定义我们的 getter 和 setter 函数时命名。让我们看看如何将其实现为装饰器:

# 使用@property 装饰器类Celsius:def __init__(self, temperature=0):self.temperature =temperature def to_fahrenheit(self):return (self.temperature * 1.8) + 32 @property def temperature(self):print("Getting value...") return self._temperature @temperature.setter def temperature(self, value):print("Setting value...") if value <-273.15 :raise ValueError("温度低于-273是不可能的") self._temperature =value#创建一个对象human =Celsius(37)print(human.temperature)print(human.to_fahrenheit())coldest_thing =Celsius(-300) 

输出


设置值...正在获取值...37正在获取值...98.60000000000001正在设置值...回溯(最近一次调用最后一次):文件“”,第 29 行,在  文件中“”,第 4 行,在 __init__ 文件“”,第 18 行,在 temperatureValueError 中:温度低于 -273 是不可能的    
 

以上实现简单高效。这是使用 property 的推荐方式 .


Python

  1. Python 字典
  2. Python 检查文件是否存在 |如何检查 Python 中是否存在目录
  3. Python pass 语句
  4. Python 全局关键字
  5. Python 数据类型
  6. Python 输入、输出和导入