Python Descriptor 

1, Python Descriptor是这样一个对象

它按照descriptor协议, 有这样的属性之一

  1. def __get__(self, obj, type=None) # 会返回一个value
  2. def __set__(self, obj, value) # 返回None
  3. def __delete__(self, obj) # 返回None

这样的对象就是一个descriptor

2, descriptor的特性

假若有一个对象t, 我们去引用它的一个属性a

  1. t.a

但是发现a是一个descriptor

那么不会返回a, 而是会去调用a相应的__get__, __set__, __delete__

那么什么情况调用那个呢?如下

  • v = t.a   <---->   v = __get__(a, t)
  • t.a = v   <----->  __set__(a, t, v)
  • del t.a   <----->  __delete__(a, t)

3, descriptor是如何实现的

只有new-style objects或class的属性在被引用时,descriptor的特性才能起作用

从 object 派生的类就是 new-style class

  1. class T(object):
  2. pass

那么这大概是怎么回事呢?

是因为object有__getattribute__属性, 这个属性的实现确保了descriptor机制

所以如果我们重写了__getattribute__, 那么就可以消除descriptor机制

__getattribute__是如何实现的,以后探讨, 参考2中有一点点例子

内置函数 property()

Python有内置property()函数, 它可以直接做函数,也可以用来做装饰器, 它的使用方式如下, 例子来自参考3

  1. class Test(object):
  2. def getx(self):
  3. return self._x
  4. def setx(self, v):
  5. self._x = v
  6. def deletex(self):
  7. del self._x
  8.  
  9. x = property(getx, setx, deletex, ''' __doc__''')

而上面的代码等价于下面的

  1. class Test(object):
  2. @property
  3. def x(self):
  4. return self._x
  5.  
  6. @x.setter
  7. def x(self, v):
  8. self._x = v
  9.  
  10. @x.deleter
  11. def x(self):
  12. del self._x

对于Test的x属性,可以这么用

  1. t = Test()
  2. t.x = 5
  3. print t.x
  4. del t.x

那么为什么property()可以这么用,尤其是第二种中, x.setter和 x.deleter还可以做装饰器呢?

首先我们要先明白装饰器是什么

property()会返回一个Property对象, 然后我们来看一个用Python模拟的Property类的实现,  摘自参考1

  1. class Property(object):
  2. "Emulate PyProperty_Type() in Objects/descrobject.c"
  3.  
  4. def __init__(self, fget=None, fset=None, fdel=None, doc=None):
  5. self.fget = fget
  6. self.fset = fset
  7. self.fdel = fdel
  8. if doc is None and fget is not None:
  9. doc = fget.__doc__
  10. self.__doc__ = doc
  11.  
  12. def __get__(self, obj, objtype=None):
  13. if obj is None:
  14. return self
  15. if self.fget is None:
  16. raise AttributeError("unreadable attribute")
  17. return self.fget(obj)
  18.  
  19. def __set__(self, obj, value):
  20. if self.fset is None:
  21. raise AttributeError("can't set attribute")
  22. self.fset(obj, value)
  23.  
  24. def __delete__(self, obj):
  25. if self.fdel is None:
  26. raise AttributeError("can't delete attribute")
  27. self.fdel(obj)
  28.  
  29. def getter(self, fget):
  30. return type(self)(fget, self.fset, self.fdel, self.__doc__)
  31.  
  32. def setter(self, fset):
  33. return type(self)(self.fget, fset, self.fdel, self.__doc__)
  34.  
  35. def deleter(self, fdel):
  36. return type(self)(self.fget, self.fset, fdel, self.__doc__)

认真看看就明白了

  • Property对象是Descriptor
  • Property.setter 和 Property.deleter 都是装饰器,他们和property一样,都是返回Property()对象,不同的是 @property设置 fget ,  setter和 deleter分别设置 fset, 和 fdel

-----------------------------------

很好的学习参考:

1, http://stackoverflow.com/questions/17330160/python-how-does-decorator-property-work

2, http://docs.python.org/3.2/howto/descriptor.html

3, http://docs.python.org/3.2/library/functions.html#property

