Python装饰器&

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

有什么区别,包括/不包括装饰器内部函数(和任何嵌套函数)的return语句中的括号?仅当函数返回一个以上的变量时才需要括号吗?

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

原因背后的术语会很好,所以有助于我完全理解。谢谢。

1
2
3
4
5
6
7
8
9
10
def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner()

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

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

另一个工作示例,但是return inner在这种情况下工作得很好,只要我设置了函数来支持可调用变量,例如msg

1
2
3
4
5
6
7
8
9
10
11
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("我的新消息")打印我的消息,装饰一下。当我不使用可调用函数时,为什么要将其与前面的示例进行比较?


在装饰器中,不应使用return inner()

这意味着您将用调用包装的func的结果替换装饰的func。

您的代码将立即打印修改后的消息,而不必尝试调用func()!!

1
2
3
**************************************************
Decorate this message.
**************************************************

但当你装饰一个功能时,这并不是你想要的。

您打算修改函数的行为,但仍然需要手动调用函数。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner

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

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

进一步解释:

当使用decorator语法时

1
2
@stars
def func():

您要告诉python执行以下操作:

1
func = stars(func)

换言之,def func但是用调用stars(func)的结果替换函数。

如果不在代码中重用名称func,您可能会发现它不那么容易混淆。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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用inner替换print_a_message


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

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

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

更重要的是,在您的函数接受参数的情况下,这肯定不起作用,因为您需要实际调用带有有效参数的修饰函数,以便将它们传递给inner,然后再传递给func


不同的是,使用圆括号时,不会返回decorator函数。相反,您返回的是函数的返回值,这意味着您过早地调用了修饰函数。如果没有括号,代码将正常工作,并返回函数对象inner

简而言之,不要调用函数。您需要返回实际的函数本身,这样您的修饰器才能正常工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> 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()时,您的消息就会被打印出来。


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

1
2
3
4
5
6
7
8
9
10
def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner

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