Python 中 zip 同时遍历多个列表
FreeGuideOnline
最新
2026-07-07
python names = ["Alice", "Bob", "Charlie"] scores = [85, 92, 78]
for name, score in zip(names, scores): print(f"{name}: {score}")
输出:
Alice: 85 Bob: 92 Charlie: 78
## `zip` 的基本语法
```python
zip(iterable1, iterable2, ..., strict=False)
iterable1, iterable2, ...:两个或多个可迭代对象。strict(Python 3.10 新增):如果设为True,当输入的可迭代对象长度不一致时会抛出ValueError,强制要求长度相等。默认是False,不检查长度。
zip 返回的是一个迭代器,可以通过 list()、tuple() 或循环来消费数据。迭代器只能遍历一次,再次遍历需要重新创建。
a = [1, 2, 3]
b = ['a', 'b', 'c']
zipped = zip(a, b)
print(list(zipped)) # [(1, 'a'), (2, 'b'), (3, 'c')]
print(list(zipped)) # [] 迭代器已耗尽
同时遍历多个列表
两个列表并行处理
最常见的场景:有两个长度相同的列表,需要按索引一一对应处理。
items = ['apple', 'banana', 'cherry']
prices = [1.2, 1.5, 2.0]
for item, price in zip(items, prices):
print(f"{item}: ${price}")
多于两个列表
zip 可以同时处理任意数量的可迭代对象,只要每个对象的元素个数匹配对应的索引。
students = ['Alice', 'Bob']
math = [90, 85]
english = [88, 92]
science = [95, 89]
for name, m, e, s in zip(students, math, english, science):
avg = (m + e + s) / 3
print(f"{name}: Average {avg:.1f}")
长度不一致时的行为
默认情况下,zip 会在最短的可迭代对象耗尽时停止,剩余的元素会被忽略。这个行为称为“最短匹配”。
list1 = [1, 2, 3, 4]
list2 = ['a', 'b']
print(list(zip(list1, list2))) # [(1, 'a'), (2, 'b')]
如果想保留所有元素,可以用 itertools.zip_longest 来填充缺失值。
from itertools import zip_longest
print(list(zip_longest(list1, list2, fillvalue=None)))
# [(1, 'a'), (2, 'b'), (3, None), (4, None)]
strict 参数:强制长度相等
在 Python 3.10 及以上版本,如果希望两个列表必须长度相同,否则就报错,可以使用 strict=True。这在数据需要严格一一对应的场景下很有用,能提前暴露 bug。
a = [1, 2, 3]
b = [10, 20]
# 下面代码会抛出 ValueError:
# zip() argument 2 is shorter than argument 1
list(zip(a, b, strict=True))
如果你的 Python 版本较低,又不希望静默截断数据,可以在使用 zip 前先自行判断长度是否一致,或通过第三方库实现。
反向解压:将配对结果拆分回原来的列表
利用 zip(*zipped) 可以实现反向操作,将打包好的元组序列“解压”回多个元组(可再转为列表)。
pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
numbers, letters = zip(*pairs)
print(numbers) # (1, 2, 3)
print(letters) # ('a', 'b', 'c')
这个技巧在需要将数据矩阵转置时非常方便。
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
transposed = list(zip(*matrix))
print(transposed)
# [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
常见误区与注意事项
- 不要期望原地修改:
zip创建的是迭代器,它不会生成新的列表,除非用list()强制转换。 - 迭代器只能用一次:想在多个地方使用,需要把结果转为列表或重新调用
zip。 - 长度不一致时的静默截断:如果数据完整性至关重要,请使用
strict=True(3.10+)或预先验证长度。 - 与
range联合遍历:如果还需要索引,可以用enumerate(zip(...)),但更推荐直接使用zip搭配元素变量,代码更清晰。
实战练习
练习 1:合并两个列表为字典
keys = ['name', 'age', 'city']
values = ['Alice', 25, 'New York']
person = dict(zip(keys, values))
print(person) # {'name': 'Alice', 'age': 25, 'city': 'New York'}
练习 2:列表元素对应相加减
a = [1, 2, 3]
b = [10, 20, 30]
sum_list = [x + y for x, y in zip(a, b)]
print(sum_list) # [11, 22, 33]
练习 3:实现简易版矩阵转置
rows = [
['a', 'b', 'c'],
['d', 'e', 'f']
]
cols = [list(col) for col in zip(*rows)]
print(cols)
# [['a', 'd'], ['b', 'e'], ['c', 'f']]
性能说明
zip 在 C 层面实现,遍历大量数据时比手动索引循环快得多,并且内存占用低(返回迭代器)。它不仅是代码简洁的选择,在性能上也通常是更优方案。
# 推荐
for x, y in zip(list_a, list_b):
pass
# 不推荐(慢且代码冗余)
for i in range(min(len(list_a), len(list_b))):
x = list_a[i]
y = list_b[i]
pass