【问题标题】:Is it possible to pass a @property to a predefined function such that the property's underlying method is invoked when the function uses it?是否可以将@property 传递给预定义的函数,以便在函数使用它时调用属性的底层方法?
【发布时间】:2017-07-30 00:42:16
【问题描述】:

我很好奇 Python 3 中的 @property 注释。

我知道我可以在调用这样的属性之间操纵状态...

class Obj:
    _x = 0
    @property
    def x(self):
        self._x += 1
        return self._x

obj = Obj()
print(obj.x)
print(obj.x)

... 打印:

1
2

但是,这种机制在传递给函数后是否可以保留?

取如下函数:

def f(x):
    print(x)
    print(x)

假设我们无法更改它,这意味着我们不能简单地将对象传递给函数并直接使用属性。是否可以只传递属性或类似的东西,这样每次x 在函数x 中“使用”时都会增加?有没有办法通过操纵和传递类或对象本身来做到这一点?类似于__call__(self, ...) 的东西,或者将@property 添加到类本身或类的__init__(self, ...) 中?

我尝试了以下幼稚的方法...

obj = Obj()
f(obj.x)

...和...

obj = Obj()
f(getattr(obj, 'x'))

都打印...

1
1

... 这是有意义的,因为它在传递给f 之前被评估。我也尝试扩展Obj

class Obj:
    _x = 0
    @property
    def x(self):
        self._x += 1
        return self._x
    def y(self):
        return x

...然后去...

obj = Obj()
f(obj.y)

...但它会产生...

<bound method Obj.y of <__main__.Obj object at 0x000002379E015748>>
<bound method Obj.y of <__main__.Obj object at 0x000002379E015748>>

这也很有意义,因为我们只是获取方法本身并将其传递给f 函数。

请注意:这不是现实世界的问题/示例。我只是想了解python本身的原理和局限性。

【问题讨论】:

  • 属性为descriptors。注意,实际发生的是当你访问obj.x时,本质上是Obj.x.__get__(obj, Obj)
  • 每当我们在上面的装饰器类中分配或检索像x 这样的任何对象属性时,Python 都会在对象的 dict 字典中搜索它。尝试obj.__dict__ 自己查看,它会返回{'_x': 3}。同样type(obj.x) 将返回int,而不是method

标签: python python-3.x properties


【解决方案1】:

property() 包装器是 descriptor,这意味着它只能通过点分访问调用,例如 a.x,而不是通过普通变量访问。

要触发仅使用变量引用的方法调用或函数调用,我认为有必要在自定义 locals 命名空间中 exec() 代码:

>>> def add_ten(x):
        return x + 10

>>> class NS(dict):
        def __getitem__(self, key):
            value = dict.__getitem__(self, key)
            if key == 'x':
                return add_ten(value)
            return value

>>> exec('print(x + 2)', globals(), NS(x=5))
17

在上面的例子中,仅仅引用变量 x 就足以触发对 add_ten() 的调用。

这可能比它的价值更麻烦,但正如你所说,你只是想看看有什么可能:-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多