Python常见面试题014.请说出下面的代码返回结果是什么?
示例代码
def fun(a, b, c, d):
nums = []
for num in range(a, b):
nums.append(lambda: num ** c)
return nums[d]()
print(fun(1, 5, 2, 0))
print(fun(1, 5, 2, 1))
print(fun(1, 5, 3, 1))
print(fun(1, 10, 2, 1))
- 答案是
16
16
64
81
原因分析
-
调用函数fun(1, 5, 2, 0)
-
意味着
nums = [] for num in range(1, 5): nums.append(lambda: num ** 2) return nums[0]()
-
所在列表nums中是多个匿名函数
-
应该依次是
lambda :1**2 lambda :2**2 lambda :3**2 #依次类推 ...
-
那按照我们的想法,nums[0]应该是lambda :1**2,调用应该得到1才是
>>> demo1 = lambda :1**2 >>> demo1() 1 >>> demo2 = lambda :2**2 >>> demo2() 4
-
但结果并不是这样的,
nums[0]()
得到的结果是range()结束值=5-1时的4**2 -
甚至从答案可以看出来
nums[1]()
也是 -
依次类推,fun(1, 5, 3, 1)=>
nums[1]()
=>结束值5-1=4的三次方=>64
-
所以规律是有了,道理何在?
-
看下代码
def fun(a, b, c, d): nums = [] for num in range(a, b): nums.append(lambda: num ** c) return nums[d]()
-
这是因为
num
不是 lambda 函数的内部变量,而是定义于外部作用域中的,并且num
是在调用 lambda 时访问的——而不是在定义时访问。循环结束时num
的值是4
,所以此时所有的函数都将返回4**2
,即16
拓展
-
那要如何才能符合我们的预期呢?
nums[0]()
和nums[1]()
是不一样的 -
你可以将值保存在 lambda 局部变量,以使其不依赖于全局
num
的值def fun(a, b, c, d): nums = [] for num in range(a, b): nums.append(lambda n=num: n ** c) # n = num return nums[d]() print(fun(1, 5, 2, 0)) print(fun(1, 5, 2, 1)) print(fun(1, 5, 3, 1)) print(fun(1, 10, 2, 1)) # 依次输出 1 4 8 4
-
以上
n=num
创建了一个新的 lambda 本地变量n
,并在定义 lambda 时计算其值,使其与循环当前时点的num
值相同。这意味着n
的值在第 1 个 lambda 中为0
,在第 2 个 lambda 中为1
,在第 3 个中为2
,依此类推
以上参考