Python 装饰器和嵌套函数 return 语句。带括号的正确用法?

Python Decorators & Nested Functions return statement. Proper usage with parenthesis?

有什么区别 including/not 包括装饰器(和任何嵌套函数)的内部函数的 return 语句中的括号?仅当函数 returns 多于 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('my new message') 来打印我的消息,装饰。当我不使用可调用函数时,为什么这与前面的示例相比?

在装饰器中你不应该做 return inner()

这意味着您要用调用包装函数的结果替换装饰函数

您的代码将立即 打印修改后的消息,您甚至不需要尝试调用 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_messageinner

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

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

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

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

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

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

更重要的是,如果您的 函数接受参数 ,这肯定行不通,因为您需要使用 valid 实际调用装饰函数将它们传递给 inner 然后再传递给 func.

的参数

不同之处在于,有了括号,您就不会 return 装饰器函数。相反,您正在 returning 函数的 return 值,这意味着您过早地调用了装饰函数。如果没有括号,您的代码将正常工作,并且函数对象 inner 将被 returned.

总之,不要调用函数。您需要 return 实际函数本身才能使您的装饰器正常工作:

>>> 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() 时打印。