zoukankan      html  css  js  c++  java
  • Python descriptor 以及 内置property()函数

    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

  • 相关阅读:
    Android布局控件
    XAMPP里tomcat启动报错:Make sure you have Java JDK or JRE installed and the required ports are free
    poj 北京大学 2014研究生推免上机考试(校内)
    2014北大计算机学科保研直博夏令营上机poj考试
    《C++Primer》第四版学习笔记--持续更新中
    poj1986:Distance Queries
    poj2533:最长上升子序列
    poj1062:昂贵的聘礼
    黑书贪心例题之钓鱼 poj1042:Gone Fishing
    转:最小没出现的整数
  • 原文地址:https://www.cnblogs.com/livingintruth/p/3601861.html
Copyright © 2011-2022 走看看