property

property装饰器的应用来自这样一个问题:如果对实例的属性值不加以限制,那么实例的属性值会出现明显不合理的情况,为了解决这个问题也许你会思考在对属性的修改时利用实例方法加以限制,但python中引入了@property 装饰器更方便的解决这个问题。

class Person(object):
def __init__(self, age=1):
self.age = age
p = Person()
p.age = -1 # 这显然是不合理的
class Person(object):
def __init__(self):
self._age = 1 # 私有属性,外部无法直接修改和访问 def age_setter(self, age):
if 0 < age < 120 and isinstance(age, int):
self._age = age
else:
raise ValueError('age must between 0-120 and be integer')
def age_getter(self):
return self._age
# 这时虽然做到了属性值的控制,但是每次设置和获取值的时候要调用不同的方法,不太方便

@property 装饰器兼顾了方便和控制,让实例的使用显得更加优雅,提高了可用性。另外,@property装饰器不设置setter时,就是一个只读属性,相当于对属性起到了保护作用,如下实验

class Person(object):
def __init__(self):
self._height = 1 @property # 这里就是height的getter
def height(self):
return self._height @height.setter
def height(self, height):
if 0 < height < 220 and isinstance(height, int):
self._height = height
else:
raise ValueError('height must between 0-220 and be an integer') @property
def normal_weight(self):
return round(22.86*(self.height/100)**2*2, 2) p = Person()
p.height = 190
print(p.height)
print(p.normal_weight)
------ 结果 ——————
190
165.05

__set__ 和 _get_

理解set和get方法,实际上必须知道描述器是什么,成为一个描述器,一个类必须至少有__get____set____delete__方法被实现。如果一个对象同时定义了 __get__()__set__(),它叫做资料描述器(data descriptor)。仅定义了 __get__() 的描述器叫非资料描述器(non-data descriptor)。

__get__(self, obj, type=None) --> value
定义了当描述器的值被取得的时候的行为。instance是拥有该描述器对象的一个实例。owner是拥有者本身
__set__(self, obj, value) --> None
定义了当描述器的值被改变的时候的行为。instance是拥有该描述器类的一个实例。value是要设置的值。
__delete__(self, instance) --> None
定义了当描述器的值被删除的时候的行为。instance是拥有该描述器对象的一个实例。

几个注意事项:资料描述器的执行顺序优先于实例字典,而实例字典的执行顺序优先于非资料描述器,重写getattribute可能会阻止描述器的使用。关于属性查找优先顺序的问题,后面会写一篇博客描述和实验,这里不重复。

class Descriptor:
def __get__(self, instance, owner):
print('1 get called,', 'instance is', instance, ',owner is', owner)
return instance._a def __set__(self, instance, value):
print('2 set called,', 'instance is', instance, ',value is', value)
instance._a = value * 2 class T:
desc = Descriptor() # 类方法
def __init__(self):
self._a = 123 t = T()
t.desc = 5
print('result:', t.desc)

其实这里的使用已经很像@property了,但@property则更加简单方便。

--------结果------------
2 set called, instance is <__main__.T object at 0x00000182D90DC630> ,value is 5
1 get called, instance is <__main__.T object at 0x00000182D90DC630> ,owner is <class '__main__.T'>
result: 10

描述器协议是一个理解python内部机制的知识点,属性(property), 方法(bound和unbound method), 静态方法和类方法都是基于描述器协议的。

参考:

https://pyzh.readthedocs.io/en/latest/Descriptor-HOW-TO-Guide.html

https://blog.csdn.net/huithe/article/details/7484606

