Python Descriptor 

1, Python Descriptor是这样一个对象

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

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

这样的对象就是一个descriptor

2, descriptor的特性

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

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

class T(object):
    pass

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

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

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

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

内置函数 property()

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

class Test(object):
    def getx(self):
           return self._x
    def setx(self, v):
           self._x = v
    def deletex(self):
           del self._x

    x = property(getx, setx, deletex, ''' __doc__''')

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

class Test(object):
    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, v):
        self._x = v

    @x.deleter
    def x(self):
        del self._x

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

t = Test()
t.x = 5
print t.x
del t.x

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

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

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

class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        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. java 跨域

    jsonp做前端跨域需要服务器的支持的,造成json字符串前缀 var a=...或者 a[].... 实在有点麻烦,故还是后台跨域取数据好了 package com.pro.domain; impo ...

  2. Unity3D绑定button监听事件

    一.可视化创建及事件绑定 第一步:通过Hierarchy面板创建button,如图 第二步:创建一个脚本名为TestClick,并定义一个名为Click的public方法 ? 1 2 3 4 5 6 ...

  3. XAMPP端口占用启动不了

    skype默认会占用80和443端口 如果在apache之前启动skype,apache就会启动不了了!! 解决办法很简单: 1. 先启动apache再启动skype,这样skype就会换其他的端口监 ...

  4. nginx 从vagant挂载目录中加载nginx.conf配置进行开机启动

    nginx从vagrant挂载目录中读取配置启动,将nginx加入开机启动项!开机启动的时候nginx会因为加载不了配置导致启动失败! 原因是开机启动nginx服务在vagrant挂载之前,导致无法正 ...

  5. opencv学习笔记(二)寻找轮廓

    opencv学习笔记(二)寻找轮廓 opencv中使用findContours函数来查找轮廓,这个函数的原型为: void findContours(InputOutputArray image, O ...

  6. 2015湖南省选集训DAY5——work(BZOJ4177)

    Description Mike有一个农场,这个农场n个牲畜围栏,如今他想在每一个牲畜围栏中养一仅仅动物,每仅仅动物能够是牛或羊,并且每一个牲畜围栏中的饲养条件都不同,当中第i个牲畜围栏中的动物长大后 ...

  7. cakephp 的事件系统(Getting to grips with CakePHP’s events system), 基于观察者模式

    This article was written about CakePHP 2.x and has been untested with CakePHP 3.x CakePHP seems to g ...

  8. Python sort后赋值 操作陷阱

    x=[1,4,2,0] # 错误的方式,因为sort没有返回值 y=x.sort() type (y) #NoneType #正确的方式 x.sort() y=x[:]

  9. Robot Framework + Pywinauto 框架实现Windows GUI Automation

    Robot Framework is a generic test automation framework for acceptance testing and acceptance test-dr ...

  10. 模拟stringBeanFactory解析xml

    思路:根据源码分析,将配置Bean类信息存放到xml文件中,通过解析xml, 然后反射拿到对象 存放到集合中 这里选择hashmap(键放置类名,值放置对象)存放,使用时使用get方法通过键(类名)拿 ...