查看全课大纲(第 47 / 51 节)
  1. 1.Python 是什么?为什么值得学?
  2. 2.如何为 Python 编程准备一个“全家桶”环境?
  3. 3.Python 有哪几种执行方法?
  4. 4.行与缩进到底有什么用?
  5. 5.注释有什么用,怎么写?
  6. 6.变量:如何给数据起个好名字?
  7. 7.运算符的优先级和常见坑点是什么?
  8. 8.Python 中,数字和布尔值究竟有哪几种?
  9. 9.输入函数 `input()` 和文件读取 `open()` 怎么用?
  10. 10.如何将程序的结果展示给用户或保存下来?
  11. 11.CSV 文件怎么读怎么写才方便?
  12. 12.列表是什么,如何创建和访问它?
  13. 13.列表的修改操作,有哪些方法?
  14. 14.列表切片为什么能取到部分元素?排序和查找又该怎么用?
  15. 15.判断语句:如何让程序根据条件做不同的事?
  16. 16.for 循环如何遍历序列中的元素?
  17. 17.while 循环什么时候才会停?
  18. 18.while 循环的结束条件,你写对了吗?
  19. 19.循环中途想提前结束,怎么办?
  20. 20.`break` 和 `continue` 到底有什么区别?
  21. 21.列表推导式如何让代码更简洁高效?
  22. 22.字符串怎么定义、拼接和操作?
  23. 23.元组:为什么定义单个元素时要加逗号?
  24. 24.集合(set)怎么用?如何快速去重和做集合运算?
  25. 25.字典是什么,为什么比列表更方便?
  26. 26.字典的增删改查与遍历,如何避免 KeyError?
  27. 27.函数里的变量,为什么有的能用有的不能用?
  28. 28.在函数内部修改全局变量,为什么有时不生效?
  29. 29.函数里能修改全局变量吗?返回值怎么用?
  30. 30.匿名函数:如何用 lambda 快速定义简单函数?
  31. 31.面向对象编程是什么,为什么需要它?
  32. 32.类中的方法和属性到底怎么定义和使用?
  33. 33.如何控制对对象内部属性和方法的访问?
  34. 34.异常发生时,程序会怎样继续执行?
  35. 35.如何组织代码:包和模块
  36. 36.`if __name__ == '__main__'` 到底有什么用?
  37. 37.如何用 IDE 的 Debug 功能排查程序错误?
  38. 38.Matplotlib 绘图的第一步该做什么?
  39. 39.Figure 是什么,如何设置图形尺寸?
  40. 40.如何自定义 Matplotlib 的坐标轴?
  41. 41.如何为图表添加图例,让不同曲线一目了然?
  42. 42.饼图怎么画才能直观展示数据占比?
  43. 43.如何用 Matplotlib 绘制散点图?
  44. 44.柱状图怎么画?
  45. 45.如何使用 Matplotlib 绘制等高线图?
  46. 46.如何在 Matplotlib 中绘制子图?
  47. 47.zip 函数如何把多个列表“打包”在一起?
  48. 48.如何给可迭代对象加上索引?
  49. 49.random 模块如何生成随机数?
  50. 50.math 模块怎么用?
  51. 51.Counter 如何快速统计元素出现次数?

zip 函数如何把多个列表“打包”在一起?

约 7 分钟

小象实战讲义 · Python 编程从入门到实践

在编程中,我们常常需要把多个列表(或其他可迭代对象)中相同位置的元素关联起来,比如把姓名列表与成绩列表一一对应。zip 函数就是为这类需求而生的“打包”工具。本节是第 6 章《一些常用的函数》的第 1 节,你将学会如何合并数据、如何反向“解压”,以及遇到长度不一致时结果会怎样。

💡 核心导读

  • 作用:把多个可迭代对象中对应位置的元素打包成一个个元组。
  • 语法:zip(iterable1, iterable2, ...),返回一个 zip 对象。
  • 版本差异:Python 2 返回元组列表,Python 3 返回 zip 对象,需要转换才能查看内容。
  • 长度处理:传入的对象长度不一致时,结果长度由最短的那个决定。
  • 反向操作:zip(*zipped) 可以把打包结果解压回原来的多列。

zip 函数是什么?

zip 是 Python 的内置函数,作用是把多个可遍历的数据对象(列表、元组、字符串等)中对应位置的元素组合到一起。它的调用格式很简单:

zip(iterable1, iterable2, ...)

注意版本差异:在 Python 2 中,zip 直接返回由元组组成的列表;在 Python 3 中,它返回一个 zip 对象。本节所有示例都按 Python 3 讲解,所以打印之前通常要先做一次类型转换。

怎么用 zip 打包数据?

基本打包与结果查看

假设我们有两个列表,分别存储学号和姓名,希望把它们一一对应起来。

# 定义两个列表
ids = [1001, 1002, 1003]
names = ['小明', '小红', '小刚']

# 打包:把两个列表中对应位置的元素配成元组
zipped = zip(ids, names)

# Python 3 中 zip 返回的是 zip 对象,不是列表
print(type(zipped))

# 转成列表才能看到打包后的内容
print(list(zipped))

# 长度不一致时:结果只保留到最短的那个列表
list_a = [1, 2, 3]
list_b = ['a', 'b', 'c', 'd', 'e']  # 比 list_a 长
print(list(zip(list_a, list_b)))
<class 'zip'>
[(1001, '小明'), (1002, '小红'), (1003, '小刚')]
[(1, 'a'), (2, 'b'), (3, 'c')]

