Python 有一个概念叫做 property,它能让你在 Python 的面向对象编程中轻松不少。在了解它之前,我们先看一下为什么 property 会被提出。

一个简单的例子
比如说你要创建一个温度的类Celsius,它能存储摄氏度,也能转换为华氏度。即:

如果你对python感兴趣,我这有个学习Python基地,里面有很多学习资料,感兴趣的+Q群:688244617class Celsius:def __init__(self, temperature = 0):self.temperature = temperaturedef to_fahrenheit(self):return (self.temperature * 1.8) + 32

我们可以使用这个类:

>>> # 创建对象 man
>>> man = Celsius()>>> # 设置温度
>>> man.temperature = 37>>> # 获取温度
>>> man.temperature
37>>> # 获取华氏度
>>> man.to_fahrenheit()
98.60000000000001

最后额外的小数部分是浮点误差,属于正常现象,你可以在 Python 里试一下 1.1 + 2.2。

在 Python 里,当我们对一个对象的属性进行赋值或估值时(如上面的temperature),Python 实际上是在这个对象的 __dict__字典里搜索这个属性来操作。

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

因此,man.temperature实际上被转换成了man.dict[‘temperature’]。

假设我们这个类被程序员广泛的应用了,他们在数以千计的客户端代码里使用了我们的类,你很高兴。

突然有一天,有个人跑过来说,温度不可能低于零下273度,这个类应该加上对温度的限制。这个建议当然应该被采纳。作为一名经验丰富的程序员,你立刻想到应该使用 setter 和 getter 来限制温度,于是你将代码改成下面这样:

class Celsius:def __init__(self, temperature = 0):self.set_temperature(temperature)def to_fahrenheit(self):return (self.get_temperature() * 1.8) + 32# 更新部分def get_temperature(self):return self._temperaturedef set_temperature(self, value):if value < -273:raise ValueError("Temperature below -273 is not possible")self._temperature = value

很自然地,你使用了“私有变量”_temperature来存储温度,使用get_temperature()和set_temperature()提供了访问_temperature的接口,在这个过程中对温度值进行条件判断,防止它超过限制。这都很好。

问题是,这样一来,使用你的类的程序员们需要把他们的代码中无数个obj.temperature = val改为obj.set_temperature(val),把obj.temperature改为obj.get_temperature()。这种重构实在令人头痛。

所以,这种方法不是“向下兼容”的,我们要另辟蹊径。

@property 的威力!
想要使用 Python 哲学来解决这个问题,就使用 property。直接看代码:

class Celsius:def __init__(self, temperature = 0):self.temperature = temperaturedef to_fahrenheit(self):return (self.temperature * 1.8) + 32def get_temperature(self):print("Getting value")return self._temperaturedef set_temperature(self, value):if value < -273:raise ValueError("Temperature below -273 is not possible")print("Setting value")self._temperature = value
# 重点在这里
temperature = property(get_temperature,set_temperature)

我们在class Celsius的最后一行使用了一个 Python 内置函数(类) property()。它接受两个函数作为参数,一个 getter,一个 setter,并且返回一个 property 对象(这里是temperature)。

这样以后,任何访问temperature的代码都会自动转而运行get_temperature(),任何对temperature赋值的代码都会自动转而运行set_temperature()。我们在代码里加了print()便于测试它们的运行状态。


>>> c = Celsius()  # 此时会运行 setter,因为 __init__ 里对 temperature 进行了赋值
Setting value>>> c.temperature  # 此时会运行 getter,因为对 temperature 进行了访问
Getting value

需要注意的是,实际的温度存储在_temperature里,temperature只是提供一个访问的接口。

深入了解 Property
正如之前提到的,property()是 Python 的一个内置函数,同时它也是一个类。函数签名为:

property(fget=None, fset=None, fdel=None, doc=None)
其中,fget是一个 getter 函数,fset是一个 setter 函数,fdel是删除该属性的函数,doc是一个字符串,用作注释。函数返回一个 property 对象。

一个 property 对象有 getter()、setter()和deleter()三个方法用来指定相应绑定的函数。之前的

temperature = property(get_temperature,set_temperature)
实际上等价于

# 创建一个空的 property 对象
temperature = property()
# 绑定 getter
temperature = temperature.getter(get_temperature)
# 绑定 setter
temperature = temperature.setter(set_temperature)
这两个代码块等价。

熟悉 Python 装饰器的程序员肯定已经想到,上面的 property 可以用装饰器来实现。

通过装饰器@property,我们可以不定义没有必要的 get_temperature()和set_temperature(),这样还避免了污染命名空间。使用方式如下:

