参考自: 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我们介绍完毕。

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

一文了解python的 @property的更多相关文章

  1. 第7.23节 Python使用property函数定义属性简化属性访问的代码实现

    第7.23节 Python使用property函数定义属性简化属性访问的代码实现 一.    背景       在本章前面章节中,我们介绍了类相关的知识,并举例进行了说明,在这些例子中会定义一些形如 ...

  2. Python的property装饰器的基本用法

    Python的@property装饰器用来把一个类的方法变成类的属性调用,然后@property本身又创建了另一个装饰器,用一个方法给属性赋值.下面是在类中使用了@property后,设置类的读写属性 ...

  3. python's @property

    [python's @property] 参考:http://docs.python.org/3/library/functions.html?highlight=property#property

  4. python 中 property 属性的讲解及应用

    Python中property属性的功能是:property属性内部进行一系列的逻辑计算,最终将计算结果返回 property属性的有两种方式: 1. 装饰器 即:在方法上应用装饰器 2. 类属性 即 ...

  5. python 中property函数如何实现

    实际上,在python中property(fget,fset,fdel,doc)函数不是一个真正的函数,他其实是拥有很多特殊方法的类. 这特殊类总的很多方法完成了property函数中的所有工作,涉及 ...

  6. python的property属性

    最近看书中关于Python的property()内建函数属性内容时<python核心编程>解释的生僻难懂,但在网上看到了一篇关于property属性非常好的译文介绍. http://pyt ...

  7. python中@property装饰器的使用

    目录 python中@property装饰器的使用 1.引出问题 2.初步改善 3.使用@property 4.解析@property 5.总结 python中@property装饰器的使用 1.引出 ...

  8. 【转】python之property属性

    1. 什么是property属性 一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法 # ############### 定义 ############### class Foo: def ...

  9. python中property属性的介绍及其应用

    Python的property属性的功能是:property属性内部进行一系列的逻辑计算,最终将计算结果返回. 使用property修饰的实例方法被调用时,可以把它当做实例属性一样 property的 ...

随机推荐

  1. python实现通过指定浏览器免费观看vip视频

    程序是先通过一个解析视频的网站,然后我们提取其接口,然后实现观看vip视频的目的 所以说免费观看视频python程序很容易,但是下载视频就有些许麻烦了,下载视频请见我另一篇博客:python+fidd ...

  2. CodeForces - 1209D 并查集

    题意: 有 n个不同的糖果,从 1到 n编号.有 k个客人.要用糖果招待客人.对于每个客人,这些糖果中恰有两个是其最爱.第 i个客人最爱的糖果编号是 xi和 y.将 k 个客人任意排列,他们按顺序去拿 ...

  3. Intelligent IME HDU - 4287 字典树

    题意: 给你m个字符串,每一个字符对应一个数字,如下: 2 : a, b, c    3 : d, e, f    4 : g, h, i    5 : j, k, l    6 : m, n, o ...

  4. C++ string (浅谈)

    浅谈string <string> typedef basic_string<char> string; 本篇主要内容是简单地介绍 string类 在竞赛方面较实用的一些功能, ...

  5. 【译】Async/Await(五)—— Executors and Wakers

    原文标题:Async/Await 原文链接:https://os.phil-opp.com/async-await/#multitasking 公众号: Rust 碎碎念 翻译 by: Praying ...

  6. 整体算力提升40% 芯片级安全防护 | 阿里云发布第七代ECS云服务器

    2 月 8 日,阿里云宣布推出第七代 ECS 云服务器产品家族,基于最新的神龙架构,相较于上一代整体算力提升 40%,容器部署密度最大可提升 6 倍,是最佳的云原生载体,此外全量搭载安全芯片,实现&q ...

  7. LINUX - 最简单的CS通信实例

    服务端[编译:gcc server.c -o server] #include <stdio.h> #include <sys/socket.h> #include <s ...

  8. u-boot 移植 --->7、u-bootl流程粗线条梳理

    通过前面的调试了解到s5pv210这个芯片的启动流程是需要将u-boot分为两部分的分别为SPL和u-boot.这里我使用网上的方式不直接使用u-boot的SPL连接脚本单独生成SPL的image而是 ...

  9. js load more select

    js load more select searchable scroll load more append to list refs xgqfrms 2012-2020 www.cnblogs.co ...

  10. CSS Grid Layout In Action

    CSS Grid Layout In Action CSS 异形网格布局实战 refs https://static-nginx-online.fbcontent.cn/tutor/tutor-ybc ...