zip(ids, names) 把 1001 和 '小明'、1002 和 '小红'、1003 和 '小刚' 分别配成元组。zip 对象本身不直接显示内容,所以示例里用 list() 转换了一次。

长度不一致时以最短为准

如果两个列表长度不同,zip 不会报错,也不会补齐,而是以最短的那个为准,较长列表多出来的元素会被忽略。上面的代码块最后一行就是这种情况:list_b 有两个多余元素,但结果只到 list_a 的长度。

如果业务上要求两边长度必须对齐,应在调用 zip 之前自己先把数据补齐,而不是指望 zip 自动处理。

转换成字典或集合

zip 的结果可以直接交给 dict(),快速建立映射关系:每个元组的第一个元素成为键,第二个元素成为值。

keys = ['name', 'age', 'city']
values = ['李雷', 18, '北京']

# 转成字典:元组的第一个元素作键,第二个元素作值
print(dict(zip(keys, values)))

# 也可以转成集合;集合无序,打印前先 sorted 保证输出稳定
print(sorted(set(zip(keys, values))))
{'name': '李雷', 'age': 18, 'city': '北京'}
[('age', 18), ('city', '北京'), ('name', '李雷')]

除了列表和字典,转成集合同样可行。集合只保留打包后的元组,并会自动去重,因此打印时先排序,才能得到稳定、可对照的结果。

解压:zip(*zipped)

有打包就有解压。做法仍然是调用 zip,只是在传入参数前加一个星号 *,把列表“摊开”成多个参数。

# 一个已经打包好的列表
paired_data = [('苹果', 5), ('香蕉', 3), ('橘子', 8)]

# 前面的 * 把列表摊开成三个参数,再交给 zip 重新组合
unzipped = zip(*paired_data)
print(list(unzipped))
[('苹果', '香蕉', '橘子'), (5, 3, 8)]

解压后得到两个元组:第一个是所有水果名,第二个是所有数量,正好恢复了原来的“列”结构。需要注意,解压返回的同样是 zip 对象,所以也要转换后才能查看。

典型场景:同时遍历多个序列

zip 最常见的用途是在 for 循环里同时取出多个序列中对应位置的元素,省掉手动维护下标。

# 名字和体重一一对应
names = ['Tom', 'Jerry', 'Dora']
weights = [15, 5, 30]

for name, weight in zip(names, weights):
    print('{} 的重量是 {} 公斤'.format(name, weight))
Tom 的重量是 15 公斤
Jerry 的重量是 5 公斤
Dora 的重量是 30 公斤

循环每一轮,zip 提供一个 (名字, 体重) 元组,再用两个循环变量分别接住,代码比按下标访问清晰得多。

📝 动手练一练

  1. 有两个列表 fruits = ['apple', 'banana', 'cherry'] 和 prices = [5, 3, 7],请用 zip 把它们组合成字典。再对 a = [10, 20, 30, 40]、b = [1, 2]、c = [100, 200, 300] 执行 zip(a, b, c),转成列表后结果是什么?为什么?
👉 点击查看参考答案

思路:组合字典直接用 dict(zip(...));三个列表长度不同,结果长度由最短的 b(长度 2)决定。

fruits = ['apple', 'banana', 'cherry']
prices = [5, 3, 7]
print(dict(zip(fruits, prices)))

a = [10, 20, 30, 40]
b = [1, 2]
c = [100, 200, 300]
print(list(zip(a, b, c)))
{'apple': 5, 'banana': 3, 'cherry': 7}
[(10, 1, 100), (20, 2, 200)]

常见错误

错误写法现象或报错原因正确写法
print(zip(a, b))输出类似 <zip object at 0x...>Python 3 的 zip 返回对象,不直接显示内容print(list(zip(a, b)))
以为结果长度与最长输入一致长列表尾部数据被丢弃,程序逻辑出错zip 以最短的输入为准调用前先把数据补齐,或只传等长序列
对同一个 zip 对象遍历两次第二次遍历得不到任何内容zip 对象是迭代器,遍历一次后元素就被消费完需要多次使用先转成列表:pairs = list(zip(a, b))

旧写法对照

下表列出旧教程中可能见到的写法与 Python 3 的对应写法,按现代 Python 3 学习即可:

Python 2 旧写法Python 3 正确写法说明
zip(a, b) 直接得到元组列表list(zip(a, b))Python 3 中返回 zip 对象,需转换才能查看

小结

  • zip(iterable1, iterable2, ...) 把多个可迭代对象中对应位置的元素打包成元组。
  • Python 3 中返回 zip 对象,查看内容前要转成 list、dict、set 等类型。
  • 输入长度不一致时,结果以最短的那个为准,多余元素被忽略。
  • zip(*zipped) 是解压操作,能把打包结果还原成原来的多列。
  • zip 常用于在 for 循环中同时遍历多个相关序列。

📋 行动清单

  • 把示例中的 ids、names 改成三个列表,用 zip 打包后转成列表查看结果。
  • 对打包结果执行 zip(*...) 解压,观察是否恢复了原始数据。
  • 故意让两个列表长度不同,确认输出只保留到最短列表的长度。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 第6章代码包:zip(含1 个 Notebook)
    ZIP · 636B
    下载