【发布时间】:2017-10-17 15:27:11
【问题描述】:
当我使用循环将两个生成器附加到列表时,第一个生成器复制第二个生成器的输出。当我展开循环时,我得到了与预期不同的输出。
以下代码演示了该问题。
import itertools
iterators = itertools.tee(itertools.repeat(('a', 0), 5), 2)
result = []
result.append(r[0] for r in iterators[0])
result.append(r[1] for r in iterators[1])
# As expected
print('Written out...')
print(list(result[0])) # ['a', 'a', 'a', 'a', 'a']
print(list(result[1])) # [0, 0, 0, 0, 0]
# Now do it again but use a loop
iterators = itertools.tee(itertools.repeat(('a', 0), 5), 2)
result = []
for index in [0, 1]:
result.append(r[index] for r in iterators[index])
# This time both lists are of the second item.
print('With a loop...')
print(list(result[0])) # [0, 0, 0, 0, 0] <--- Huh?!
print(list(result[1])) # [0, 0, 0, 0, 0]
为什么循环版本不能按我预期的那样工作?我该怎么办?
解决方案
现在这已作为重复关闭我无法发布另一个答案,但为了记录,这是我最终使用的解决方案。
@MikeMüller 指出的问题是索引r 的index 实例是后期绑定的。以下通过为循环中 index 的每个值创建一个新的局部变量实例 i 来强制进行早期绑定:
for index, it in enumerate(iterators):
g = lambda i: (r[i] for r in it) # force early binding on index
result.append(g(index))
(我也很喜欢 Mike 的建议,即一直使用生成器,但不幸的是,我需要实现外部生成器(result),以便我可以重复引用 result 中的各个元素。但 @987654330 @ 与我的原始循环代码具有相同的行为。)
【问题讨论】:
-
你想得到什么输出?
-
您只有一个
index变量。两个生成器都使用它。和 JavaScript 一样,我会尝试找到一个 Python 副本:stackoverflow.com/questions/750486/… -
请记住,在您调用
list并且您正在捕获index之前,生成器不会运行。将打印内容粘贴到循环中,看看会发生什么。
标签: python python-3.x generator