python-property、__get__、__set__的更多相关文章

  1. python的__get__、__set__、__delete__(1)

    内容:    描述符引导        摘要        定义和介绍        描述符协议        调用描述符        样例        Properties        函数和 ...

  2. python 面向对象专题(八):特殊方法 (一)__get__、__set__、__delete__ 描述符(一)

    https://www.cnblogs.com/flashBoxer/p/9771797.html 实现了 __get__.__set__ 或 __delete__ 方法的类是描述符.描述符的用法是, ...

  3. python 面向对象专题(十一):特殊方法 (四)__get__、__set__、__delete__ 描述符(四)描述符用法建议

    使用特性以保持简单 内置的 property 类创建的其实是覆盖型描述符,__set__ 方法和__get__ 方法都实现了,即便不定义设值方法也是如此. 特性的__set__ 方法默认抛出 Attr ...

  4. python 面向对象专题(九):特殊方法 (二)__get__、__set__、__delete__ 描述符(二)覆盖型与非覆盖型描述符对比

    前言 根据是否定义__set__ 方法,描述符可分为两大类. 实现 __set__ 方法的描述符属于覆盖型描述符,因为虽然描述符是类属性,但是实现 __set__ 方法的话,会覆盖对实例属性的赋值操作 ...

  5. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

     1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...

  6. python 3全栈开发-面向对象之绑定方法(classmethod与staticmethod的区别)、多态、封装的特性property

    一.面向对象绑定方法 一.类中定义的函数分成两大类 1.绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入): 1. 绑定到类的方法:用classmethod装饰器装饰的方法. 为类量身定制 ...

  7. python基础-abstractmethod、__属性、property、setter、deleter、classmethod、staticmethod

    python基础-abstractmethod.__属性.property.setter.deleter.classmethod.staticmethod

  8. 【Python】__slots__ 、@property、多重继承、定制类、枚举类、元类

    __slots__ @property 多重继承 定制类 枚举类 元类 [使用__slots__] 1.动态语言的一个特点就是允许给实例绑定任意的方法和变量,而静态语言(例如Java)必须事先将属性方 ...

  9. 第7.26节 Python中的@property装饰器定义属性访问方法getter、setter、deleter 详解

    第7.26节 Python中的@property装饰器定义属性访问方法getter.setter.deleter 详解 一.    引言 Python中的装饰器在前面接触过,老猿还没有深入展开介绍装饰 ...

随机推荐

  1. 关于日期的一些常用方法的封装——dates.js

    针对自己在日常用到的一些日期方法,整理成一个js日期插件,插件定义了一个dates全局对象,继承了Date函数,相当于在Date函数上做了一些扩展. 这个插件会不断更新,所有我之后用到的关于日期的自定 ...

  2. LCG(linear congruential generator): 一种简单的随机数生成算法

    目录 LCG算法 python 实现 LCG算法 LCG(linear congruential generator)线性同余算法,是一个古老的产生随机数的算法.由以下参数组成: 参数 m a c X ...

  3. .NET Core中NETSDK1061错误解决(转载)

    NETSDK1061错误解决 在vs生成和运行都正常,发布的时候报错 .netcore控制台项目引用另一个类库 错误信息 NETSDK1061: 项目是使用 Microsoft.NETCore.App ...

  4. iOS开发Mac配置(CocoaPods、SourceTree、ssh key)

    作为开发,有一个自己的饭碗还是有必要的.因为交接旧电脑的时候,你会遇到了一些问题,而自己的电脑就方便很多了. 要开发,当然要装一些与开发相关的东西,那么新电脑入手,要做些什么呢? 1.安装Xcode: ...

  5. Qt绘制动态曲线

    首先*.pro文件中加一句 QT += charts 然后 mainwindow.cpp文件如下: #include "mainwindow.h" #include "u ...

  6. mac 下安装php7.1 redis

    1.下载phpredis源文件 https://nodeload.github.com/nicolasff/phpredis/zip/master 下载后解压 2.执行命令 phpize  执行后执行 ...

  7. thinkphp5查询表达式IN使用小计

    根据多个id批量更新指定字段值 $map[] = ['id','in', input('post.id/a')]; $result = db('picture')->where($map)-&g ...

  8. 大专生自学php到找到工作的前前后后

    先做个自我介绍,我13年考上一所很烂专科民办的学校,学的是生物专业,具体的学校名称我就不说出来献丑了.13年我就辍学了,我在那样的学校,一年学费要1万多,但是根本没有人学习,我实在看不到希望,我就退学 ...

  9. Delphi的FIFO实现

    FIFO主要用于多个不同线程或进程之间数据交换时做缓冲区用,尤其适合实时数据通讯应用中的数据缓冲,接收线程(进程)将数据写入FIFO,处理线程(进程)从FIFO取出数据 本单元中: TMemoryFI ...

  10. 欧几里得算法/欧几里得扩展算法-python

    说在开头. 出于对欧几里得的尊重,先简单介(cou)绍(ge)一(zi)下(shu).. 欧几里得,古希腊人,数学家.他活跃于托勒密一世时期的亚历山大里亚,被称为“几何之父”. 他最著名的著作< ...