一文了解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的 ...
随机推荐
- 掌握数位dp
最近遇到了数位dp题目,于是就屁颠屁颠的跑过来学习数位dp了~ "在信息学竞赛中,有这样一类问题:求给定区间中,满足给定条件的某个D 进制数或此类数的数量.所求的限定条件往往与数位有关,例如 ...
- Codeforces Round #272 (Div. 2) B. Dreamoon and WiFi (暴力二进制枚举)
题意:给你一个只含\(+\)和\(-\)的字符串,统计它的加减和,然后再给你一个包含\(+,-,?\)的字符串,其中\(?\)可以表示为\(+\)或\(-\),问有多少种情况使得第二个字符串的加减和等 ...
- 使用cfssl生成自签证书
安装ssl wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 wget https://pkg.cfssl.org/R1.2/cfssljson_li ...
- 通过k8s部署dubbo微服务并接入ELK架构
需要这样一套日志收集.分析的系统: 收集 -- 能够采集多种来源的日志数据 (流式日志收集器) 传输 -- 能够稳定的把日志数据传输到中央系统 (消息队列) 存储 -- 可以将日志以结构化数据的形式存 ...
- springboot demo(一)快速开始
快速入门 maven构建项目 1.访问http://start.spring.io/ 2.选择构建工具Maven Project.Spring Boot版本2.26以及一些工程基本信息,点击" ...
- BZOJ3211 花神游历各国(分块 区间开根号)
题意:给n个数,可以进行两种操作:给区间[l,r]每个数开方向下取整:算区间[l,r]的和. 思路:我们可以知道,一个数一直开方下去,就会变成0或者1,然后就不会变了.那么当一个区间只剩0或1时,就不 ...
- Androidstudio 新GradlePlugin和Gradle Version对应关系
Project Gradle AS建议升级到4.2. Plugin对应AS的版本,Plugin工具也要和Gradle对应上,否则某些语法不支持,如果是非必要的建议不要轻易升级. Gradle DSL ...
- Node.js 文件上传 cli tools
Node.js 文件上传 cli tools byte stream 断点续传 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!
- js & document.designMode
js & document.designMode js 一键开启页面编辑模式 var mode = document.designMode; document.designMode = val ...
- GitHub Ribbons : 谈网站的安全性-资源链接如何 预防/实现 爬虫的批量下载!
GitHub Ribbons : 谈网站的安全性-资源链接如何 预防/实现 爬虫的批量下载! 预防方法: 1. 使用随机数字符串,拼接URL! https://camo.githubuserconte ...