@property装饰器如何工作?

本文翻译自:How does the @property decorator work?

I would like to understand how the built-in function property works. 我想了解内置函数property工作方式。 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. 令我感到困惑的是,该property还可以用作装饰器,但是仅当用作内置函数时才接受参数,而不能用作装饰器。

This example is from the 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.")

property 's arguments are getx , setx , delx and a doc string. property的参数是getxsetxdelx和doc字符串。

In the code below property is used as decorator. 在下面的代码中, property用作装饰器。 The object of it is the x function, but in the code above there is no place for an object function in the arguments. 它的对象是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

And, how are the x.setter and x.deleter decorators created? 而且,如何创建x.setterx.deleter装饰器? I am confused. 我很困惑。


#1楼

参考:https://stackoom.com/question/1AiMi/property装饰器如何工作


#2楼

Documentation says it's just a shortcut for creating readonly properties. 文档说这只是创建只读属性的捷径。 So 所以

@property
def x(self):
    return self._x

is equivalent to 相当于

def getx(self):
    return self._x
x = property(getx)

#3楼

The first part is simple: 第一部分很简单:

@property
def x(self): ...

is the same as 是相同的

def x(self): ...
x = property(x)
  • which, in turn, is the simplified syntax for creating a property with just a getter. 反过来,这是用于仅使用getter创建property的简化语法。

The next step would be to extend this property with a setter and a deleter. 下一步将使用设置器和删除器扩展此属性。 And this happens with the appropriate methods: 这是通过适当的方法发生的:

@x.setter
def x(self, value): ...

returns a new property which inherits everything from the old x plus the given setter. 返回一个新属性,该属性继承了旧x以及给定setter的所有内容。

x.deleter works the same way. x.deleter工作方式相同。


#4楼

The property() function returns a special descriptor object : property()函数返回一个特殊的描述符对象

>>> 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; 记住, @decorator语法只是语法糖; 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. 因此foo函数由property(foo)代替,我们在上面看到的是一个特殊的对象。 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. 然后,当您使用@foo.setter() ,您正在做的就是调用我在上面显示的那个property().setter方法,该方法将返回该属性的新副本,但是这次将setter函数替换为装饰方法。 。

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: 首先,我们仅使用一个吸气剂来创建一些函数和一个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

Next we use the .setter() method to add a setter: 接下来,我们使用.setter()方法添加一个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: 最后,我们使用.deleter()方法添加删除器:

>>> 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: 最后但并非最不重要的一点是, property对象充当描述符对象 ,因此它具有.__get__().__set__().__delete__()方法,可用于获取,设置和删除实例属性:

>>> 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: Descriptor Howto包括property()类型的纯Python示例实现

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

#5楼

Here is a minimal example of how @property can be implemented: 这是一个如何实现@property的最小示例:

class Thing:
    def __init__(self, my_word):
        self._word = my_word 
    @property
    def word(self):
        return self._word

>>> print( Thing('ok').word )
'ok'

Otherwise word remains a method instead of a property. 否则, word仍然是方法而不是属性。

class Thing:
    def __init__(self, my_word):
        self._word = my_word
    def word(self):
        return self._word

>>> print( Thing('ok').word() )
'ok'

#6楼

This following: 以下内容:

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

Is the same as: 是相同的:

class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, _x_set, _x_del, 
                    "I'm the 'x' property.")

Is the same as: 是相同的:

class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, doc="I'm the 'x' property.")
    x = x.setter(_x_set)
    x = x.deleter(_x_del)

Is the same as: 是相同的:

class C(object):
    def __init__(self):
        self._x = None

    def _x_get(self):
        return self._x
    x = property(_x_get, doc="I'm the 'x' property.")

    def _x_set(self, value):
        self._x = value
    x = x.setter(_x_set)

    def _x_del(self):
        del self._x
    x = x.deleter(_x_del)

Which is the same as : 等同于:

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
发布了0 篇原创文章 · 获赞 137 · 访问量 84万+

猜你喜欢

转载自blog.csdn.net/xfxf996/article/details/105344589
今日推荐