循环中的副作用会影响生成器吗?

1 投票
2 回答
511 浏览
提问于 2025-04-17 17:35

在Python 2.7中,我遇到了一个关于for循环的情况,这个循环是基于一个for生成器的。在循环的主体部分,作为for生成器来源的那个项目发生了变化:

for ssid in (ssid for ssid in overlaps if ssid != subseq_id):
  overlaps = subseq_id_to_overlap_ssids_dict[ssid]

我想问的是,这种对overlaps的变化是否会影响到for生成器?我希望不会,但如果会的话,那具体意味着什么呢?如果我处理了第一个匹配的元素,然后替换了overlaps,那么for会不会指向overlaps的新值的下一个位置呢?

2 个回答

3

一个 for 循环的工作原理是,它会对给定的内容进行迭代,也就是先调用 iter 函数来生成一个迭代器,然后不断调用 next 来获取下一个元素,直到遇到 StopIteration 这个信号,表示没有更多元素了。

在你使用生成器表达式时,overlaps 这个名字会在进入 for 循环之前就被计算出来,所以如果你在循环中重新给 overlaps 赋值,它是不会有任何影响的。不过,如果你改变了 overlaps 所指向的对象,那么效果就会有所不同,这取决于 type(overlaps) 的迭代器是怎么工作的。举个例子,list 的迭代器会在列表中逐个增加索引。

3

在循环里面重新绑定 overlaps 其实对循环没有影响(当然,如果修改它的话就会有影响)。在循环内部重新绑定 subseq_iq 可能会影响生成器。

for 循环在开始的时候只会评估一次表达式,以获取一个迭代器:在这个例子中,表达式就是 overlaps 的名字。一旦评估了这个表达式,它就会从可迭代对象中创建一个迭代器,并用这个迭代器来逐个处理元素。这个迭代器是依赖于表达式返回的对象,而不是依赖于用来标识这个对象的名字(如果有名字的话)。

在这个特定的情况下,代码实际上和下面的内容是完全一样的:

for ssid in overlaps:
  if ssid != subseq_id:
     overlaps = subseq_id_to_overlap_ssids_dict[ssid]

这样写会更清晰,但再次强调,重新绑定 overlaps 并不会改变 for 循环所使用的序列。

撰写回答