我会尝试更深入地解释一下。
如果您这样做
i = 0
f = lambda: i
你创建一个函数(λ本质上是一个函数),该函数访问其封闭作用域的i
变量。
内部,它通过拥有所谓的闭包来实现这一点,其中包含i
。粗略地说,它是指向真实变量的指针,在不同时间点可以保存不同的值。
def a():
yield lambda: i
for i in range(100): yield
g = a()
f = next(g)
f()
next(g)
f()
next(g)
f()
f.func_closure
f.func_closure[0].cell_contents
在这里,所有i
的值 - 在它们的时间内 - 都存储在该闭包中。如果函数f()
需要它们,它会从那里获取。
您可以在反汇编列表中看到这种差异:
这些所谓的函数a()
和f()
的反汇编如下:
>>> dis.dis(a)
2 0 LOAD_CLOSURE 0 (i)
3 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object <lambda> at 0xb72ea650, file "<stdin>", line 2>)
9 MAKE_CLOSURE 0
12 YIELD_VALUE
13 POP_TOP
3 14 SETUP_LOOP 25 (to 42)
17 LOAD_GLOBAL 0 (range)
20 LOAD_CONST 2 (100)
23 CALL_FUNCTION 1
26 GET_ITER
>> 27 FOR_ITER 11 (to 41)
30 STORE_DEREF 0 (i)
33 LOAD_CONST 0 (None)
36 YIELD_VALUE
37 POP_TOP
38 JUMP_ABSOLUTE 27
>> 41 POP_BLOCK
>> 42 LOAD_CONST 0 (None)
45 RETURN_VALUE
>>> dis.dis(f)
2 0 LOAD_DEREF 0 (i)
3 RETURN_VALUE
将其与函数b()
进行比较,它看起来像:
>>> def b():
... for i in range(100): yield
>>> dis.dis(b)
2 0 SETUP_LOOP 25 (to 28)
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (100)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 11 (to 27)
16 STORE_FAST 0 (i)
19 LOAD_CONST 0 (None)
22 YIELD_VALUE
23 POP_TOP
24 JUMP_ABSOLUTE 13
>> 27 POP_BLOCK
>> 28 LOAD_CONST 0 (None)
31 RETURN_VALUE
循环中的主要区别在于
>> 13 FOR_ITER 11 (to 27)
16 STORE_FAST 0 (i)
在b()
中对比。
>> 27 FOR_ITER 11 (to 41)
30 STORE_DEREF 0 (i)
在 a()
函数中: STORE_DEREF
存储在一个 cell
对象(闭包)中,而 STORE_FAST
使用一个“普通”的变量,这可能会稍微快一些。
lambda 表达式也有所不同:
>>> dis.dis(lambda: i)
1 0 LOAD_GLOBAL 0 (i)
3 RETURN_VALUE
这里您使用了LOAD_GLOBAL
,而上面的代码使用了LOAD_DEREF
。同样,后者用于闭包。
我完全忘记了 lambda i=i: i
。
如果您将值作为默认参数,它会通过完全不同的路径进入函数:当前的i
值通过默认参数传递给刚创建的函数:
>>> i = 42
>>> f = lambda i=i: i
>>> dis.dis(f)
1 0 LOAD_FAST 0 (i)
3 RETURN_VALUE
这样,函数将被调用为f()
。它检测到缺少参数并使用默认值填充相应的参数。所有这些都发生在函数被调用之前;在函数内部,您只看到值被获取并返回。
还有另一种方法可以完成您的任务:只需像使用接受值的lambda一样使用它:lambda i: i
。如果您调用它,它会抱怨缺少参数。
但是,您可以通过使用functools.partial
来处理这个问题:
ff = [functools.partial(lambda i: i, x) for x in range(100)]
ff[12]()
ff[54]()
这个包装器获取一个可调用对象和一些要传递的参数。结果对象是一个可调用对象,它使用这些参数加上你提供给它的任何参数来调用原始的可调用对象。在此可用于保持锁定到所需值。