Python中zip()函数并行遍历多个序列的示例详解

 更新时间:2026年07月13日 08:42:49   作者:星河耀银海  
还在用range(len())手动配对数据吗,本文将全面解析Python zip函数,从并行遍历、构建字典到矩阵转置和高级解包技巧,让你的代码更简洁优雅,轻松应对多列表同步处理

一、开篇:当三个列表需要同步处理时

在实际开发中,我们经常遇到这样的场景:用户姓名在一个列表,年龄在另一个列表,邮箱在第三个列表——它们通过相同的索引对应同一个人。

不用zip的写法:

names = ["张三", "李四", "王五"]
ages = [25, 30, 28]
emails = ["zs@test.com", "ls@test.com", "ww@test.com"]

# ❌ 老式写法
for i in range(len(names)):
    print(f"{names[i]}, {ages[i]}岁, {emails[i]}")

用zip的优雅写法:

# ✅ Pythonic!
for name, age, email in zip(names, ages, emails):
    print(f"{name}, {age}岁, {email}")

zip()就像一个"拉链",把多个序列的对应位置"拉"在一起。今天我们就来全面掌握zip()的用法、细节和高级技巧。

二、zip()的基本用法

2.1 核心功能

# zip(*iterables) —— 将多个可迭代对象的对应元素打包成元组

numbers = [1, 2, 3]
letters = ['a', 'b', 'c']
symbols = ['!', '@', '#']

# 基本使用
zipped = zip(numbers, letters, symbols)
print(list(zipped))  # [(1, 'a', '!'), (2, 'b', '@'), (3, 'c', '#')]

# 在for循环中直接解包
for num, letter, sym in zip(numbers, letters, symbols):
    print(f"{num}{letter}{sym}", end=' ')
# 输出: 1a! 2b@ 3c#

2.2 长度不一致时的行为

# zip() 按最短的可迭代对象截断
short = [1, 2]
long_list = [1, 2, 3, 4, 5]

print(list(zip(short, long_list)))
# [(1, 1), (2, 2)] —— 只有2对!

# ⚠️ 多余的元素被默默丢弃了!
# 如果你不能接受数据丢失,需要使用 itertools.zip_longest

from itertools import zip_longest

print(list(zip_longest(short, long_list)))
# [(1, 1), (2, 2), (None, 3), (None, 4), (None, 5)]

# 指定填充值
print(list(zip_longest(short, long_list, fillvalue=0)))
# [(1, 1), (2, 2), (0, 3), (0, 4), (0, 5)]

# zip函数的巧妙技巧:检查序列长度
# 如果想要在长度不一致时报错
def strict_zip(*iterables):
    """严格的zip——长度不一致时抛出异常"""
    sentinel = object()
    for i, items in enumerate(zip_longest(*iterables, fillvalue=sentinel)):
        if any(item is sentinel for item in items):
            raise ValueError(f"可迭代对象长度不一致!在第{i}个位置出现缺失")
        yield items

# Python 3.10+ 可以直接用 strict 参数
# list(zip(short, long_list, strict=True))  # ValueError!

2.3 zip对象是迭代器

# zip返回的是一个迭代器,只能遍历一次
z = zip([1, 2, 3], ['a', 'b', 'c'])

print("第一次遍历:")
for item in z:
    print(f"  {item}")

print("第二次遍历:")
for item in z:
    print(f"  {item}")  # 什么都不输出!迭代器已耗尽

# ✅ 需要多次使用时,转为列表
z_list = list(zip([1, 2, 3], ['a', 'b', 'c']))
for item in z_list:
    print(item)
for item in z_list:    # 可以再次使用
    print(item)

三、zip()的经典应用

3.1 并行遍历

这是zip最常见的用法:

# 多列数据同步处理
students = ["张三", "李四", "王五", "赵六"]
math_scores = [85, 92, 78, 90]
english_scores = [88, 86, 95, 72]
physics_scores = [90, 78, 85, 88]

print(f"{'姓名':<8} {'数学':<6} {'英语':<6} {'物理':<6} {'平均':<6}")
print("-" * 40)

for name, math, eng, phy in zip(students, math_scores, english_scores, physics_scores):
    avg = (math + eng + phy) / 3
    print(f"{name:<8} {math:<6} {eng:<6} {phy:<6} {avg:<6.1f}")

3.2 构建字典

# zip + dict = 快速创建字典
keys = ["name", "age", "city", "email"]
values = ["张三", 25, "北京", "zs@test.com"]

