为什么这个python装饰器不打印原始函数的值?

时间:2017-04-21 12:58:17

标签: python function decorator

我试图在Python中学习装饰器,每当我想到它时,我遇到了一个像这样的问题。我无法弄清楚为什么来自my_func的打印声明不会显示,而是我得到了“无”#39;回。如果我在我的包装器func中的return语句中包含return (func, wrapper),则会收到错误,指出元组对象不可调用。这个例子有什么问题?

def my_dec(func):
    def wrapper():
        decoration = "decorated"
        print(decoration)
    return wrapper

@my_dec
def my_func():
    a = "Original"
    print (a)

print(my_func())

1 个答案:

答案 0 :(得分:4)

您永远不会在func中调用已包裹的wrapper。添加呼叫,例如:

def my_dec(func):
    def wrapper():
        decoration = "decorated"
        print(decoration)
        # Call the decorated function and return what it returns
        return func()

    return wrapper

@my_dec
def my_func():
    a = "Original"
    print (a)

print(my_func())

现在会生成(自func() implicitly returns None):

decorated
Original
None
  

如果我在我的包装器func中的return语句中包含return func, wrapper,则会收到错误消息,指出tuple对象不可调用。

错误必须来自你做的事情:

def my_dec(func):
    def wrapper():
        decoration = "decorated"
        print(decoration)

    # Now `my_dec` returns a tuple instead of a function
    return func, wrapper

请记住装饰is (roughly) equivalent to just doing

def my_func():
    ...

my_func = my_dec(my_func)

您的my_dec()装饰者现在返回了一个元组(func, wrapper)而不是包装函数,所以当您尝试拨打my_func()时,您实际上正在尝试"呼叫& #34;已分配给my_func的元组。

作为一个很好的衡量标准,您应该学习如何使用functools.wraps,这是一个用于调用update_wrapper()的便捷函数,它将包装函数更新为 FUNC

from functools import wraps

def my_dec(func):
    @wraps(func)
    def wrapper():
        decoration = "decorated"
        print(decoration)
        return func()

    return wrapper

没有它,你得到:

In [4]: print(my_func.__name__)
wrapper

和包装:

In [9]: print(my_func.__name__)
my_func

它也会复制其他有用的属性,例如__doc__