class Celsius:def __init__(self, temperature = 0):self._temperature = temperaturedef to_fahrenheit(self):return (self.temperature * 1.8) + 32# Getter 装饰器@propertydef temperature(self):print("Getting value")return self._temperature# Setter 装饰器@temperature.setterdef temperature(self, value):if value < -273:raise ValueError("Temperature below -273 is not possible")print("Setting value")self._temperature = value

你可以使用装饰器,也可以使用之前的方法,完全看个人喜好。但使用装饰器应该是更加 Pythonic 的方法吧。

Python @property 详解相关推荐

  1. python装饰器setter_第7.27节 Python案例详解: @property装饰器定义属性访问方法getter、setter、deleter...

    上节详细介绍了利用@property装饰器定义属性的语法,本节通过具体案例来进一步说明. 一.    案例说明 本节的案例是定义Rectangle(长方形)类,为了说明问题,除构造函数外,其他方法都只 ...

  2. Python Class 详解

    Python Class 详解 1.基本概念 1.1 类 `class` 1.2 对象 `instance / object` 1.3 面向对象三要素 1.4 哲学思想 2.类 2.1 类的定义 2. ...

  3. python区块链开发_Fabric区块链Python开发详解

    Hyperledger Fabric是最流行的联盟区块链平台.Fabric区块链Python开发详解课程 涵盖Fabric区块链的核心概念.Fabric网络搭建.Node链码开发.Python应用开发 ...

  4. 【python】详解类class的继承、__init__初始化、super方法

    原文链接; https://blog.csdn.net/brucewong0516/article/details/79121179?utm_medium=distribute.pc_relevant ...

  5. python与golang_Golang与python线程详解及简单实例

    Golang与python线程详解及简单实例 在GO中,开启15个线程,每个线程把全局变量遍历增加100000次,因此预测结果是 15*100000=1500000. var sum int var ...

  6. python 最小二乘法_最小二乘法及其python实现详解

    最小二乘法Least Square Method,做为分类回归算法的基础,有着悠久的历史(由马里·勒让德于1806年提出).它通过最小化误差的平方和寻找数据的最佳函数匹配.利用最小二乘法可以简便地求得 ...

  7. Objective-C中的@Property详解

    Objective-C中的@Property详解 @Property (属性) class vairs 这个属性有nonatomic, strong, weak, retain, copy等等 我把它 ...

  8. 【python】详解multiprocessing多进程-Pool进程池模块(二)

    [python]详解multiprocessing多进程-process模块(一) [python]详解multiprocessing多进程-Pool进程池模块(二) [python]详解multip ...

  9. 【python】什么是序列,Python序列详解

    什么是序列,Python序列详解 概述 序列索引 序列切片 序列相加 序列相乘 检查元素是否包含在序列中 序列相关的内置函数 range 快速初始化数字列表 概述 所谓序列,指的是一块可存放多个值的连 ...

最新文章

  1. 科研与爱情选谁?中科院教授教你平衡!
  2. Tensorflow—交叉熵
  3. Java IO 体系(三):Reader与Writer
  4. Azure正式对外发布容器服务,支持Swarm和Mesos
  5. 反查BOM, 找出它的上阶
  6. Linux 线程属性的使用
  7. kaggle中安装lightgbm的gpu版本
  8. 宣布EAXY:在Java中简化XML
  9. 小学计算机课评课用语,信息技术评课心得
  10. 买书动态规划java_《编程之美》买书问题——动态规划
  11. mac下发html邮件的方法
  12. SQL语句写起来太繁琐?你可以试试 MyBatis “动态” SQL
  13. 【LM】windows7 内部版本7601,此windows副本不是正版——已解决
  14. [个人笔记] ssh-keygen和openssl工具的使用
  15. three实战:月球围绕地球
  16. 公众号扫描二维码(前端uniapp、后端java)
  17. 机器人主要有哪几部分组成?
  18. ubuntu 开机启动 ibus 输入法
  19. iqooneo3 如何不用vivo账号下载外部应用_你说iQOO Neo 3很香?抱歉,我有不同的意见...
  20. Angular2 ElementRef 实现低耦合高内聚 视图应用分离

热门文章

  1. 知识图谱嵌入经典方法(Trans系列、KG2E)
  2. 移动开发中一些bug及解决方案
  3. 利用kettle HTTP Client 获取百度API区域位置内相关信息,并解析json
  4. 数睿数据深度 | 关于软件自主可控,源代码向左,无代码向右
  5. cad高程测绘图lisp_已知CAD中的高程测绘图,很多点,如何求出所有高程的平均值呢?难道只能用计算器一个一个的相加来算吗?...
  6. linux怎么配置yolo环境,【项目实战】 YOLOv5 安装配置及简单使用
  7. 如何为你的 Windows 应用程序关联一种或多种文件类型
  8. dspace安装及应用
  9. MT40A1G16KH-062E AIT内存MT40A1G16KH-062E AUT
  10. Navicat Premium 15 完全卸载