user = dict(zip(keys, values))
print(user)
# {'name': '张三', 'age': 25, 'city': '北京', 'email': 'zs@test.com'}

# 从两个列表创建映射表
countries = ["中国", "美国", "日本", "英国"]
capitals = ["北京", "华盛顿", "东京", "伦敦"]
country_to_capital = dict(zip(countries, capitals))
print(country_to_capital)

# 从CSV数据一次性构建
headers = ["id", "product", "price", "stock"]
row = [101, "机械键盘", 299.00, 50]
product = dict(zip(headers, row))
print(product)

3.3 转置矩阵

# zip的经典用途:矩阵转置
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
]

# 转置 = zip(*matrix)
transposed = list(zip(*matrix))
print("转置前:")
for row in matrix:
    print(row)
print("转置后:")
for row in transposed:
    print(row)

# 输出:
# 转置前: [1,2,3] [4,5,6] [7,8,9]
# 转置后: (1,4,7) (2,5,8) (3,6,9)

# * 解包运算符将matrix的每一行作为zip的单独参数
# zip([1,2,3], [4,5,6], [7,8,9])
# → (1,4,7), (2,5,8), (3,6,9)

# 实际应用:旋转表格数据
def rotate_table(table):
    """旋转表格(行列互换)"""
    return [list(row) for row in zip(*table)]

data = [
    ["姓名", "张三", "李四", "王五"],
    ["数学", 85, 92, 78],
    ["英语", 88, 86, 95],
]
rotated = rotate_table(data)
for row in rotated:
    print(row)

3.4 成对处理

# 处理序列中的相邻元素对
data = [3, 1, 4, 1, 5, 9, 2, 6]

# zip(data, data[1:]) —— 元素与其下一个元素成对
for prev, curr in zip(data, data[1:]):
    change = "↑" if curr > prev else "↓" if curr < prev else "→"
    print(f"{prev} → {curr} {change}")

# 计算相邻移动平均
moving_avg = [(a + b) / 2 for a, b in zip(data, data[1:])]
print(f"移动平均: {moving_avg}")

# 比较两个相邻版本的差异
old_version = list(range(10))
new_version = [0, 1, 2, 9, 4, 5, 6, 7, 8, 3]  # 3和9互换了

changes = [
    (i, old, new)
    for i, (old, new) in enumerate(zip(old_version, new_version))
    if old != new
]
for idx, old, new in changes:
    print(f"位置{idx}: {old} → {new}")

四、zip()与*解包的组合

4.1 zip和unzip

# zip() 和 zip(*zipped) 是一对可逆操作
pairs = [(1, 'a'), (2, 'b'), (3, 'c')]

# unzip:把配对的数据分离回原始序列
numbers, letters = zip(*pairs)
print(numbers)  # (1, 2, 3)
print(letters)  # ('a', 'b', 'c')

# 完整示例
users = [
    ("张三", 25, "北京"),
    ("李四", 30, "上海"),
    ("王五", 28, "广州"),
]

names, ages, cities = zip(*users)
print(f"姓名: {names}")
print(f"年龄: {ages}")
print(f"城市: {cities}")

# 计算统计信息
print(f"平均年龄: {sum(ages) / len(ages):.1f}")

4.2 数据行与列的转换

# 从行式数据转到列式数据,反之亦然
# 行式:每条记录是一个元组/列表
# 列式:每列是一个列表

rows = [
    ("张三", 85, 92, 78),
    ("李四", 90, 88, 95),
    ("王五", 76, 85, 82),
]

# 行 → 列
columns = list(zip(*rows))
print("列式数据:")
print(f"姓名列: {columns[0]}")
print(f"数学列: {columns[1]}")
print(f"英语列: {columns[2]}")
print(f"物理列: {columns[3]}")

# 列 → 行
rows_again = list(zip(*columns))
print("\n还原为行式:")
for row in rows_again:
    print(row)

五、zip()的高级用法

5.1 创建迭代器对比

# 使用zip创建"滑动窗口"
def sliding_window(iterable, n):
    """生成滑动窗口"""
    iterators = zip(*(iterable[i:] for i in range(n)))
    return iterators

data = list(range(10))
windows = list(sliding_window(data, 3))
print("滑动窗口(大小=3):")
for w in windows:
    print(f"  {w}")

# 等价于:
# zip(data[0:], data[1:], data[2:])

# itertools中有更高效的实现
# from itertools import pairwise  # Python 3.10+