Python descriptor 以及 内置property()函数的更多相关文章

  1. python 中的内置高级函数

    1.map(function,iterable) map是把迭代对象依次进行函数运算,并返回. 例子: map返回的十分map对象,需要list()函数转化. 2.exec()函数 执行储存在字符串或 ...

  2. python 常见的内置函数

    内置函数 接下来,我们就一起来看看python里的内置函数.截止到python版本3.6.2,现在python一共为我们提供了68个内置函数.它们就是python提供给你直接可以拿来使用的所有函数.这 ...

  3. python之路——内置函数和匿名函数

    阅读目录 楔子 内置函数 匿名函数 本章小结 楔子 在讲新知识之前,我们先来复习复习函数的基础知识. 问:函数怎么调用? 函数名() 如果你们这么说...那你们就对了!好了记住这个事儿别给忘记了,咱们 ...

  4. python学习交流 - 内置函数使用方法和应用举例

    内置函数 python提供了68个内置函数,在使用过程中用户不再需要定义函数来实现内置函数支持的功能.更重要的是内置函数的算法是经过python作者优化的,并且部分是使用c语言实现,通常来说使用内置函 ...

  5. python常用的内置函数哈哈

    python常用的内置函数集合做一个归类用的时候可以查找 abs 返回数字x的绝对值或者x的摸 all (iterable)对于可迭代的对象iterable中所有元素x都有bool(x)为true,就 ...

  6. python常用的内置函数

    python常用的内置函数集合做一个归类用的时候可以查找- abs 返回数字x的绝对值或者x的摸 - all (iterable)对于可迭代的对象iterable中所有元素x都有bool(x)为tru ...

  7. 十六. Python基础(16)--内置函数-2

    十六. Python基础(16)--内置函数-2 1 ● 内置函数format() Convert a value to a "formatted" representation. ...

  8. 十五. Python基础(15)--内置函数-1

    十五. Python基础(15)--内置函数-1 1 ● eval(), exec(), compile() 执行字符串数据类型的python代码 检测#import os 'import' in c ...

  9. Python的常用内置函数介绍

    Python的常用内置函数介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.取绝对值(abs) #!/usr/bin/env python #_*_coding:utf-8_ ...

随机推荐

  1. hdu5955 Guessing the Dice Roll【AC自动机】【高斯消元】【概率】

    含高斯消元模板 2016沈阳区域赛http://acm.hdu.edu.cn/showproblem.php?pid=5955 Guessing the Dice Roll Time Limit: 2 ...

  2. 如何取消一个目录的git初始化

    一不小心把我的整个home目录都初始化为git仓库了,通过执行删除.git命令,可以恢复 rm -rf .git

  3. PyQT5-QCheckBox按钮

    """ QcheckBox:单选框有两种状态:开和关.通常跟标签一起使用,用在一些激活或者关闭的场景 Author:dengyexun DateTime:2018.11. ...

  4. Bitwise and Bit Shift Operators 位运算 取反 补码

    Bitwise and Bit Shift Operators (The Java™ Tutorials > Learning the Java Language > Language B ...

  5. vue - vue-cli脚手架安装和webpack-simple模板项目生成

    ue-cli 是一个官方发布 vue.js 项目脚手架,使用 vue-cli 可以快速创建 vue 项目. GitHub地址是:https://github.com/vuejs/vue-cli 一.安 ...

  6. Mysql 时间类型精度截取的bug

    mysql-connector-java版本升级出现的一次问题.涉及到了时间精度的截取和四舍五入. 首先了解一点,timestamp,datetime如果不指定精度,默认的精度是秒. 当mysql-c ...

  7. IO流(4)重命名

    重命名功能:public boolean renameTo(File dest) * 如果路径名相同,就是改名. * 如果路径名不同,就是改名并剪切. * * 路径以盘符开始:绝对路径 c:\\a.t ...

  8. 【Python】如何切换浏览器的tap页?

    当点击浏览器当前页面中的某个链接后自动弹出一个新的浏览器的tap页面时,浏览器正常都会在当前操作的tap页面右1位置打开新弹出的tap页. 当前selenium还不具备自动切换页面后窗口切换功能.需要 ...

  9. Shell中的表达式及IF

    #!/bin/bash #你值得收藏的四则表达式运算. val1=1 val2=1 val3=1 val4=1 val5=1 val6=1 val7=1 let val1++ ((val2++)) v ...

  10. 8 jmeter之集合点

    集合点:集合点用以同步虚拟用户,以便恰好在同一时刻执行任务.在测试计划中,可能会要求系统能够承受1000 人同时提交数据,在LoadRunner 中可以通过在提交数据操作前面加入集合点,这样当虚拟用户 ...