Python装饰器&嵌套函数返回语句。正确使用括号?

时间:2017-07-07 14:48:01

标签: python python-3.x return python-decorators

有什么区别,包括/不包括装饰器内部函数return语句的括号(以及任何嵌套函数)?如果函数返回多于1个变量,是否只需要括号?

在下面的示例中,我知道除非我使用return inner(),否则这将无效,但我看到其他示例不使用()上的return并且它们正常工作。

背后的术语原因很棒,所以帮助我完全理解。感谢。

def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner()

@stars
def func():
    print('Decorate this message.')

它最初打印我的消息,装饰。但是,如果我再次调用func(),它将不会打印任何内容。

另一个工作示例,但return inner在这种情况下工作正常,只要我设置了支持可调用变量的函数,我的示例为msg

def star(func):
    def inner(*args, **kwargs):
        print("*" * 30)
        func(*args, **kwargs)
        print("*" * 30)
    return inner

@star
def func(msg):
    print(msg)
func("Another message to be decorated")

我每次都可以打电话给func('我的新消息')来打印我的消息。当我不使用可调用函数时,为什么将此与前一个示例进行比较?

4 个答案:

答案 0 :(得分:4)

在装饰者中,你不应该return inner()

这意味着你要用调用包装的func

的结果替换装饰的func

您的代码将立即打印修改后的消息,您甚至无需致电func() !!

**************************************************
Decorate this message.
**************************************************

但是,这不是装饰函数时的意图。

您打算修改该函数的行为,但您仍然希望必须手动调用该函数。

这就是为什么代码应该是:

def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner

@stars
def func():
    print('Decorate this message.')

func()
**************************************************
Decorate this message.
**************************************************

进一步解释:

使用装饰器语法时

@stars
def func():

你告诉python执行以下操作:

func = stars(func)

换句话说,def func但将函数替换为调用stars(func)的结果

如果您不在代码中重复使用名称func,您可能会发现它不那么令人困惑。例如:

def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner

@stars
def print_a_message():
    print('Decorate this message.')

print_a_message()
**************************************************
Decorate this message.
**************************************************

现在可能更清楚的是,当我们从装饰器做return inner时,我们告诉Python print_a_message替换 inner

答案 1 :(得分:2)

通过调用inner函数,而不是返回函数对象,在装饰时调用func

stars(func) -> inner() -> func() # with some side effects

这通常不是我们想要的。该函数被修饰以便稍后调用。

更多的是,在你的函数接受参数的情况下,这当然不会起作用,因为你需要实际调用带有效参数的修饰函数来让它们通过到inner然后到func

答案 2 :(得分:1)

您调用inner函数而不是返回它。下面的代码包含func函数,而不是像您上面粘贴的代码一样立即调用它。

def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner

@stars
def func():
    print('Decorate this message.')

答案 3 :(得分:1)

不同之处在于,使用括号,您不会返回装饰器功能。而是,您返回函数的返回值,这意味着您过早地调用了修饰函数。如果没有括号,则代码将正常工作,并返回函数对象inner

简而言之,请勿调用此功能。您需要返回实际的函数本身,以便装饰器正常工作:

>>> def stars(func):
        def inner():
            print("*" * 50)
            func()
            print("*" * 50)
        return inner # Don't call inner, return it.

>>> @stars
def func():
    print('Decorate this message.')


>>> func()
**************************************************
Decorate this message.
**************************************************
>>> 

如果您无论如何都拨打了inner,那么在定义func()而不是func()被调用时,您的信息就会被打印出来。