Py学习  »  Python

Python中的 @property特性

Python程序员 • 5 年前 • 379 次点击  


你将了解Python中的 @property特性, 以pythonic的方式使用getter和setter。


目录表


  • 从一个例子开始

  • 使用 Getter 和 Setter

  • @property的力量

  • 深入理解Property


Python有一个很棒的概念,叫做property,它使面向对象的程序员的生活更加简单。


在定义和研究@property是什么之前,让我们先直观感受下为什么首先应该使用它。


从一个例子开始


我们假设你决定创建一个可以以摄氏度存储温度的类[1],它还将实现一个将温度转换为华氏度的方法。一种方法是像下面这样做。



我们可以使用这个类创建对象,并按照我们的意愿操作其属性temperature。你可以在Python shell上试试这些操作。


在转换成华氏温度时,由于浮点运算错误(请在Python解释器中尝试1.1 + 2.2),小数点多了一位。


当我们赋值或检索任何对象属性像temperature时,如上面所示,Python都会在该对象的__dict__字典中搜索它。


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


现在,让我们进一步假设我们的类在客户中很受欢迎,他们开始在自己的程序中使用它。他们对这个对象做了各种各样的赋值操作。


有一天,一个值得信赖的客户来找我们,建议温度不能低于-273摄氏度(热力学专业的学生可能会说实际上是-273.15摄氏度),也被称为绝对零度。他还要求我们实现这个值约束。作为一家追求客户满意的公司,我们很高兴地采纳了这个建议,并发布了1.01版本(对现有的类进行升级)。


使用Getter和Setter


上述对值进行约束的一个明显解决方案是隐藏属性temperature(使其私有)并定义新的 getter 和 setter 接口来操作它。可以按照下面这样做。



从上面可以看出,我们定义了get_temperature()set_temperature()两个新方法,并且用 _temperature 替换了temperature。在Python中,开头的下划线 (_) 用于表示私有变量。



这次更新成功地实现了新的限制。我们没法再将温度设置在-273度以下。


请注意,Python中不存在私有变量,但还是有一些简单的准则可以遵循。Python语言本身并不会做限制。


但这并不是什么大问题。上述更新的一个大问题是,所有在其程序中实现我们前面的类的客户都必须修改他们的代码,将obj.temperature修改为 obj.get_temperature(),并且将像 obj.temperature = val 的所有赋值语句修改为obj.set_temperature(val)


这种重构可能会给客户带来数十多万行代码的麻烦。


总之,我们的新更新不向后兼容。这时property就派上用场了。


@property的力量


处理上述问题的Pythonic的方法是使用property。以下是我们如何实现它。



然后,在shell中运行以下代码并注意观察。



我们在 get_temperature()set_temperature() 中添加了一个 print() 函数,来清楚地观察它们是否正在执行。


代码的最后一行创建了一个property对象 temperature。简单地说,property将一些代码( get_temperature set_temperature )附加到成员属性访问中( temperature )。


任何检索 temperature 值的代码都将自动调用 get_temperature(),而不是使用字典(__dict__)进行查找。类似地,任何对temperature 赋值的代码都会自动调用 set_temperature()。这是Python中一个很酷的特性。


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


你能猜到这是为什么吗?


原因是在创建对象时, __init__() 方法被调用。这个方法有 self.temperature = temperature 这行代码,所以赋值时会自动调用set_temperature()



类似地,任何访问,比如 c.temperature,都会自动调用 get_temperature()。这就是property的作用。这里有更多的几个例子。



通过使用 property,可以看到,我们修改了类并实现了对值的约束,而不需要对客户代码进行任何更改。因此,我们的实现是向后兼容的,皆大欢喜。


最后请注意,实际的温度值存储在私有变量 _temperature中。属性 temperature是一个property对象,它为这个私有变量提供接口。


深入理解 Property


在Python中,property()是一个内置函数,用于创建和返回一个property对象。这个函数的签名是:



其中,fget 是获取属性值的函数,fset 是设置属性值的函数,fdel 是删除属性的函数,doc 是字符串(像注释一样)。从上述实现中可以看出,这些函数参数是可选的。因此,可以按照以下方式创建property对象。



property对象有三个方法,getter()setter()deleter(),用于后续指定 fgetfsetfdel。这意味着本行代码

可以分解为

这两段代码是等价的。


熟悉Python中的装饰器[2]的程序员可能会意识到,上面的构造可以实现为装饰器。


我们可以继续,不去定义 get_temperature set_temperature名称,因为它们是不必要的,并且会污染类命名空间。为此,我们在定义 gettersetter 函数时重用了名称 temperature。这就是它实现的方式。



上述实现是既简单又推荐使用的创建property的方法。当你在Python中寻找property时,你很可能会遇到这些类型的构造。


好了,今天就到这里。


相关链接:

[1]——https://www.programiz.com/python-programming/class 

[2]——https://www.programiz.com/python-programming/decorator



英文原文:https://www.programiz.com/python-programming/property  
 译者:野生大熊猫  



今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/8E7qFFI1bN
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/29056
 
379 次点击