用decorator实现property方法探究


                                                1.  基础
built-in 函数 property([fget[, fset[, fdel[, doc]]]]): Return a property attribute for new-style classes (classes that
  derive from object).
>>> dir(property)
['__class__', '__delattr__', '__delete__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__set__', '__setattr__', '__str__', 'fdel', 'fget', 'fset']
范例代码:
class C(object):
    def __init__(self): self.__x = None
    def fget(self): return self._x
    def fset(self, value): self._x = value
    def fdel(self): del self._x
    x = property(fget, fset, fdel, "I'm the 'x' property.")
另外,由property的定义可知,用它作为decorator可实现以被修饰函数为名的只读属性。
class Parrot(object):
    def __init__(self):
        self._voltage = 100000
    @property
    def voltage(self):
        """Get the current voltage."""
        return self._voltage
2. 进阶
在上面的范例代码中,要实现完整的支持get,set,del的属性,需要在class范围内引入 getx等函数,
污染了locals字典并且需要x=property(...)语句。下面用decorator来实现:
(1)使用tuple def make_property( func ):
     return property( *func(),doc=func.__doc__ )
class C(object):
     def __init__(self):
         __x= 1
     @make_property
     def x():
         def fget(self): return self.__x
         def fset(self, value): self.__x = value
         def fdel(self): del self.__x
         return fget,fset,fdel
另一种定义如下(注意红色强调的代码中,unpack tuple时元素个数可能不足的情况的技巧):
def make_property(func):
    data = func()
    if not data:
        raise ValueError, "Invalid property descriptors"
    getter, setter, deller = (data + (None, None))[:3]
    return property(fget=getter, fset=setter, fdel=deller,
                    doc=func.__doc__)
(2)使用dict, 利用locals()
               
               
               
                def make_property( func ):
     return property( **func(),doc=func.__doc__ )
class A(object):
    def __init__(self, x, y):
        self.__x = x

    def x():
        def fget(self):return self.__x
        def fset(self, x): self.__x = x
        def fset(self, x): del self.__x
        return locals()
(3) 有人会疑惑:此中的x()为什么不必要是def x(self | cls)的形式呢。因为,一般的method在外部调用是都是clsObj.method() 或者instanceObj.method(), 执行时clsObj和instanceObj作为参数传给self | cls。而这里并不存在这种调用,It is only used as a container to hold the "real" methods。