Python 3.5装饰器和函数字段

Vas*_*dis 4 python field function decorator python-decorators

我有以下代码片段:

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

@wrapper
def f_out():
    print(f_out.var)
Run Code Online (Sandbox Code Playgroud)

能告诉我为什么要f_out()加油:

AttributeError: 'function' object has no attribute 'var'
Run Code Online (Sandbox Code Playgroud)

编辑

我不得不详细说明,因为答案给了我另一种选择,但这对我想要的情况不起作用.给出以下代码段:

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)
Run Code Online (Sandbox Code Playgroud)

我得到输出:

0
1
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

Ser*_*sta 6

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

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

@wrapper
def f_out():
    print(f_out.var)
Run Code Online (Sandbox Code Playgroud)

你正确得到:

print(f_out())
Run Code Online (Sandbox Code Playgroud)

0
Run Code Online (Sandbox Code Playgroud)

更新的剪切会更改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)
Run Code Online (Sandbox Code Playgroud)

它打印

0
1 0
Run Code Online (Sandbox Code Playgroud)