@property decorator是如何工作的?

  • 问题:
  • 我想了解内置函数属性是如何工作的。让我困惑的是,属性也可以用作装饰器,但它只接受作为内置函数使用的参数,而不是用作装饰器时的参数

    此示例来自documentation公司名称:

    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.")

    属性的参数是getxsetxdelx和一个doc字符串

    在下面的代码中,属性用作修饰符。它的对象是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.setterx.deleter装饰器是如何创建的?

  • 答案:
  • property()函数返回一个特殊的descriptor object公司名称:

    >>> 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函数替换为decorated方法

    下面的序列还通过使用这些decorator方法创建一个full-on属性

    首先,我们使用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:

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

    最后但并非最不重要的是,属性对象充当descriptor object,所以它有,\uu get\uuu(),\uu set\uu9()>挂接实例属性获取、设置和删除的方法:

    >>> class Foo: pass
    ...
    >>> prop.__get__(Foo(), Foo)
    Get!
    >>> prop.__set__(Foo(), 'bar')
    Set to 'bar'!
    >>> prop.__delete__(Foo())
    Delete!

    描述符Howto包括pure Python sample implementation属于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__)