一文了解python的 @property
参考自: 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的更多相关文章
- 第7.23节 Python使用property函数定义属性简化属性访问的代码实现
第7.23节 Python使用property函数定义属性简化属性访问的代码实现 一. 背景 在本章前面章节中,我们介绍了类相关的知识,并举例进行了说明,在这些例子中会定义一些形如 ...
- Python的property装饰器的基本用法
Python的@property装饰器用来把一个类的方法变成类的属性调用,然后@property本身又创建了另一个装饰器,用一个方法给属性赋值.下面是在类中使用了@property后,设置类的读写属性 ...
- python's @property
[python's @property] 参考:http://docs.python.org/3/library/functions.html?highlight=property#property
- python 中 property 属性的讲解及应用
Python中property属性的功能是:property属性内部进行一系列的逻辑计算,最终将计算结果返回 property属性的有两种方式: 1. 装饰器 即:在方法上应用装饰器 2. 类属性 即 ...
- python 中property函数如何实现
实际上,在python中property(fget,fset,fdel,doc)函数不是一个真正的函数,他其实是拥有很多特殊方法的类. 这特殊类总的很多方法完成了property函数中的所有工作,涉及 ...
- python的property属性
最近看书中关于Python的property()内建函数属性内容时<python核心编程>解释的生僻难懂,但在网上看到了一篇关于property属性非常好的译文介绍. http://pyt ...
- python中@property装饰器的使用
目录 python中@property装饰器的使用 1.引出问题 2.初步改善 3.使用@property 4.解析@property 5.总结 python中@property装饰器的使用 1.引出 ...
- 【转】python之property属性
1. 什么是property属性 一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法 # ############### 定义 ############### class Foo: def ...
- python中property属性的介绍及其应用
Python的property属性的功能是:property属性内部进行一系列的逻辑计算,最终将计算结果返回. 使用property修饰的实例方法被调用时,可以把它当做实例属性一样 property的 ...
随机推荐
- Codeforces Round #634 (Div. 3)
D题想复杂了,花了好多时间,感觉也没时间看F了,就来写个题解蹭蹭访问量把^_^ 传送门:1335 A. Candies and Two Sisters 题意:你要把n个糖果分给两个人,两个人的糖果数不 ...
- hdu5662 YJQQQAQ and the function (单调栈)
Problem Description YJQQQAQ has an array A of length n. He defines a function fl,r,k where l,r,k are ...
- Codeforces Round #678 (Div. 2) C. Binary Search (二分,组合数)
题意:有长度\(n\)的序列,让你构造序列,使得二分查找能在\(pos\)位置找到值\(x\).问最多能构造出多少种排列? 题解:题目给出的\(pos\)是固定的,所以我们可以根据图中所给的代码来进行 ...
- hdu1828 Picture(线段树+扫描线+矩形周长)
看这篇博客前可以看一下扫描线求面积:线段树扫描线(一.Atlantis HDU - 1542(覆盖面积) 二.覆盖的面积 HDU - 1255(重叠两次的面积)) 解法一·:两次扫描线 如图我们可以 ...
- 2015ACM/ICPC亚洲区沈阳站-重现赛 M - Meeting (特殊建边,最短路)
题意:有\(n\)个点,\(m\)个集合,集合\(E_i\)中的点都与集合中的其它点有一条边权为\(t_i\)的边,现在问第\(1\)个点和第\(n\)个点到某个点的路径最短,输出最短路径和目标点,如 ...
- 5.2 spring5源码--spring AOP源码分析三---切面源码分析
一. AOP切面源码分析 源码分析分为三部分 1. 解析切面 2. 创建动态代理 3. 调用 源码的入口 源码分析的入口, 从注解开始: 组件的入口是一个注解, 比如启用AOP的注解@EnableAs ...
- OpenStack Train版-4.安装placement放置服务
安装placement放置服务 创建placement数据库 mysql -uroot CREATE DATABASE placement; GRANT ALL PRIVILEGES ON place ...
- javascript输出数据到文件
function export(name, data) { var urlObject = window.URL || window.webkitURL || window var export_bl ...
- Oh My Zsh All In One
Oh My Zsh All In One https://ohmyz.sh/ install # CURL $ sh -c "$(curl -fsSL https://raw.github. ...
- 阅文集团 招聘官网 bug
阅文集团 招聘官网 bug https://join.yuewen.com/ 前端开发 zxx.jpg 张鑫旭 https://qidian.gtimg.com/yuewen/join/css/ima ...