用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。