一道好题
题目如下:
def f():
l = []
for i in range(4):
def a(x):
return x * i
l.append(a)
return l
print([e(2) for e in f()]) # [6, 6, 6, 6]
代码可以翻译成这样:
def f():
l = []
for i in range(4):
def a(x):
return x * i
l.append(a)
return l
l_curr = []
for e in f():
l_curr.append(e(2))
print(l_curr)
代码的执行过程如下:
-
代码从上到下执行,进入函数
f() -
初始化空列表
l -
进入
for循环 -
i=0,执行l.append(a)python调用函数时加括号表示调用函数的最终执行结果,不加括号表示调用函数对象,所以这里列表追加的时函数对象。此时
l=[<function f.<locals>.a at 内存地址1>] -
i=1,执行l.append(a)此时
l=[<function f.<locals>.a at 内存地址1>,<function f.<locals>.a at 内存地址2>] -
i=2,执行l.append(a)此时
l=[<function f.<locals>.a at 内存地址1>,<function f.<locals>.a at 内存地址2>],<function f.<locals>.a at 内存地址3> -
i=3,执行l.append(a)此时
l=[<function f.<locals>.a at 内存地址1>,<function f.<locals>.a at 内存地址2>],<function f.<locals>.a at 内存地址3>,<function f.<locals>.a at 内存地址4> -
函数
f()执行完毕,return l此时
l=[<function f.<locals>.a at 内存地址1>,<function f.<locals>.a at 内存地址2>],<function f.<locals>.a at 内存地址3>,<function f.<locals>.a at 内存地址4> -
初始化空列表
l_curr -
进入
for循环,开始遍历f()此时的
f()是带括号的,所以引用的是最终返回的列表 -
遍历第一个元素
<function f.<locals>.a at 内存地址1>,执行2 * 3 = 6,这个函数存储的i是i的引用,此时的i=3 -
遍历第二个元素
<function f.<locals>.a at 内存地址2>,执行2 * 3 = 6,这个函数存储的i是i的引用,此时的i=3 -
遍历第三个元素
<function f.<locals>.a at 内存地址3>,执行2 * 3 = 6,这个函数存储的i是i的引用,此时的i=3 -
遍历第四个元素
<function f.<locals>.a at 内存地址4>,执行2 * 3 = 6,这个函数存储的i是i的引用,此时的i=3 -
遍历完毕,返回列表
l_curr=[6, 6, 6, 6]
类比
def f():
l = []
for i in range(4):
def a(x, i=i):
return x * i
l.append(a)
return l
l_curr = []
for e in f():
l_curr.append(e(2))
print(l_curr)
区别是:def a(x, i=i)
在这个程序中,函数f()中的列表l每次追加的函数a中存储的i是当前的i值,而不是引用。所以四次的i值分别为0, 1, 2, 3。
所以最终的结果为l_curr=[0, 2, 4, 6]

被折叠的 条评论
为什么被折叠?



