当前位置: 首页 > 面试题库 >

https://stackoverflow.com/questions/17330160/how-does-the-property-decorator-work-in-python

雍骏俊
2023-03-14
问题内容

我想了解内置函数的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的论点是getxsetxdelx和文档字符串。

在下面的代码中property用作装饰器。它的对象是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装饰器是如何创建的?


问题答案:

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


 类似资料:
  • Introduction This is the fifth part of the chapter that describes system calls mechanism in the Linux kernel. Previous parts of this chapter described this mechanism in general. Now I will try to desc

  • 问题内容: 我正在尝试使用Python 3中的Paramiko将特定文件从远程服务器发送到我的本地计算机。 背景:目标计算机198.18.2.2上有一个目录,其中包含许多以名称开头的时间戳目录2020… 目标机器: 源机器: 到目前为止,我已经设法构造了要执行的命令,如下所示: 码: 呼叫: 问题总是给我最新的时间戳文件夹。但是,如果该文件夹中没有该文件,我想查看具有该文件的下一个最新时间戳文件夹

  • 问题内容: 我下载了pip并运行python setup.py install,一切正常。本教程的下一步是运行,pip install 但是甚至在尝试在线查找任何内容之前,我都会收到错误消息“ bash:pip:not found”。 这是在Mac OS X上,这也是我的新手,因此我假设有些路径设置在我运行setup.py时未正确设置。我该如何进一步调查?我需要检查什么才能更好地了解问题的确切原因

  • 问题内容: 我已经使用PuTTYgen生成了密钥对,并使用Pageant进行了登录,因此在系统启动时,我只需输入一次密码。 如何在Linux中实现呢?我听说过,但听说它使用了不同的密钥对格式-我不想更改Windows密钥,如果我可以在Windows和Linux中以相同的方式无缝连接,那就太好了。 问题答案: puttygen支持将您的私钥导出为OpenSSH兼容格式。然后,您可以使用OpenSSH

  • 问题内容: 我想使用一个正则表达式来检查字符串是否仅包含大写和小写字母,数字和下划线。 问题答案: 要匹配仅包含这些字符的字符串(或空字符串),请尝试 这适用于.NET正则表达式,也可能适用于许多其他语言。 分解: 如果您不想允许使用空字符串,请使用+代替*。 正如其他人指出的那样,某些正则表达式语言具有的简写形式[a-zA-Z0-9_]。在.NET正则表达式语言中,您可以打开ECMAScript

  • 问题内容: There is some code I wanted to put into JSFiddle. It didn’t work. Narrowing it down I can’t even get this simplest of code to work: JSFiddle The box doesn’t show up in the JSFiddle. 问题答案: http:/