一文了解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的 ...
随机推荐
- python实现通过指定浏览器免费观看vip视频
程序是先通过一个解析视频的网站,然后我们提取其接口,然后实现观看vip视频的目的 所以说免费观看视频python程序很容易,但是下载视频就有些许麻烦了,下载视频请见我另一篇博客:python+fidd ...
- CodeForces - 1209D 并查集
题意: 有 n个不同的糖果,从 1到 n编号.有 k个客人.要用糖果招待客人.对于每个客人,这些糖果中恰有两个是其最爱.第 i个客人最爱的糖果编号是 xi和 y.将 k 个客人任意排列,他们按顺序去拿 ...
- 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 ...
- C++ string (浅谈)
浅谈string <string> typedef basic_string<char> string; 本篇主要内容是简单地介绍 string类 在竞赛方面较实用的一些功能, ...
- 【译】Async/Await(五)—— Executors and Wakers
原文标题:Async/Await 原文链接:https://os.phil-opp.com/async-await/#multitasking 公众号: Rust 碎碎念 翻译 by: Praying ...
- 整体算力提升40% 芯片级安全防护 | 阿里云发布第七代ECS云服务器
2 月 8 日,阿里云宣布推出第七代 ECS 云服务器产品家族,基于最新的神龙架构,相较于上一代整体算力提升 40%,容器部署密度最大可提升 6 倍,是最佳的云原生载体,此外全量搭载安全芯片,实现&q ...
- LINUX - 最简单的CS通信实例
服务端[编译:gcc server.c -o server] #include <stdio.h> #include <sys/socket.h> #include <s ...
- u-boot 移植 --->7、u-bootl流程粗线条梳理
通过前面的调试了解到s5pv210这个芯片的启动流程是需要将u-boot分为两部分的分别为SPL和u-boot.这里我使用网上的方式不直接使用u-boot的SPL连接脚本单独生成SPL的image而是 ...
- js load more select
js load more select searchable scroll load more append to list refs xgqfrms 2012-2020 www.cnblogs.co ...
- CSS Grid Layout In Action
CSS Grid Layout In Action CSS 异形网格布局实战 refs https://static-nginx-online.fbcontent.cn/tutor/tutor-ybc ...