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() itertools.zip_longest()
长度不一致时 以最短为准截断 以最长为准,填充默认值
返回值类型 zip对象(迭代器) zip_longest对象(迭代器)
填充参数 fillvalue(默认None)
导入方式 内置函数,直接使用 需from itertools import
适用场景 确定长度一致的数据 长度可能不一致的数据

七、注意事项

  • 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]] 的转置结果。编写完整代码并测试。

标签: zip函数 Python内置函数 并行遍历 解包操作 字典构建 迭代器 Python教程

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python reversed sorted sum函数 下一篇: Python模块导入import

poll相关推荐