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. javaEE中错误提示 Exception starting filter BackServletFilter java.lang.ClassNotFoundException: tmall.filter.BackServletFilter提示这个错误啊

    最近在学习javaEE的部署,不借助eclipse中的部署方式,而是通过修改server.xml文件的方式部署 添加Context路径 <Context path="/tm" ...

  2. [LuoguP3668][USACO17OPEN]现代艺术2

    [LuoguP3668][USACO17OPEN]Modern Art2(Link) 现在你有一块长为\(N\)的画布,每次可以选择一段连续的区间进行颜色填涂,新颜色会覆盖旧颜色.每一次填涂都要耗费一 ...

  3. 怎样实现一个简单的jQuery编程

    第一步:在head中载入jQuery框架 <script type="text/javascript"  src="jQuery文档所在的绝对路径"> ...

  4. ios开发遇到的问题

    运行后界面空白,Xcode跳转到APPDelegate.swift文件提示如下 第一种可能原因: 做输出口后在代码中重新命名了输出口 解决方法: 右键控件关闭输出口的连接,变回+号,将它重新连到代码的 ...

  5. C# WebClient Get获取网页内容

    //不知道怎么删除,只好留着 1. Get方式: WebClient web = new WebClient(); var html = web.DownloadString(url); 2. Pos ...

  6. http 协议状态码

    1xx   信息类状态码 100 - Continue 初始的请求已经接受,客户应当继续发送请求的其余部分.(HTTP 1.1新) 101 - Switching Protocols 服务器将遵从客户 ...

  7. [jQuery]常用正则表达式

    验证网址:^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$电子 ...

  8. 记录一下自己用jQuery写的轮播图

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  9. json数组按照日期先后排序

    var allMyApp = [ {"startDate": "2018-07-07 12:30:00",'name':'aa'}, {"startD ...

  10. linux 相关命令记录

    NetworkManager关闭及禁用 关闭:systemctl stop NetworkManager 禁用:systemctl disable NetworkManager 查看日志:journa ...