为什么decorator函数有返回值



考虑以下示例。

def decorator(function_to_decorate):
def wrapper():
print('Entering', function_to_decorate.__name__)
function_to_decorate()
print('Exiting', function_to_decorate.__name__)
return wrapper
@decorator
def func():
print("Original function.")
func()

由于@decorator语法只是func = my_decorator(func)的简写,因此my_decorator必须返回一些内容是合乎逻辑的。我的问题是:为什么装饰器是以这种方式定义的,而不是没有返回值:my_decorator(func)?返回包装器函数wrapper的目的是什么?


编辑

除了简单的包装器,装饰器还能做什么?

def wrapper(function_to_decorate):
print('Entering', function_to_decorate.__name__)
function_to_decorate()
print('Exiting', function_to_decorate.__name__)
def func():
print("Original function.")
wrapper(func)

想象一下,如果您可以将装饰器应用于常规变量赋值,比如:

def add1(x):
return x + 1
@add1
number = 5

类似于函数装饰器的行为如下:

number = 5
number = add1(number)

这将导致将值6分配给变量number。现在想象一下,decorator只是被调用而没有返回任何内容:

number = 5
add1(number)

此代码不可能将6分配给变量number,因为number是通过值传递的,而不是通过引用传递的;在Python中,函数不能将新值分配给它无法访问的完全不同范围中的变量。


def语句实际上是一种赋值;它将函数指定给您定义它的名称。例如,函数定义def func(): pass编译为执行STORE_NAME的字节码,即赋值:

1     0 LOAD_CONST         0 (<code object func at ...>)
3 LOAD_CONST         1 ('func')
6 MAKE_FUNCTION      0
9 STORE_NAME         0 (func)

因此,函数装饰器的行为以与上述相同的方式工作,原因相同;decorator函数不能在完全不同的作用域中将新函数重新分配给变量func,因为func是通过值而不是通过引用传递给decorator的。

func = decorator(func)等效实际上有点误导。为了完全正确,当您使用decorator时,您在def语句中定义的函数会直接传递给decorator,而不是在传递之前分配给本地名称func。这是字节码:

1     0 LOAD_NAME          0 (decorate)
3 LOAD_CONST         0 (<code object func at ...>)
6 LOAD_CONST         1 ('func')
9 MAKE_FUNCTION      0
12 CALL_FUNCTION      1 (1 positional, 0 keyword pair)
15 STORE_NAME         1 (func)

循序渐进:

  • CCD_ 19函数被加载到堆栈上
  • func的代码对象被加载到堆栈上,然后是字符串'func',然后是MAKE_FUNCTION指令将这两者转换为一个留在堆栈上的函数
  • CALL_FUNCTION指令用一个参数func函数调用decorate函数(该函数仍在堆栈中(
  • 无论decorate函数返回什么,都留在堆栈上,并由STORE_NAME指令分配给名称func

因此,如果decorator函数没有返回任何内容,那么就不会为名称func分配任何内容,甚至不会为def语句中的原始函数分配任何内容。

最新更新