pin_drop当前位置:知识文库 ❯ 图文
Python zip函数
目录
一、zip()函数简介
zip() 是Python内置函数,用于将多个可迭代对象"压缩"成一个迭代器,返回的每个元素是包含各可迭代对象对应位置元素的元组。就像拉链一样,将多个序列的对应位置元素配对。
代码示例
# zip()函数语法
zip(*iterables)
# 参数说明:
# *iterables - 一个或多个可迭代对象(列表、元组、字符串等)
# 返回值 - zip对象(迭代器),每个元素是元组
zip()函数名来源于"拉链"(zipper),形象地描述了它的工作原理:像拉上拉链一样,将多个序列的对应元素一一配对。
二、基础用法:并行遍历
zip()最常见的用途是并行遍历多个序列,这在处理相关联的数据时非常有用,比如姓名和年龄、学号和成绩等。
示例1:两个列表并行遍历
代码示例
names = ["张三", "李四", "王五"]
ages = [20, 22, 21]
# 使用zip并行遍历
for name, age in zip(names, ages):
print(f"{name}今年{age}岁")
# 输出结果
# 张三今年20岁
# 李四今年22岁
# 王五今年21岁
示例2:三个或更多列表
代码示例
students = ["张三", "李四", "王五"]
scores = [85, 92, 78]
grades = ["B", "A", "C"]
# 同时遍历三个列表
for name, score, grade in zip(students, scores, grades):
print(f"{name}: {score}分 - 等级{grade}")
# 查看zip返回的对象
zipped = zip(students, scores, grades)
print(f"zip对象类型: {type(zipped)}")
print(f"转为列表: {list(zipped)}")
# 输出结果
# 张三: 85分 - 等级B
# 李四: 92分 - 等级A
# 王五: 78分 - 等级C
# zip对象类型: <class 'zip'>
# 转为列表: [('张三', 85, 'B'), ('李四', 92, 'A'), ('王五', 78, 'C')]
示例3:创建索引对
代码示例
fruits = ["apple", "banana", "cherry"]
# 使用zip创建带索引的元组
indexed = list(zip(range(len(fruits)), fruits))
print(f"带索引的水果: {indexed}")
# 更推荐的方式:使用enumerate()
indexed_enum = list(enumerate(fruits))
print(f"enumerate结果: {indexed_enum}")
# 输出结果
# 带索引的水果: [(0, 'apple'), (1, 'banana'), (2, 'cherry')]
# enumerate结果: [(0, 'apple'), (1, 'banana'), (2, 'cherry')]
三、长度不一致时的截断行为
当传入zip()的可迭代对象长度不一致时,zip()会以**最短的序列为准**进行截断,超出部分会被忽略。这是zip()的重要特性,使用时需要特别注意。
示例1:截断行为演示
代码示例
names = ["张三", "李四", "王五", "赵六"]
scores = [85, 92, 78] # 少一个元素
# zip会以最短的为准
result = list(zip(names, scores))
print(f"zip结果: {result}")
print(f"被截断的元素: '{names[3]}' 被忽略")
# 输出结果
# zip结果: [('张三', 85), ('李四', 92), ('王五', 78)]
# 被截断的元素: '赵六' 被忽略
示例2:处理长度不一致的数据
代码示例
from itertools import zip_longest
names = ["张三", "李四", "王五", "赵六"]
scores = [85, 92, 78]
# 方式1:使用zip_longest填充默认值
result1 = list(zip_longest(names, scores, fillvalue="缺考"))
print(f"zip_longest结果: {result1}")
# 方式2:手动处理
max_len = max(len(names), len(scores))
result2 = []
for i in range(max_len):
name = names[i] if i < len(names) else None
score = scores[i] if i < len(scores) else None
result2.append((name, score))
print(f"手动处理结果: {result2}")
# 输出结果
# zip_longest结果: [('张三', 85), ('李四', 92), ('王五', 78), ('赵六', '缺考')]
# 手动处理结果: [('张三', 85), ('李四', 92), ('王五', 78), ('赵六', None)]
四、*解包操作
* 解包操作符可以与zip()配合使用,实现"解压缩"功能,将已配对的数据重新分离成独立的序列。
示例1:解压缩zip结果
代码示例
# 原始数据
names = ["张三", "李四", "王五"]
ages = [20, 22, 21]
# 压缩
zipped = list(zip(names, ages))
print(f"压缩后: {zipped}")
# 解压缩
unzipped_names, unzipped_ages = zip(*zipped)
print(f"解压后名字: {unzipped_names}")
print(f"解压后年龄: {unzipped_ages}")
# 验证是否一致
print(f"名字一致: {tuple(names) == unzipped_names}")
print(f"年龄一致: {tuple(ages) == unzipped_ages}")
# 输出结果
# 压缩后: [('张三', 20), ('李四', 22), ('王五', 21)]
# 解压后名字: ('张三', '李四', '王五')
# 解压后年龄: (20, 22, 21)
# 名字一致: True
# 年龄一致: True
示例2:矩阵转置
代码示例
# 矩阵转置(行列互换)
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
# 使用zip(*matrix)实现转置
transposed = list(zip(*matrix))
print(f"原矩阵:")
for row in matrix:
print(f" {row}")
print(f"\n转置后:")
for row in transposed:
print(f" {list(row)}")
# 输出结果
# 原矩阵:
# [1, 2, 3]
# [4, 5, 6]
# [7, 8, 9]
#
# 转置后:
# [1, 4, 7]
# [2, 5, 8]
# [3, 6, 9]
五、字典构建技巧
zip()与dict()结合是Python中构建字典的最优雅方式之一。只需将键列表和值列表配对,即可快速创建字典。
示例1:基础字典构建
代码示例
keys = ["name", "age", "city"]
values = ["张三", 20, "北京"]
# 使用zip+dict创建字典
person = dict(zip(keys, values))
print(f"创建的字典: {person}")
# 使用字典推导式
person2 = {k: v for k, v in zip(keys, values)}
print(f"字典推导式: {person2}")
# 输出结果
# 创建的字典: {'name': '张三', 'age': 20, 'city': '北京'}
# 字典推导式: {'name': '张三', 'age': 20, 'city': '北京'}
示例2:反转字典(键值互换)
代码示例
# 原始字典
scores = {"张三": 85, "李四": 92, "王五": 78}
# 反转字典
reversed_scores = dict(zip(scores.values(), scores.keys()))
print(f"原字典: {scores}")
print(f"反转后: {reversed_scores}")
# 多对一映射(相同值的处理)
students_by_score = {}
for score, name in zip(scores.values(), scores.keys()):
students_by_score.setdefault(score, []).append(name)
print(f"分数到姓名列表: {students_by_score}")
# 输出结果
# 原字典: {'张三': 85, '李四': 92, '王五': 78}
# 反转后: {85: '张三', 92: '李四', 78: '王五'}
# 分数到姓名列表: {85: ['张三'], 92: ['李四'], 78: ['王五']}
示例3:从多个列表创建复杂字典
代码示例
# 学生数据
names = ["张三", "李四", "王五"]
math_scores = [85, 92, 78]
english_scores = [90, 88, 82]
# 创建嵌套字典
students = {}
for name, math, english in zip(names, math_scores, english_scores):
students[name] = {
"math": math,
"english": english,
"average": (math + english) / 2,
}
print("学生成绩字典:")
for name, data in students.items():
print(f" {name}: {data}")
# 输出结果
# 学生成绩字典:
# 张三: {'math': 85, 'english': 90, 'average': 87.5}
# 李四: {'math': 92, 'english': 88, 'average': 90.0}
# 王五: {'math': 78, 'english': 82, 'average': 80.0}
六、zip()与itertools.zip_longest对比
七、注意事项
-
zip()返回迭代器:zip()返回的是迭代器对象,只能遍历一次。如果需要多次使用,需转换为列表:
list(zip(...))。 -
截断风险:当序列长度不一致时,zip()会静默截断,不会抛出异常。这可能导致数据丢失,使用时务必确保长度一致或明确接受截断行为。
-
单参数行为:传入单个可迭代对象时,zip()返回每个元素为单元素元组的迭代器:
list(zip([1,2,3]))返回[(1,), (2,), (3,)]。 -
无参数行为:不传入任何参数时,zip()返回空迭代器:
list(zip())返回[]。 -
内存效率:Python 3中zip()返回迭代器,惰性求值,内存效率高。Python 2中zip()返回列表,如需迭代器应使用
itertools.izip()。
提示:如果不确定序列长度是否一致,建议先检查或使用
itertools.zip_longest()。也可以使用strict=True参数(Python 3.10+),当长度不一致时抛出异常:zip(a, b, strict=True)。
小贴士
成批处理数据:zip()可用于将列表按固定大小分组。例如 list(zip(*[iter(data)]*n)) 可以将列表data按每组n个元素分组。这是一个经典技巧,利用了迭代器的特性。例如:data = [1,2,3,4,5,6]; list(zip(*[iter(data)]*2)) 返回 [(1,2), (3,4), (5,6)]。
常见问题
zip()和enumerate()有什么区别?
enumerate()用于给单个可迭代对象添加索引,返回(index, element)对。zip()用于将多个可迭代对象的对应元素配对。虽然可以用 zip(range(len(seq)), seq) 模拟enumerate(),但直接使用enumerate()更简洁高效。
如何避免zip()截断导致的数据丢失?
有三种方法:(1) 使用Python 3.10+的 zip(a, b, strict=True),长度不一致时抛出异常;(2) 使用 itertools.zip_longest() 填充缺失值;(3) 手动检查长度:if len(a) != len(b): raise ValueError()。
zip()可以用于字典吗?
可以。对字典使用zip()时,遍历的是字典的键。例如 zip(dict1, dict2) 会配对两个字典的键。常用场景是 dict(zip(keys, values)) 从键值列表创建字典,或 zip(dict.keys(), dict.values()) 获取键值对。
zip(*matrix)实现矩阵转置的原理是什么?
*matrix 将二维列表解包为多个一列表作为zip()的参数。例如 zip(*[[1,2,3],[4,5,6]]) 等价于 zip([1,2,3], [4,5,6]),会将每行的第一个元素配对、第二个元素配对,从而实现行列互换。
十、练习题
练习1
给定两个列表:subjects = ["数学", "英语", "物理", "化学"] 和 credits = [4, 3, 3, 2]。编写函数 create_course_dict(subjects, credits),使用zip()创建课程字典(课程名为键,学分为值),并计算总学分。编写完整代码并测试。
练习2
编写函数 transpose_matrix(matrix),使用zip(*matrix)实现矩阵转置。要求:(1) 处理非方阵情况;(2) 返回转置后的列表;(3) 验证 [[1,2,3],[4,5,6]] 和 [[1,2],[3,4],[5,6]] 的转置结果。编写完整代码并测试。
本文涉及AI创作
内容由AI创作,请仔细甄别