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. HttpWebRequest类,及如何使用Cookie(转载)

    HttpWebRequest类与HttpRequest类的区别.HttpRequest类的对象用于服务器端,获取客户端传来的请求的信息,包括HTTP报文传送过来的所有信息.而HttpWebReques ...

  2. ssh框架错误:org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role。

    在做ssh项目练习的时候出现问题: org.hibernate.LazyInitializationException: failed to lazily initialize a collectio ...

  3. hdu Exponentiation高精度实数乘幂(用了带小数的高精度模板)

    #include <cstdio> #include <cstring> #include <iostream> #include <cmath> #i ...

  4. Linux系统初学-第二课 linux基础知识

    一.用户与群组 Linux是多人多任务的操作系统,每个用户有一个主目录(或者叫家目录 /home),其他用户可以浏览,但是能否查看文件要看具体的权限设置.文件拥有者可以修改权限,选择是否允许其他用户进 ...

  5. Ubuntu 16.04 64位安装YouCompleteMe

    之前记录在OneNote上感觉有点乱,而且不适合保存shell,这次重新安装又出问题了,干脆写篇博客记录. 从零开始 1.git(用来下载vim和相关插件) sudo apt-get install ...

  6. Angularjs中的超时处理

    关键代码: // 定义一个定时器, 设置5s为请求超时时间 var timer = $timeout(function () { console.log('登录超时!'); // 模拟提示信息 },5 ...

  7. 嵌入式C语言自我修养 10:内联函数探究

    10.1 属性声明:noinline & always_inline 这一节,接着讲 __atttribute__ 属性声明,__atttribute__ 可以说是 GNU C 最大的特色.我 ...

  8. A.Activity planning

    题目描述There is a collection of n activities E={1,2,..,n}, each of which requires the same resource, su ...

  9. JQuery树插件——ztree

    API与Demo:http://www.treejs.cn/v3/api.php 使用插件,第一步依然是引入: <link rel="stylesheet" href=&qu ...

  10. 2017-2018-1 20155307《信息安全技术李冬冬》实验二——Windows口令破解

    2017-2018-1 <信息安全技术>实验二--Windows口令破解 所需工具: 试验系统:Windows 2003 实验工具:LC5.SuperDic 口令破解主要有两种方法:字典破 ...