1 回答

TA贡献1796条经验 获得超7个赞
想象一下,如果您可以将装饰器应用于常规变量赋值,如下所示:
def add1(x):
return x + 1
@add1
number = 5
与函数修饰器类似的行为如下所示:
number = 5
number = add1(number)
这将导致将值赋给变量 。现在想象一下,装饰器只是被调用而没有返回任何内容:6number
number = 5
add1(number)
此代码不可能分配给变量 ,因为它是按值传递的,而不是通过引用传递的;在Python中,函数不能将新值分配给它无权访问的完全不同作用域中的变量。6numbernumber
语句实际上是一种赋值;它将函数分配给您用来定义它的名称。例如,函数定义编译为字节码,执行 ,即赋值:defdef func(): passSTORE_NAME
1 0 LOAD_CONST 0 (<code object func at ...>)
3 LOAD_CONST 1 ('func')
6 MAKE_FUNCTION 0
9 STORE_NAME 0 (func)
因此,出于同样的原因,功能装饰器的行为与上述方式相同;装饰器函数无法将新函数重新分配给完全不同作用域中的变量,因为它是按值传递给装饰器的,而不是通过引用传递的。funcfunc
这种等价性实际上有点误导。为了完全正确起见,当您使用修饰器时,您在语句中定义的函数将直接传递给装饰器,而不是在传递之前分配给本地名称。下面是字节码:func = decorator(func)deffunc
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)
循序渐进:
该函数被加载到堆栈上,
decorate
的代码对象被加载到堆栈上,然后是字符串,然后指令将这两个转换为一个函数,该函数保留在堆栈上。
func
'func'
MAKE_FUNCTION
该指令使用一个参数(函数)调用函数(仍在堆栈上)。
CALL_FUNCTION
decorate
func
无论函数返回什么,都留在堆栈上,并由指令分配给名称。
decorate
func
STORE_NAME
因此,如果函数没有返回任何内容,则不会为名称分配任何内容 - 甚至不会像语句中的原始函数那样。decorator
func
def
添加回答
举报