Python zip:为什么第二次遍历没有结果?
同一段 zip 结果第一次能打印,第二次却变成空列表,常见原因是迭代器已经被消费。下面用三个可以分别运行的小例子,区分结果保存、消费进度与输入来源。
1. 两次 list 调用共享同一个进度
pairs = zip(["A", "B"], [3, 5])
first = list(pairs)
second = list(pairs)
print(first) # [('A', 3), ('B', 5)]
print(second) # []
zip 返回迭代器。第一次 list(pairs) 会不断读取它,直到没有下一组元素;第二次再读取同一个对象时,进度已经位于末尾,所以得到空列表。
排查日志时要留意这一点:用 list(pairs) 打印调试结果,本身就会消费 pairs。后面的业务循环接收到的可能已经是耗尽的迭代器。
2. 需要多次遍历时,保存完整结果
pairs = list(zip(["A", "B"], [3, 5]))
print([name for name, value in pairs]) # ['A', 'B']
print(sum(value for name, value in pairs)) # 8
这次保存的是列表。提取名称与求和分别遍历同一份结果,都可以从列表开头读取。
这种方式适合规模明确、结果可以放入内存的场景。list 会收集完整结果;面对大型或持续产生数据的输入,应先明确是否真的需要重复遍历,再选择保存结果或重新取得输入。本文没有做内存占用或性能基准测试。
3. 重新创建 zip,也要检查输入是否已耗尽
names = iter(["A", "B", "C"])
values = iter([3, 5, 8])
pairs = zip(names, values)
print(next(pairs)) # ('A', 3)
print(list(pairs)) # [('B', 5), ('C', 8)]
print(list(zip(names, values))) # []
next 先取走一组,后续 list 只会读取剩下两组。读取完成后,names 和 values 这两个输入迭代器也已耗尽;重新调用 zip(names, values),仍然无法从头读取它们。
如果输入是可重复遍历的列表,可以重新创建 zip;如果输入来自文件或其他数据流,就要依据输入来源重新打开或重新生成,不能只更换外层变量名。示例中的对象都是普通单线程代码,没有覆盖共享迭代器的并发读取。
排查时还可以检查输入长度:zip 的默认行为是在最短输入耗尽时停止。本文三段示例都使用等长输入,以便单独观察消费进度。
实际验证与官方参考
本文三段代码已分别运行,并补充检查了耗尽后的重复读取、空输入、长短不等的输入及从列表重新生成 zip 的情况。结果说明这些最小示例的行为。
官方来源为 Python 官方文档的 Built-in functions / zip,以及 Glossary / iterator:
docs.python.org/3/builtins/functions.html#zipdocs.python.org/3/glossary.html#term-iterator
AI 辅助说明:本文由 AI 协助组织文字与编写示例,示例已实际执行,并依据上述官方文档核对语义。
- 点赞
- 收藏
- 关注作者
评论(0)