5.2 构建多键排序

# zip用于多键排序(按多个条件排序)
students = [
    ("张三", 85, 18),
    ("李四", 85, 17),
    ("王五", 90, 19),
    ("赵六", 85, 17),
    ("钱七", 78, 20),
]

# 要求:先按成绩降序,再按年龄升序,最后按姓名升序
# 技巧:把排序键打包进zip

# 方法1:使用key函数
sorted_students = sorted(
    students,
    key=lambda s: (-s[1], s[2], s[0])
)

print("排序后:")
for name, score, age in sorted_students:
    print(f"  {name}: 成绩{score}, 年龄{age}")

# 方法2:使用zip(装饰-排序-去装饰模式)
def sort_by_multiple_keys(data):
    # 装饰:创建排序用的键
    decorated = [(-s[1], s[2], s[0], s) for s in data]
    # 排序
    decorated.sort()
    # 去装饰
    return [item[-1] for item in decorated]

5.3 同时遍历多个字典

# zip遍历多个字典的对应键值
dict1 = {"a": 1, "b": 2, "c": 3}
dict2 = {"a": 10, "b": 20, "c": 30}
dict3 = {"a": 100, "b": 200, "c": 300}

# 确保按键的顺序一致
keys = dict1.keys()

for k, v1, v2, v3 in zip(keys, dict1.values(), dict2.values(), dict3.values()):
    total = v1 + v2 + v3
    print(f"{k}: {v1} + {v2} + {v3} = {total}")

# 更安全的方式:使用字典推导
# 确保三个字典的键相同
for k in dict1:
    if k in dict2 and k in dict3:
        print(f"{k}: {dict1[k]}, {dict2[k]}, {dict3[k]}")

六、实战案例

6.1 成绩合并计算器

class ScoreMerger:
    """多科目成绩合并计算 —— zip的综合应用"""
    
    def __init__(self):
        self.students = []
    
    def load_data(self, names, *score_lists):
        """加载数据:姓名列表 + 各科成绩列表"""
        self.names = names
        self.subjects = [f"科目{i+1}" for i in range(len(score_lists))]
        self.score_matrix = list(zip(*score_lists))  # 每个学生的各科成绩
    
    def get_student_totals(self):
        """计算每个学生的总分"""
        totals = [sum(scores) for scores in self.score_matrix]
        return list(zip(self.names, totals))  # 配对上姓名
    
    def get_subject_averages(self):
        """计算每个科目的平均分"""
        score_columns = list(zip(*self.score_matrix))  # 转置:每列=每科
        avgs = [sum(col) / len(col) for col in score_columns]
        return list(zip(self.subjects, avgs))
    
    def get_rankings(self):
        """获取排名"""
        totals = self.get_student_totals()
        # 按总分降序
        totals.sort(key=lambda x: x[1], reverse=True)
        return [(rank, name, score) 
                for rank, (name, score) in enumerate(totals, start=1)]
    
    def print_report(self):
        """打印成绩报告"""
        print("=" * 50)
        print("📊 成绩总览")
        print("=" * 50)
        
        # 表头
        header = ["姓名"] + self.subjects + ["总分"]
        print("  ".join(f"{h:<8}" for h in header))
        print("-" * (9 * len(header)))
        
        # 数据行
        for name, scores in zip(self.names, self.score_matrix):
            total = sum(scores)
            row = [name] + list(scores) + [total]
            print("  ".join(f"{str(v):<8}" for v in row))
        
        # 排名
        print(f"\n🏆 排名:")
        for rank, name, score in self.get_rankings():
            medal = {1: "🥇", 2: "🥈", 3: "🥉"}.get(rank, f"  {rank}.")
            print(f"  {medal} {name}: {score}分")
        
        # 科目平均
        print(f"\n📈 科目平均分:")
        for subject, avg in self.get_subject_averages():
            print(f"  {subject}: {avg:.1f}")

# 测试
merger = ScoreMerger()
merger.load_data(
    ["张三", "李四", "王五", "赵六", "钱七"],
    [85, 92, 78, 90, 88],   # 科目1
    [88, 86, 95, 72, 91],   # 科目2
    [90, 78, 85, 88, 82],   # 科目3
)
merger.print_report()

6.2 配置文件对比工具

