关于python闭包和变量的命名空间
例子
例子1
def create_multipliers():
return [lambda x : i * x for i in range(5)]
for multiplier in create_multipliers():
print(multiplier(2))
输出
8
8
8
8
8
例子2
def create_multipliers2():
multipliers = []
for i in range(5):
def multiplier(x):
return i * x
multipliers.append(multiplier)
return multipliers
for multiplier in create_multipliers2():
print(multiplier(2))
输出
8
8
8
8
8
例子3
func_list = []
for i in range(10):
def callback():
print(“clicked button”, i)
func_list.append(callback)
for func in func_list:
func()
输出
clicked button 4
clicked button 4
clicked button 4
clicked button 4
clicked button 4
##分析
原因都一样,只针对例子2进行分析。
在函数create_multipliers2中,返回了一个列表,列表中每个成员都是一个函数multiplier,该函数需要一个参数x,函数返回值是x 乘以 i。
其中,变量x是multiplier的参数,也就是函数multiplier的局部变量,所以变量x的命名空间是函数multiplier。
变量i是create_multipliers2的变量,所以变量i的命名空间是函数create_multipliers2。
在执行print(multiplier(2))时,函数create_multipliers2的变量i已经变成了4。
所以,一直打印8。
解决方法
例子2
方案1:yield
def create_multipliers2():
for i in range(5):
def multiplier(x):
return i * x
yield multiplier
for multiplier in create_multipliers2():
print(multiplier(2))
方案2:修改变量i的命名空间
def create_multipliers2():
multipliers = []
for i in range(5):
def multiplier(x, i=i):
return i * x
multipliers.append(multiplier)
return multipliers
for multiplier in create_multipliers2():
print(multiplier(2))
其他推荐
https://segmentfault.com/a/1190000004461404
https://segmentfault.com/a/1190000004519811