首页 > 解决方案 > 带循环的范围变量

问题描述

我在Python官方手册中读到了一句话。

如果在函数中定义的 lambda 或 def 嵌套在循环中,并且 >nested 函数引用了由该 >loop 更改的封闭范围变量,则在循环中生成的所有函数都将具有相同的值——该值 > 被引用变量在最后一次循环迭代中。在这种情况下,您必须 > 仍然使用默认值来保存变量的当前值。

至于剧本:

def makeActions():
     acts=[]
     for i in range(5):
         acts.append(lambda x: i**x)
     return acts
acts=makeActions()
print(acts)

我知道问题的样子以及如何解决它。但我就是无法理解原因。请看看我的解释:

def makeActions():
    acts=[]
    for i in range(5):
        acts.append(lambda x: i**x) #step2-step6: each lambda would be stored 
                                    #in the list, however, with its own "i"
    return acts

acts=makeActions() #step1: when the function is called, the list would be 
                   #created. And lambda would be called as well.
print(acts)

我的观点是,在每次迭代中,即使没有给出参数 x,也会调用每个 lambda。因此,在“acts”列表中,每个元素(即每个 lambda)都有不同的“i”。

我知道我错了,但你能告诉我为什么吗?谢谢!

标签: python

解决方案


为了更清楚地说明这个主题,对 的引用i在 lambda 中没有改变 - 您会看到每次迭代都会i生成一个新对象:

def makeActions():
  acts=[]
  for i in range(5):
    print('i:', i, 'object id:', id(i))
    acts.append(lambda: id(i))
  print('final i:', i, 'object id:', id(i))
  return acts
acts=makeActions()
print([fn() for fn in acts])

退货

i: 0 object id: 140418781832928
i: 1 object id: 140418781832960
i: 2 object id: 140418781832992
i: 3 object id: 140418781833024
i: 4 object id: 140418781833056
final i: 4 object id: 140418781833056
[140418781833056, 140418781833056, 140418781833056, 140418781833056, 140418781833056]

from 的引用i始终指向其最后分配的对象,因此在i最后一次更改后, 的 id 不会改变。

如果要在创建 lambda 时保留该值,则需要在所需的位置和时间“捕获”引用的值,例如,您可以将 lambda 创建委托给一个函数:

def delegated(d):
  return lambda: id(d)

def makeDelegatedActions():
  acts=[]
  for i in range(5):
    print('i:', i, 'object id:', id(i))
    acts.append(delegated(i))
  print('final i:', i, 'object id:', id(i))
  return acts
acts=makeDelegatedActions()
print([fn() for fn in acts])

哪个返回

i: 0 object id: 140418781832928
i: 1 object id: 140418781832960
i: 2 object id: 140418781832992
i: 3 object id: 140418781833024
i: 4 object id: 140418781833056
final i: 4 object id: 140418781833056
[140418781832928, 140418781832960, 140418781832992, 140418781833024, 140418781833056]

在线演示在这里


推荐阅读