def compare_configs(config1, config2):
    """对比两个配置字典的差异 —— zip的应用"""
    all_keys = sorted(set(config1) | set(config2))
    
    changes = []
    for key in all_keys:
        v1 = config1.get(key, "<不存在>")
        v2 = config2.get(key, "<不存在>")
        
        if v1 != v2:
            changes.append({
                "key": key,
                "old": v1,
                "new": v2,
                "type": "added" if v1 == "<不存在>" 
                         else "removed" if v2 == "<不存在>" 
                         else "modified"
            })
    
    # 打印对比报告
    if not changes:
        print("✅ 两个配置完全相同")
        return
    
    print("=" * 60)
    print("📋 配置对比报告")
    print("=" * 60)
    
    for i, change in enumerate(changes, 1):
        typ = change["type"]
        key = change["key"]
        
        if typ == "added":
            print(f"{i}. [+] {key}: {change['new']}")
        elif typ == "removed":
            print(f"{i}. [-] {key}: {change['old']} (已删除)")
        else:
            print(f"{i}. [~] {key}: {change['old']} → {change['new']}")

# 测试
old_config = {
    "host": "localhost",
    "port": 8080,
    "debug": True,
    "timeout": 30,
    "retry": 3,
}
new_config = {
    "host": "0.0.0.0",
    "port": 443,
    "debug": False,
    "timeout": 30,
    "ssl": True,
}

compare_configs(old_config, new_config)

七、本章小结

本文我们全面学习了zip()函数:

基本功能zip(*iterables)将多个可迭代对象的对应元素打包成元组。按最短序列截断,返回迭代器。

zip_longestitertools.zip_longest按最长序列处理,缺失位置用fillvalue填充。

经典应用

  • 并行遍历:多列数据同步处理
  • 构建字典:dict(zip(keys, values))
  • 矩阵转置:zip(*matrix)
  • 成对处理:zip(data, data[1:])

zip与*解包zip(*pairs)可以"解压缩",把配对数据分离回原始序列。

Python 3.10+ strict参数zip(a, b, strict=True)在长度不一致时抛出ValueError。

zip()是Python中"让代码更简洁"的利器。当你发现自己在用range(len())或者一个个地手动配对数据时,想想zip()——它几乎总能提供更优雅的方案。⌨️ 下一篇文章,我们将学习break与continue循环控制。

以上就是Python中zip()函数并行遍历多个序列的示例详解的详细内容,更多关于Python zip并行遍历多个序列的资料请关注脚本之家其它相关文章!

相关文章

  • Python OpenCV 彩色与灰度图像的转换实现

    Python OpenCV 彩色与灰度图像的转换实现

    为了加快处理速度在图像处理算法中,往往需要把彩色图像转换为灰度图像,本文主要介绍了Python OpenCV 彩色与灰度图像的转换实现,感兴趣的可以了解一下
    2021-06-06
  • Python函数中的全局变量详解

    Python函数中的全局变量详解

    大家好,本篇文章主要讲的是Python函数中的全局变量详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2022-01-01
  • 对python3中的RE(正则表达式)-详细总结

    对python3中的RE(正则表达式)-详细总结

    今天小编就为大家分享一篇对python3中的RE(正则表达式)-详细总结,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • PyTorch中dataloader制作自定义数据集的实现示例

    PyTorch中dataloader制作自定义数据集的实现示例

    本文主要介绍了PyTorch中dataloader制作自定义数据集的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-05-05
  • Django框架安装及项目创建过程解析

    Django框架安装及项目创建过程解析

    这篇文章主要介绍了Django框架安装及项目创建过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • python实现某考试系统生成word试卷

    python实现某考试系统生成word试卷

    这篇文章主要为大家详细介绍了python实现某考试系统生成word试卷,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • 利用 PyCharm 实现本地代码和远端的实时同步功能

    利用 PyCharm 实现本地代码和远端的实时同步功能

    这篇文章主要介绍了利用 PyCharm 实现本地代码和远端的实时同步功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • 对numpy中向量式三目运算符详解

    对numpy中向量式三目运算符详解

    今天小编就为大家分享一篇对numpy中向量式三目运算符详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-10-10
  • 50行Python代码获取高考志愿信息的实现方法

    50行Python代码获取高考志愿信息的实现方法

    这篇文章主要介绍了50行Python代码获取高考志愿信息的实现方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-07-07
  • PyTorch-Forecasting一个新的时间序列预测库使用详解

    PyTorch-Forecasting一个新的时间序列预测库使用详解

    这篇文章主要为大家介绍了PyTorch-Forecasting一个新的时间序列预测库示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05

最新评论