一个经典的 Python 面试题:
result = [lambda x: x + i for i in range(10)]
print(result[0](10))
问,打印的结果是多少?
19
不止result[0](10)
结果是19,result[1](10)
,result[2](10)
....result[9](10)
全是 19。
为什么不是 10,11...19 呢?变量 i 不是从 0 取值到 9 么,分别再加 10。然鹅既然是面试题, 没有坑就不好意思流传的😂。
首先我们看这句
result = [lambda x: x + i for i in range(10)]
这是一个列表生成式,生成的是一个匿名函数列表。
这里需要了解一下 Python 中函数的运行机制:
- 遇到函数定义,直接将函数加载到内存而不会执行函数代码。你可以简单认为就是把代码原封原样的放到内存中(实际上此时函数会生成一个内存中的对象);
- 只有当调用时才会实际执行函数。
这里只是生成了匿名函数的列表而不会实际执行函数代码,也就是说暂时并没有生成结果。函数内部的 i 依然是只是变量,并没有变成具体的值,因为此时函数并没有执行。
只有当函数被调用时才会实际执行函数代码,result[0]
提取列表中的第一个匿名函数,在后面加上括号并传入参数 result[0](10)
才会实际调用函数,此时才开始执行函数,才会去找对应的变量值。
这时候就有一个问题了,i 变量在 for 循环时定义,当 for 循环完成后变量 i 的值已经变成了 9。
所以不管你取列表中的哪个函数来执行,都是同样的结果。
如果想要结果达到你想要的 10,11...19 的话,可以在循环时就把 i 作为参数传进去,而不是直接使用 for 循环中的 i 变量。
result = [lambda x, i=i: x + i for i in range(10)]
print(result[0](10))
上面的代码,匿名函数增加了一个参数 i,并且把 i 参数的默认值设置为 for 循环中 i 变量的值。那么每次循环时,生成的匿名函数就会把当次循环的 i 变量的值记录到i 参数的默认值。
这样在后面调用时,匿名函数的 i 参数的默认值都是不同的,结果就会变成 10, 11...19 了。