面试题
面试题
一 前戏: 闭包延迟绑定问题
请写出以下的代码执行结果,并解释。
def multipliers(): return [lambda x : i*x for i in range(4)] print ([m(2) for m in multipliers()] ) """ [6, 6, 6, 6] """
上述代码相当于以下这段代码。
def multipliers(): list1 = [] for i in range(4): def foo(x): return i * x # foo函数内的i在函数调用前指向循环结束最后一个i的值 list1.append(foo) return list1 print(list(m(2) for m in multipliers()))
为啥结果和我们意向的不一样呢,是因为循环内的函数,在执行前变量“i”都会延迟绑定,因为函数在执行之前并不会立即绑定变量i,而是等到最终for循环结束后执行内部函数才会绑定最后的i。所以才会得到我们现在看到的结果[6,6,6,6]。
因为Python解释器,遇到lambda(类似于def),只是定义了一个匿名函数对象,并保存在内存中,只有等到调用这个匿名函数的时候,才会运行内部的表达式,而for i in range(4) 是另外一个表达式,需等待这个表达式运行结束后,才会开始运行lambda 函数,此时的i 指向3,x指向2。
二 深入: 改进
# 列表推导式,给i赋值,每次循环都指向循环的i值 def multipliers(): return [lambda x, i=i: i * x for i in range(4)] print([m(2) for m in multipliers()]) """ [0, 2, 4, 6] """
上述代码相当于一下代码
# 列表推导式,给i赋值,每次循环都指向循环的i值 def multipliers(): list1 = [] for i in range(4): # 给内部函数写一个默认值,每次调用foo的时候就会先去默认参数中查找i def foo(x, i=i): return x * i return foo return list1 print([m(2) for m in multipliers()]) """ [0, 2, 4, 6] """
Python的延迟绑定其实就是只有当运行内部函数的时候,才会引用外部变量i,不运行的时候,并不是会去找i的值,这个就是第一个函数,为什么输出的结果是[6,6,6,6]的原因。

浙公网安备 33010602011771号