参考自: https://www.programiz.com/python-programming/property

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

  在细说@property之前,我们先举一个简单的例子,让大家了解为什么需要它。

Class Without Getters and Setters

  假设我们需要一个类用来存储温度的摄氏度。这个类不但提供摄氏度,还提供一个摄氏度转华氏度的方法。该类如下所示:

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

  接下来展示我们怎么使用这个类。

# 温度类
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

  转换为华氏温度时,小数点后的额外位置是由于浮点运算错误造成的。

  当我们在设置和获取任何对象的属性时(如上文所示的tempurature)时,Python都会在对象的内置dict字典属性中搜索它。

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

  所以我们还可以这样做。

>>> human.__dict__['temperature']
37

Using Getters and Setters

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

  让我们丰富这个类让它来能够约束tempurature这个值。

  约束tempurature的方法就是将tempurature设置为私有属性,并定义setter和getter方法来操作它。

# 添加了Getters和Setter方法
class 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("Temperature below -273.15 is not possible.")
self._temperature = value

  在Celsius类中,temperature变成_temperature。开头加下划线是用来表示私有变量(约定俗成的规定)。

  接着让我们看看怎么使用这个类。

class 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("Temperature below -273.15 is not possible.")
self._temperature = value # 创建温度类
human = Celsius(37) # 通过getter方法获取温度
print(human.get_temperature()) print(human.to_fahrenheit()) # setter方法设置温度
human.set_temperature(-300) print(human.to_fahrenheit())

  输出。

37
98.60000000000001
Traceback (most recent call last):
File "<string>", line 30, in <module>
File "<string>", line 16, in set_temperature
ValueError: Temperature below -273.15 is not possible.

  这个示例成功演示了温度类不允许把温度设置在-273.15度以下。

  在Python中temperature属性依然可以通过类直接访问,与Java不同,Python中并没有private关键字。所以说在Python中,变量前添加下划线变成私有变量也就是约定俗称的规定,大家都应遵守。

>>> human._temperature = -300    # 依然可以更改此属性
>>> human.get_temperature()
-300

  然而,上面的类带来了一个新的问题,我们再也不能通过obj.temperature = obj 和 value = obj.emperature,取而代之的是obj.set_temperature(obj)和value = obj.get_temperature()。

  此时,该Python的内置装饰器出场了。

The property Class

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

# 使用property的类
class Celsius:
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 not possible")
self._temperature = value # 创建一个property对象
temperature = property(get_temperature, set_temperature)

  我们添加了一个print()方法在get_temperature和set_temperature方法中。

  类中的最后一行,我们创建了一个property对象--temperature。让我们看一下怎么使用这个新类。

# using property class
class Celsius:
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 not possible")
self._temperature = value # creating a property object
temperature = property(get_temperature, set_temperature) human = Celsius(37) print(human.temperature) print(human.to_fahrenheit()) human.temperature = -300

  输出。

Setting value...
Getting value...
37
Getting value...
98.60000000000001
Setting value...
Traceback (most recent call last):
File "<string>", line 31, in <module>
File "<string>", line 18, in set_temperature
ValueError: Temperature below -273 is not possible

  上面我们看到了,当对temperature进行操作时,会自动调用到get_temperature和set_temperature方法。前面我们也提到,当通过Celsius的对象获取temperature属性时会从obj.__dict__中找到temperature属性进行操作。而当前这个类并没有这样。

  当我们在温度类中对temperature进行赋值时也会调用到set_temperature方法。

>>> human = Celsius(37)
Setting value...

  再看看下面对temperature的使用。

>>> human.temperature
Getting value
37
>>> human.temperature = 37
Setting value >>> c.to_fahrenheit()
Getting value
98.60000000000001

  

The @property Decorator

  在Python中,property()是内建方法。此方法的定义如下。

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

  参数解释:

  • fget:获取属性值的方法。
  • fset:设置属性值的方法。
  • fdel:删除属性值的方法。
  • doc:字符串(类似于说明)。

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

>>> property()
<property object at 0x0000000003239B38>

  在Celsius类中我们添加了如下代码。

temperature = property(get_temperature,set_temperature)

  当然我们也可以这样做。

# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)

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

  接下来让我们看一下如何运用装饰器来替代上面的set_temperature和get_temperature。

# Using @property decorator
class 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("Temperature below -273 is not possible")
self._temperature = value # create an object
human = Celsius(37) print(human.temperature) print(human.to_fahrenheit()) coldest_thing = Celsius(-300)

  输出。

Setting value...
Getting value...
37
Getting value...
98.60000000000001
Setting value...
Traceback (most recent call last):
File "<string>", line 29, in <module>
File "<string>", line 4, in __init__
File "<string>", line 18, in temperature
ValueError: Temperature below -273 is not possible

  到此,property我们介绍完毕。

  我想说的是,既然使用的是面向对象的语言,那么我们要善用面向对象中封装这个特性,使它能够发挥出重要的作用。

最新文章

  1. Oozie命令行常用命令汇总[转]
  2. NOIP2002pj产生数[floyd 高精度]
  3. Python 3.X 实现定时器 Timer,制作抽象的Timer定时器基类
  4. QNX 实时操作系统(Quick Unix)
  5. SGU 165.Basketball
  6. WebService CXF调试常见报错及解决方案
  7. thinkphp 一些常用写法
  8. JAVA并发编程实战---第二章:线程安全性
  9. python报错“UnicodeEncodeError: &#39;ascii&#39; codec can&#39;t encode characters in position 22-26: ordinal not in range(128)”问题解决
  10. 常用业务接口界面化 in python flask
  11. 编写第一个spring MVC程序
  12. memcached+狀態模式+工廠方法使用
  13. 只有一百行的xss扫描工具——DSXS源码分析
  14. Spring Boot程序获取tomcat启动端口
  15. 神州数码标准访问控制列表配置(ACL)
  16. 省市区三级联动(附j全国省市区json文件)
  17. css伪元素之before和after
  18. CentOS7.4安装部署KVM虚拟机
  19. OninitDialog与OnCreate两个消息有何区别
  20. Git和Github入门教程

热门文章

  1. [ZJOI2007]仓库建设(斜率dp优化)
  2. Codeforces1248F. Catowice City
  3. hdu5550 Game Rooms
  4. 递归实现jsonTree
  5. Python优化机制:常量折叠
  6. leetcode16 最接近的三数之和 双指针
  7. React Hooks: useMemo All In One
  8. React Native &amp; Fast Refresh
  9. DataBase All in One
  10. 图解 Webpack 4.x 热更新原理