我想了解内置函数property工作原理。令我困惑的是, property也可以用作装饰器,但它只在用作内置函数时才需要参数,而不是用作装饰器时。
这个例子来自文档 :
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.") property的参数是getx , setx , delx和 doc 字符串。
在下面的代码中, property用作装饰器。它的对象是x函数,但在上面的代码中,参数中没有对象函数的位置。
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x而且, x.setter和x.deleter装饰器是如何创建的?我很迷惑。
property()函数返回一个特殊的描述符对象 :
>>> property()
<property object at 0x10ff07940>这个对象有额外的方法:
>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>这些作为装饰过 。他们返回一个新的属性对象:
>>> property().getter(None)
<property object at 0x10ff079f0>这是旧对象的副本,但替换了其中一个函数。
请记住, @decorator语法只是语法糖; 语法:
@property
def foo(self): return self._foo真的意味着同样的事情
def foo(self): return self._foo
foo = property(foo)所以foo函数被property(foo)取代,我们在上面看到的是一个特殊的对象。然后当你使用@foo.setter() ,你正在做的就是调用我在上面给你看的property().setter方法,它返回一个属性的新副本,但是这次用 setter 函数替换了装饰方法。
以下序列还通过使用这些装饰器方法创建了一个完整的属性。
首先,我们使用 getter 创建一些函数和一个property对象:
>>> def getter(self): print 'Get!'
...
>>> def setter(self, value): print 'Set to {!r}!'.format(value)
...
>>> def deleter(self): print 'Delete!'
...
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True接下来我们使用.setter()方法添加一个 setter:
>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True最后我们使用.deleter()方法添加一个删除器:
>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True最后但并非最不重要的是, property对象充当描述符对象 ,因此它具有.__get__() , .__set__()和.__delete__()方法以挂钩到实例属性获取,设置和删除:
>>> class Foo(object): pass
...
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!描述符 Howto 包含property()类型的纯 python 示例实现 :
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
def x(self):
return self._x相当于
def getx(self):
return self._x
x = property(getx)
第一部分很简单:
@property
def x(self): ...是相同的
def x(self): ...
x = property(x)property的简化语法。 下一步是使用 setter 和 deleter 扩展此属性。这种情况发生在适当的方法:
@x.setter
def x(self, value): ...返回一个新属性,它继承旧x加上给定 setter 的所有内容。
x.deleter工作方式相同。