【问题标题】:Cannot set function attribute inside a decorator无法在装饰器中设置函数属性
【发布时间】:2021-05-19 12:44:25
【问题描述】:

我有一个这样的 Python 代码:

from functools import wraps

def dec(f): 
    
    @wraps(f)
    def wrapper(*args, **kwargs):
        f.foo = 'foo'
        value = f()
        f.foo = 'foo'
        return value
    return wrapper

@dec
def f():
    print('Hello, f')

f()
print(f.foo)

你可以找到准备好的代码here

这段代码的问题是我最终得到了AttributeError: 'function' object has no attribute 'foo',尽管我使用了来自functools 的wraps 装饰器,它应该保留函数的属性范围。任何想法错误的原因是什么?

【问题讨论】:

  • dec 需要返回 wrapper 而不是 f。你的装饰器目前是空的。
  • foo 属性仅在您调用f() 时创建。如果您希望它在“装饰时间”创建,请将该行移至dec,而不是wrapper
  • 修复了这个问题,但仍然没有消除根本问题
  • @deceze,请参阅问题中的更新代码。问题依旧
  • 这不是 deceze 建议的。你无缘无故地调用 f() 两次

标签: python python-decorators


【解决方案1】:

您在f 上设置属性,但您返回wrapper 并且主要范围内的fwrapper 函数对象。用不太容易混淆的名称来说明:

def dec(f): 
    @wraps(f)
    def wrapper(*args, **kwargs):
        f.foo = 'foo'  # <-- this is the original bar function
        value = f()
        return value

    return wrapper

@dec
def bar():
    print('Hello, f')

bar()  # <-- this is wrapper()

当您将代码更改为 wrapper.foo = 'foo' 时,它会按预期工作。

【讨论】:

  • 让我不同意你的观点,@deceze。这实际上是functoolwraps 函数所做的。请参阅此代码 - onlinegdb.com/3UnBzZME65。使用和不使用 wraps 装饰器来玩弄它
  • wraps 确保wrapper 的签名看起来像 f 的签名。它不会使它们成为同一个对象。装饰器语法是 bar = dec(bar) 的糖。 bar 将是 dec 返回的任何内容。 dec 返回wrapperbar wrapper。您没有在该对象上设置属性,因此它不会显示在那里。
猜你喜欢
  • 2013-03-25
  • 2019-05-09
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 2015-10-23
  • 2017-01-06
  • 2014-07-09
  • 2018-07-08
相关资源
最近更新 更多