Python zip()函数详解
zip()是Python内置函数,用于将多个可迭代对象打包成元组组成的迭代器。
它接收任意数量的可迭代对象作为参数,返回一个元组迭代器,每个元组包含来自各可迭代对象的对应位置元素。
主要特点包括:默认以最短的可迭代对象为准,可通过itertools.zip_longest()处理不同长度的情况。
常见应用场景包括创建字典、并行遍历多个列表、矩阵转置等。
zip()具有高效的内存使用(惰性求值),但需要注意zip对象只能使用一次,且不同长度时会丢失数据。
与enumerate()相比,zip()更适合处理多个序列的并行操作。
掌握zip()可以编写更简洁高效的Python代码。
Python zip() 函数详解
zip() 是 Python 的内置函数,用于将多个可迭代对象打包成元组组成的迭代器。
1. 基本语法
python
zip(*iterables)
参数:
*iterables:一个或多个可迭代对象(列表、元组、字符串等)
返回值:
- 返回一个元组迭代器,每个元组包含来自每个可迭代对象的对应位置元素
2. 基本用法
打包两个列表
python
names = ['Alice', 'Bob', 'Charlie']
scores = [85, 92, 78]
result = zip(names, scores)
print(result) # <zip object at 0x...>
print(list(result)) # [('Alice', 85), ('Bob', 92), ('Charlie', 78)]
打包三个列表
python
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
scores = [85, 92, 78]
result = list(zip(names, ages, scores))
print(result)
# [('Alice', 25, 85), ('Bob', 30, 92), ('Charlie', 35, 78)]
打包字符串
python
word1 = "abc"
word2 = "123"
result = list(zip(word1, word2))
print(result) # [('a', '1'), ('b', '2'), ('c', '3')]
3. 处理不同长度的可迭代对象
默认行为:以最短的为准
python
names = ['Alice', 'Bob', 'Charlie', 'David']
scores = [85, 92]
result = list(zip(names, scores))
print(result) # [('Alice', 85), ('Bob', 92)] # Charlie和David被忽略
使用 itertools.zip_longest() 以最长的为准
python
from itertools import zip_longest
names = ['Alice', 'Bob', 'Charlie', 'David']
scores = [85, 92]
result = list(zip_longest(names, scores))
print(result) # [('Alice', 85), ('Bob', 92), ('Charlie', None), ('David', None)]
# 指定填充值
result = list(zip_longest(names, scores, fillvalue=0))
print(result) # [('Alice', 85), ('Bob', 92), ('Charlie', 0), ('David', 0)]
4. 常见应用场景
场景1:创建字典
python
keys = ['name', 'age', 'city']
values = ['Alice', 25, 'Beijing']
# 使用 zip 创建字典
dictionary = dict(zip(keys, values))
print(dictionary) # {'name': 'Alice', 'age': 25, 'city': 'Beijing'}
场景2:并行遍历多个列表
python
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
cities = ['Beijing', 'Shanghai', 'Guangzhou']
for name, age, city in zip(names, ages, cities):
print(f'{name} is {age} years old and lives in {city}')
# 输出:
# Alice is 25 years old and lives in Beijing
# Bob is 30 years old and lives in Shanghai
# Charlie is 35 years old and lives in Guangzhou
场景3:矩阵转置
python
# 原始矩阵
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)]
# 如果需要列表而不是元组
transposed = [list(row) for row in zip(*matrix)]
print(transposed) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
场景4:拆解列表(解压)
python
# 压缩
pairs = [('Alice', 85), ('Bob', 92), ('Charlie', 78)]
names, scores = zip(*pairs)
print(names) # ('Alice', 'Bob', 'Charlie')
print(scores) # (85, 92, 78)
场景5:同时遍历字典的键和值
python
# 方法1:直接使用 items()
d = {'a': 1, 'b': 2, 'c': 3}
for key, value in d.items():
print(f'{key}: {value}')
# 方法2:使用 zip(不推荐,但可行)
for key, value in zip(d.keys(), d.values()):
print(f'{key}: {value}')
5. 实际应用示例
示例1:计算学生总分
python
students = ['Alice', 'Bob', 'Charlie']
scores_math = [85, 92, 78]
scores_english = [88, 85, 90]
scores_python = [95, 88, 92]
for student, math, eng, py in zip(students, scores_math, scores_english, scores_python):
total = math + eng + py
print(f'{student}: 总分 {total}')
# 输出:
# Alice: 总分 268
# Bob: 总分 265
# Charlie: 总分 260
示例2:格式化输出表格
python
headers = ['Name', 'Age', 'City']
data = [
['Alice', 25, 'Beijing'],
['Bob', 30, 'Shanghai'],
['Charlie', 35, 'Guangzhou']
]
# 打印表头
print(f"{headers[0]:<10} {headers[1]:<6} {headers[2]:<10}")
print("-" * 28)
# 打印数据
for row in data:
print(f"{row[0]:<10} {row[1]:<6} {row[2]:<10}")
# 或使用 zip 转置
for row in zip(*data):
print(f"{row[0]:<10} {row[1]:<6} {row[2]:<10}")
示例3:比较两个列表的差异
python
list1 = [1, 2, 3, 4, 5]
list2 = [1, 2, 0, 4, 6]
for a, b in zip(list1, list2):
if a != b:
print(f'差异: {a} vs {b}')
# 输出:
# 差异: 3 vs 0
# 差异: 5 vs 6
示例4:添加索引
python
names = ['Alice', 'Bob', 'Charlie']
# 使用 enumerate 更合适,但 zip 也可以
for i, name in zip(range(len(names)), names):
print(f'{i}: {name}')
# 更好的方式
for i, name in enumerate(names):
print(f'{i}: {name}')
示例5:处理多个列表的筛选
python
names = ['Alice', 'Bob', 'Charlie', 'David']
ages = [25, 30, 35, 40]
scores = [85, 92, 78, 88]
# 找出成绩大于80的学生
filtered = [(name, age, score) for name, age, score in zip(names, ages, scores) if score > 80]
print(filtered)
# [('Alice', 25, 85), ('Bob', 30, 92), ('David', 40, 88)]
6. zip() 的高级用法
使用 * 解包操作符
python
# 解包列表
data = [('a', 1), ('b', 2), ('c', 3)]
letters, numbers = zip(*data)
print(letters) # ('a', 'b', 'c')
print(numbers) # (1, 2, 3)
# 解包嵌套列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposed = list(zip(*matrix))
与 sorted() 结合使用
python
names = ['Charlie', 'Alice', 'Bob']
scores = [78, 85, 92]
# 按分数排序
sorted_pairs = sorted(zip(scores, names))
print(sorted_pairs) # [(78, 'Charlie'), (85, 'Alice'), (92, 'Bob')]
# 按分数排序后只取名字
sorted_names = [name for score, name in sorted(zip(scores, names))]
print(sorted_names) # ['Charlie', 'Alice', 'Bob']
7. 性能对比
python
import time
# 方法1:使用索引
list1 = list(range(10000))
list2 = list(range(10000))
start = time.time()
result = [(list1[i], list2[i]) for i in range(len(list1))]
print(f"索引方式: {time.time() - start:.5f}秒")
# 方法2:使用 zip
start = time.time()
result = list(zip(list1, list2))
print(f"zip方式: {time.time() - start:.5f}秒")
# zip 通常更快且更 Pythonic
8. 注意事项和常见陷阱
陷阱1:zip 只能使用一次
python
names = ['Alice', 'Bob', 'Charlie']
scores = [85, 92, 78]
zipped = zip(names, scores)
print(list(zipped)) # [('Alice', 85), ('Bob', 92), ('Charlie', 78)]
print(list(zipped)) # [] 第二次为空!
陷阱2:不同长度时的数据丢失
python
names = ['Alice', 'Bob', 'Charlie', 'David']
scores = [85, 92]
result = dict(zip(names, scores))
print(result) # {'Alice': 85, 'Bob': 92} # Charlie 和 David 丢失!
陷阱3:空可迭代对象
python
result = list(zip([], [1, 2, 3]))
print(result) # [] 空列表
9. 与其他函数对比
| 函数 | 功能 | 返回值 | 适用场景 |
|---|---|---|---|
zip() |
并行打包 | 元组迭代器 | 多个序列并行处理 |
map() |
应用函数 | 迭代器 | 对序列应用函数 |
enumerate() |
添加索引 | 索引-值对 | 需要索引的遍历 |
python
# zip vs enumerate
names = ['Alice', 'Bob', 'Charlie']
# zip 方式
for i, name in zip(range(len(names)), names):
print(i, name)
# enumerate 方式(更优)
for i, name in enumerate(names):
print(i, name)
10. 实用技巧汇总
python
# 1. 创建字典
d = dict(zip(['a', 'b', 'c'], [1, 2, 3]))
# 2. 并行循环
for a, b in zip(list_a, list_b):
pass
# 3. 矩阵转置
transposed = list(zip(*matrix))
# 4. 拆分成两个列表
list1, list2 = zip(*list_of_pairs)
# 5. 添加默认值(使用 zip_longest)
from itertools import zip_longest
pairs = list(zip_longest(list1, list2, fillvalue=0))
# 6. 生成相邻元素对
lst = [1, 2, 3, 4, 5]
pairs = list(zip(lst, lst[1:])) # [(1,2), (2,3), (3,4), (4,5)]
# 7. 生成偏移对
offset = 2
offset_pairs = list(zip(lst, lst[offset:])) # [(1,3), (2,4), (3,5)]
总结表
| 特性 | 说明 |
|---|---|
| 类型 | 内置函数 |
| 返回值 | zip 对象(迭代器) |
| 参数 | 多个可迭代对象 |
| 长度处理 | 以最短的为准 |
| 主要用途 | 并行打包、解包、字典创建 |
| 内存效率 | 高(惰性求值) |
| Pythonic | ✅ 非常 Pythonic |
最佳实践
-
✅ 使用
zip()进行并行遍历 -
✅ 使用
dict(zip(keys, values))创建字典 -
✅ 使用
zip(*matrix)进行矩阵转置 -
✅ 结合列表推导式进行筛选
-
⚠️ 注意不同长度的可迭代对象
-
⚠️ zip 对象只能使用一次
-
💡 需要填充值时使用
itertools.zip_longest()
zip() 是 Python 中最实用的函数之一,掌握它可以编写更简洁、更高效的代码!