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