我想了解内置功能的property工作原理。令我感到困惑的是,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和文档字符串。
getx,setx,delx
在下面的代码中property用作装饰器。它的对象是x函数,但是在上面的代码中,参数中没有对象函数的位置。
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装饰器是如何创建的?我很困惑。
x.setter
x.deleter
该property()函数返回一个特殊的描述符对象:
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语法只是语法糖。语法:
@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函数替换为装饰方法。
property(foo)
property().setter
下面的序列还通过使用那些装饰器方法创建了一个全开属性。
首先,我们property仅使用getter 创建一些函数和一个对象:
getter
>>> 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:
.setter()方
setter
>>> prop = prop.setter(setter) >>> prop.fget is getter True >>> prop.fset is setter True >>> prop.fdel is None True
最后,我们使用以下.deleter()方法添加删除器:
.deleter()
>>> prop = prop.deleter(deleter) >>> prop.fget is getter True >>> prop.fset is setter True >>> prop.fdel is deleter True
最后但并非最不重要的一点是,该property对象充当描述符对象,因此具有和.__get__(),可以.__set__()与.__delete__()实例属性的获取,设置和删除方法挂钩:
__get__()
__set__()
__delete__()
>>> class Foo: pass ... >>> prop.__get__(Foo(), Foo) Get! >>> prop.__set__(Foo(), 'bar') Set to 'bar'! >>> prop.__delete__(Foo()) Delete!
Descriptor Howto包括以下类型的纯Python示例实现property():
class Property: "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__)