为了账号安全,请及时绑定邮箱和手机立即绑定

@property装饰器在Python中如何工作?

@property装饰器在Python中如何工作?

千巷猫影 2021-03-29 09:17:05
我想了解内置函数的property工作原理。令我感到困惑的是,property它还可以用作装饰器,但仅在用作内置函数时才接受参数,而在用作装饰器时则不接受参数。这个例子来自文档: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的论点是getx,setx,delx和文档字符串。在下面的代码中property用作装饰器。它的对象是x函数,但是在上面的代码中,参数中没有对象函数的位置。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在这种情况下,x.setter和x.deleter装饰器是如何创建的?
查看完整描述

3 回答

?
三国纷争

TA贡献1804条经验 获得超7个赞

该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函数替换为装饰方法。


下面的序列还通过使用那些装饰器方法创建了一个全开属性。


首先,我们创建一些函数和一个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: 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__)


查看完整回答
反对 回复 2021-04-06
?
哆啦的时光机

TA贡献1779条经验 获得超6个赞

文档说,这只是创建只读属性的捷径。所以


@property

def x(self):

    return self._x

相当于


def getx(self):

    return self._x

x = property(getx)


查看完整回答
反对 回复 2021-04-06
  • 3 回答
  • 0 关注
  • 193 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号