Python 3.5 装饰器和函数域

Python 3.5 Decorators and function fields

我有以下代码片段:

def wrapper(func):
    def wrapped(*args, **kwargs):
        func.var = 0
        return func(*args, **kwargs)
    return wrapped

@wrapper
def f_out():
    print(f_out.var)

你能解释一下为什么 运行 f_out() 加薪吗:

AttributeError: 'function' object has no attribute 'var'

编辑

我必须详细说明,因为答案给了我替代方案,但这不适用于我想要的情况。给定以下代码段:

def wrapper(func):
    def wrapped(*args, **kwargs):
        func.var = 0
        ret = func(*args, **kwargs)
        print(func.var)
    return wrapped

@wrapper
def f_out():
    f_out.var = 1
f_out()
print(f_out.var)

我得到输出:

0
1

为什么会这样?

如果 return func 你必须添加 return wrapped 试试这个:

def wrapper(func):
    def wrapped(*args, **kwargs):
        func.var = 0
        return func(*args, **kwargs)
    return wrapped

@wrapper
def f_out():
    print(f_out.var)

正确的方法是 return 包装函数并在 return 之前更改它:

def wrapper(func):
    def wrapped(*args, **kwargs):
        return func(*args, **kwargs)
    wrapped.var = 0
    return wrapped

@wrapper
def f_out():
    print(f_out.var)

你正确地得到:

print(f_out())

给予

0

更新后的片段更改了 var 属性两次:

  • 第一次在包装器中将原始函数的属性设置为 0 并在调用原始函数后打印它
  • 然后当从包装器调用原始函数时,它会将引用为 f_out 的函数的属性 设置为 1。但在那一刻,函数引用为 f_out 的是包装函数,不再是原始函数。

因此,当您稍后打印 f_out.var 时,您会打印包装函数的属性 1。

这里是一个稍微修改过的代码来演示它:

def wrapper(func):
    def wrapped(*args, **kwargs):
        wrapped.orig = func          # keeps a ref to the original function
        func.var = 0
        ret = func(*args, **kwargs)
        print(func.var)
    return wrapped

@wrapper
def f_out():
    f_out.var = 1

f_out()
print(f_out.var, f_out.orig.var)

它打印

0
1 0

Decorator 在您调用函数时包装您的函数。 因此,当您调用 f_out() 时,它会 returns 1。它是您调用的包装函数,而不是它的定义。

@wrapper
def f_out()

等于 wrapper(f_out)当你调用它时。

当您尝试打印 f_out.var 时,它 returns 来自函数定义的值。