@property 装饰器如何在 Python 中工作? [英] How does the @property decorator work in Python?
问题描述
我想了解内置函数 property
是如何工作的.令我困惑的是 property
也可以用作装饰器,但它仅在用作内置函数时才接受参数,而在用作装饰器时则不接受.
此示例来自文档:
C 类:def __init__(self):self._x = 无def getx(self):返回 self._xdef setx(self, value):self._x = 值def delx(自我):del self._xx = property(getx, setx, delx, 我是‘x’属性.")
property
的参数是 getx
、setx
、delx
和一个文档字符串.
在下面的代码中,property
用作装饰器.它的对象是 x
函数,但在上面的代码中,参数中没有对象函数的位置.
C 类:def __init__(self):self._x = 无@财产def x(self):"我是x"属性.""返回 self._x@x.setterdef x(self, value):self._x = 值@x.deleterdef x(self):del self._x
在这种情况下如何创建 x.setter
和 x.deleter
装饰器?
property()
函数返回一个特殊的 描述符对象:
>>>财产()<0x10ff07940处的属性对象>
正是这个具有额外方法的对象:
<预><代码>>>>属性().getter<0x10ff07998处的属性对象的内置方法getter>>>>属性().setter<0x10ff07940处的属性对象的内置方法设置器>>>>属性().deleter<0x10ff07998处的属性对象的内置方法删除器>这些也作为装饰器.他们返回一个新的属性对象:
<预><代码>>>>属性().getter(无)<0x10ff079f0处的属性对象>这是旧对象的副本,但替换了其中一个功能.
记住,@decorator
语法只是语法糖;语法:
@propertydef foo(self): 返回 self._foo
其实和
意思一样def foo(self): return self._foo富 = 财产(富)
so foo
函数被替换为 property(foo)
,我们上面看到的是一个特殊的对象.然后,当您使用 @foo.setter()
时,您所做的是调用我上面向您展示的 property().setter
方法,它返回属性,但这次用 setter 函数替换为装饰方法.
以下序列还通过使用这些装饰器方法创建了一个完整的属性.
首先,我们创建一些函数和一个 property
对象,只有一个 getter:
接下来我们使用.setter()
方法来添加一个setter:
最后我们使用 .deleter()
方法添加一个删除器:
最后但并非最不重要的是,property
对象充当 描述符对象,所以它有 .__get__()
, .__set__()
和 .__delete__()
挂钩实例属性获取、设置和删除的方法:
Descriptor Howto 包括 纯 Python 示例实现property()
类型:
class 属性:在 Objects/descrobject.c 中模拟 PyProperty_Type()"def __init__(self, fget=None, fset=None, fdel=None, doc=None):self.fget = fgetself.fset = fsetself.fdel = fdel如果 doc 是 None 并且 fget 不是 None:doc = fget.__doc__self.__doc__ = docdef __get__(self, obj, objtype=None):如果 obj 为 None:回归自我如果 self.fget 是 None:引发 AttributeError("不可读的属性")返回 self.fget(obj)def __set__(self, obj, value):如果 self.fset 是 None:引发 AttributeError("无法设置属性")self.fset(obj, value)def __delete__(self, obj):如果 self.fdel 是 None:raise AttributeError("无法删除属性")self.fdel(obj)def getter(self, fget):返回类型(self)(fget,self.fset,self.fdel,self.__doc__)def setter(self, fset):返回类型(self)(self.fget,fset,self.fdel,self.__doc__)def删除器(自我,fdel):返回类型(self)(self.fget,self.fset,fdel,self.__doc__)
I would like to understand how the built-in function property
works. What confuses me is that property
can also be used as a decorator, but it only takes arguments when used as a built-in function and not when used as a decorator.
This example is from the documentation:
class C:
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
's arguments are getx
, setx
, delx
and a doc string.
In the code below property
is used as a decorator. The object of it is the x
function, but in the code above there is no place for an object function in the arguments.
class C:
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
How are the x.setter
and x.deleter
decorators created in this case?
The property()
function returns a special descriptor object:
>>> property()
<property object at 0x10ff07940>
It is this object that has extra methods:
>>> 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>
These act as decorators too. They return a new property object:
>>> property().getter(None)
<property object at 0x10ff079f0>
that is a copy of the old object, but with one of the functions replaced.
Remember, that the @decorator
syntax is just syntactic sugar; the syntax:
@property
def foo(self): return self._foo
really means the same thing as
def foo(self): return self._foo
foo = property(foo)
so foo
the function is replaced by property(foo)
, which we saw above is a special object. Then when you use @foo.setter()
, what you are doing is call that property().setter
method I showed you above, which returns a new copy of the property, but this time with the setter function replaced with the decorated method.
The following sequence also creates a full-on property, by using those decorator methods.
First we create some functions and a property
object with just a 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
Next we use the .setter()
method to add a setter:
>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True
Last we add a deleter with the .deleter()
method:
>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True
Last but not least, the property
object acts as a descriptor object, so it has .__get__()
, .__set__()
and .__delete__()
methods to hook into instance attribute getting, setting and deleting:
>>> class Foo: pass
...
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!
The Descriptor Howto includes a pure Python sample implementation of the property()
type:
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__)
这篇关于@property 装饰器如何在 Python 中工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!