pin_drop当前位置:知识文库 ❯ 图文

Python标准库itertools详解

一、itertools概述

itertools 是Python标准库中一个非常强大的模块,专门用于创建高效迭代器。它提供了一系列用于操作迭代器的函数,这些函数可以帮助我们以更优雅、更高效的方式处理循环和迭代操作。

itertools模块中的函数主要分为三大类:无限迭代器、有限迭代器和组合生成器。这些函数返回的都是迭代器对象,具有惰性求值的特性,可以大大节省内存消耗。


二、无限迭代器

无限迭代器会生成无限序列,使用时需要配合break或其他条件来终止循环。

1. count(start=0, step=1)

start开始,按step步长无限递增生成数字:

代码示例

import itertools

# 从0开始,步长为1
for i in itertools.count():
    if i > 5:
        break
    print(i)
# 输出: 0 1 2 3 4 5

# 从10开始,步长为2
for i in itertools.count(10, 2):
    if i > 20:
        break
    print(i)
# 输出: 10 12 14 16 18 20

# 支持负数步长
for i in itertools.count(10, -1):
    if i < 5:
        break
    print(i)
# 输出: 10 9 8 7 6

2. cycle(iterable)

无限循环遍历给定的可迭代对象:

代码示例

import itertools

# 循环遍历列表
colors = itertools.cycle(['红', '绿', '蓝'])
for _ in range(8):
    print(next(colors))
# 输出: 红 绿 蓝 红 绿 蓝 红 绿

# 实现交替效果
for i, color in zip(range(6), itertools.cycle(['A', 'B'])):
    print(f'{i}:{color}')
# 输出: 0:A 1:B 2:A 3:B 4:A 5:B

3. repeat(object[, times])

重复生成同一个对象,如果指定了times则重复指定次数:

代码示例

import itertools

# 无限重复
r = itertools.repeat('Hello', 3)
print(list(r))  # 输出: ['Hello', 'Hello', 'Hello']

# 配合map使用
result = list(map(pow, range(1, 5), itertools.repeat(2)))
print(result)  # 输出: [1, 4, 9, 16]

# 创建固定值列表
fixed_values = list(itertools.repeat(None, 5))
print(fixed_values)  # 输出: [None, None, None, None, None]

三、有限迭代器

有限迭代器在输入迭代器耗尽时停止生成。

1. chain(*iterables)

将多个可迭代对象连接成一个迭代器:

代码示例

import itertools

# 连接多个列表
result = list(itertools.chain([1, 2], [3, 4], [5, 6]))
print(result)  # 输出: [1, 2, 3, 4, 5, 6]

# 连接字符串
chars = itertools.chain('abc', 'def')
print(''.join(chars))  # 输出: abcdef

# chain.from_iterable: 从单个可迭代对象中连接
nested = [[1, 2], [3, 4], [5]]
flat = list(itertools.chain.from_iterable(nested))
print(flat)  # 输出: [1, 2, 3, 4, 5]

2. compress(data, selectors)

根据选择器筛选数据,只保留选择器为真的对应元素:

代码示例

import itertools

data = ['A', 'B', 'C', 'D', 'E']
selectors = [1, 0, 1, 0, 1]

result = list(itertools.compress(data, selectors))
print(result)  # 输出: ['A', 'C', 'E']

# 实际应用场景:过滤偶数
numbers = list(range(10))
is_even = [n % 2 == 0 for n in numbers]
evens = list(itertools.compress(numbers, is_even))
print(evens)  # 输出: [0, 2, 4, 6, 8]

3. islice(iterable, stop) / islice(iterable, start, stop[, step])

对迭代器进行切片操作,类似于列表切片:

代码示例

import itertools

# 从无限迭代器中获取有限部分
result = list(itertools.islice(itertools.count(), 5))
print(result)  # 输出: [0, 1, 2, 3, 4]

# 指定起始和结束位置
result = list(itertools.islice(range(10), 2, 8))
print(result)  # 输出: [2, 3, 4, 5, 6, 7]

# 指定步长
result = list(itertools.islice(range(10), 0, 10, 2))
print(result)  # 输出: [0, 2, 4, 6, 8]

4. 其他常用有限迭代器

代码示例

import itertools

# accumulate: 累积求和或其他函数
nums = [1, 2, 3, 4, 5]
print(list(itertools.accumulate(nums)))  # [1, 3, 6, 10, 15]

# 累积乘法
import operator
print(list(itertools.accumulate(nums, operator.mul)))  # [1, 2, 6, 24, 120]

# starmap: 使用参数元组解包调用函数
points = [(2, 3), (4, 5), (6, 7)]
print(list(itertools.starmap(pow, points)))  # [8, 1024, 279936]

# takewhile / dropwhile
print(list(itertools.takewhile(lambda x: x < 5, [1, 3, 5, 2, 4])))  # [1, 3]
print(list(itertools.dropwhile(lambda x: x < 5, [1, 3, 5, 2, 4])))  # [5, 2, 4]

四、组合生成器

组合生成器用于生成排列组合等数学运算结果。

1. product(*iterables, repeat=1)

计算笛卡尔积,等价于嵌套的for循环:

代码示例

import itertools

# 两个列表的笛卡尔积
result = list(itertools.product('AB', '12'))
print(result)  # [('A', '1'), ('A', '2'), ('B', '1'), ('B', '2')]

# 使用repeat参数
result = list(itertools.product('AB', repeat=2))
print(result)  # [('A', 'A'), ('A', 'B'), ('B', 'A'), ('B', 'B')]

# 实际场景:生成坐标点
x_axis = range(2)
y_axis = range(3)
coords = list(itertools.product(x_axis, y_axis))
print(coords)  # [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

2. permutations(iterable, r=None)

生成所有可能的排列(考虑顺序):

代码示例

import itertools

# 全排列
result = list(itertools.permutations('ABC'))
print(result)
# [('A', 'B', 'C'), ('A', 'C', 'B'), ('B', 'A', 'C'),
#  ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')]

# 指定长度
result = list(itertools.permutations('ABC', 2))
print(result)
# [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]

3. combinations(iterable, r)

生成组合(不考虑顺序,元素不重复):

代码示例

import itertools

# 从4个元素中选2个
result = list(itertools.combinations('ABCD', 2))
print(result)
# [('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]

# 实际场景:从团队中选人组队
team = ['张三', '李四', '王五', '赵六']
pairs = list(itertools.combinations(team, 2))
for pair in pairs:
    print(f'{pair[0]} 和 {pair[1]}')

4. combinations_with_replacement(iterable, r)

生成允许元素重复的组合:

代码示例

import itertools

# 允许重复的组合
result = list(itertools.combinations_with_replacement('ABC', 2))
print(result)
# [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')]
组合函数 是否考虑顺序 是否允许重复 示例输入 输出数量
permutations ABC, r=2 6
combinations ABC, r=2 3
combinations_with_replacement ABC, r=2 6
product AB, repeat=2 4

五、代码示例与实战应用

实战1:矩阵转置

代码示例

import itertools

def transpose_matrix(matrix):
    """使用zip实现矩阵转置"""
    return [list(row) for row in zip(*matrix)]

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

result = transpose_matrix(matrix)
for row in result:
    print(row)
# 输出:
# [1, 4, 7]
# [2, 5, 8]
# [3, 6, 9]

实战2:数据分组

代码示例

import itertools

# 将数据按条件分组
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 按奇偶分组
def is_even(x):
    return x % 2 == 0

# 先排序(groupby要求相邻元素具有相同的key)
sorted_data = sorted(data, key=is_even)
groups = itertools.groupby(sorted_data, key=is_even)

for key, group in groups:
    label = "偶数" if key else "奇数"
    print(f"{label}: {list(group)}")
# 输出:
# 奇数: [1, 3, 5, 7, 9]
# 偶数: [2, 4, 6, 8, 10]

实战3:批量处理任务

代码示例

import itertools

def batch_process(items, batch_size):
    """将数据分批处理"""
    it = iter(items)
    while True:
        batch = list(itertools.islice(it, batch_size))
        if not batch:
            break
        yield batch

# 模拟大批量数据处理
data = list(range(23))
for batch_num, batch in enumerate(batch_process(data, 5), 1):
    print(f"批次 {batch_num}: {batch}")
# 输出:
# 批次 1: [0, 1, 2, 3, 4]
# 批次 2: [5, 6, 7, 8, 9]
# 批次 3: [10, 11, 12, 13, 14]
# 批次 4: [15, 16, 17, 18, 19]
# 批次 5: [20, 21, 22]

实战4:展平嵌套列表

代码示例

import itertools

def flatten(nested_list):
    """展平一层嵌套列表"""
    return list(itertools.chain.from_iterable(nested_list))

nested = [[1, 2, 3], [4, 5], [6], [7, 8, 9, 10]]
flat = flatten(nested)
print(flat)  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 处理字典列表
records = [
    {'name': '张三', 'scores': [85, 90, 78]},
    {'name': '李四', 'scores': [92, 88, 95]},
    {'name': '王五', 'scores': [76, 82, 89]}
]

all_scores = list(itertools.chain.from_iterable(
    r['scores'] for r in records
))
print(f"所有分数: {all_scores}")
print(f"平均分: {sum(all_scores) / len(all_scores):.2f}")
# 输出:
# 所有分数: [85, 90, 78, 92, 88, 95, 76, 82, 89]
# 平均分: 86.11

六、itertools与内置函数对比

对比项 itertools 内置函数/列表推导式
内存使用 惰性求值,节省内存 可能创建完整列表
性能 C语言实现,性能更优 Python实现,相对较慢
代码可读性 语义明确,可读性好 复杂场景可能冗长
无限序列 原生支持(count/cycle) 需要手动实现
组合排列 内置支持,简洁高效 需要递归或复杂逻辑

七、注意事项与最佳实践

1. 无限迭代器的使用陷阱

注意:使用count()cycle()等无限迭代器时,必须确保有终止条件,否则会导致无限循环。直接将其转换为列表会导致内存溢出。

代码示例

# 错误示例:会导致程序卡死
# list(itertools.count())  # 千万不要这样做!

# 正确示例:使用islice限制数量
import itertools
limited = list(itertools.islice(itertools.count(), 10))
print(limited)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

2. groupby的排序要求

注意groupby()只对相邻的相同key值元素进行分组,使用前通常需要先对数据进行排序。

3. 迭代器只能消费一次

注意:itertools返回的迭代器只能迭代一次,迭代完成后就为空。如果需要多次使用,请将其转换为列表或使用tee()函数。

代码示例

import itertools

# 迭代器只能消费一次
it = itertools.chain([1, 2], [3, 4])
print(list(it))  # [1, 2, 3, 4]
print(list(it))  # [] 已经为空!

# 使用tee复制迭代器
original = itertools.chain([1, 2], [3, 4])
it1, it2 = itertools.tee(original, 2)
print(list(it1))  # [1, 2, 3, 4]
print(list(it2))  # [1, 2, 3, 4]

小贴士

itertools模块的函数都是用C语言实现的,因此在处理大规模数据时,其性能通常远优于纯Python的等价实现。在需要处理大量数据或复杂迭代逻辑时,优先考虑使用itertools。更多Python标准库的详细介绍,可以参考Python官方文档


八、课程小结

  • 无限迭代器:count、cycle、repeat用于生成无限或重复序列,使用时注意设置终止条件

  • 有限迭代器:chain、compress、islice、accumulate等用于处理和转换有限序列

  • 组合生成器:product、permutations、combinations用于生成排列组合,是解决组合数学问题的利器

  • 惰性求值:所有itertools函数返回的都是迭代器,按需生成元素,节省内存

  • 性能优势:C语言实现,在处理大规模数据时性能优于纯Python实现

常见问题

itertools和列表推导式有什么区别?

列表推导式会立即创建完整的列表,占用较多内存;而itertools返回迭代器,采用惰性求值,只在需要时生成元素,内存效率更高。此外,itertools的函数是C语言实现的,执行速度通常更快。

如何将itertools迭代器转换为列表?

使用list()函数即可,例如:list(itertools.chain([1,2], [3,4]))。但注意无限迭代器不能直接转换,否则会导致程序卡死。

product和permutations有什么区别?

product计算笛卡尔积,允许元素自身重复(相当于有放回抽样);permutations生成排列,不允许元素重复(相当于无放回抽样)。例如product('AB', repeat=2)会产生AA、BB,而permutations('AB', 2)只会产生AB、BA。

itertools适合处理什么场景?

itertools特别适合:1)大规模数据处理(惰性求值节省内存);2)组合数学问题(排列组合生成);3)数据流处理(如分批处理、滑动窗口);4)需要高效连接或筛选多个数据源的场景。

练习1

使用itertools.combinations编写程序,从一个列表中找出所有和为10的两个数的组合。例如输入[1, 3, 5, 7, 9, 2, 8],输出所有和为10的配对。

练习2

编写一个函数,接收一个嵌套的字典(如学生成绩表),使用itertools.chain.from_iterable将所有成绩展平,并计算总平均分、最高分和最低分。

标签: itertools 迭代器 Python标准库 排列组合 惰性求值 Python入门

本文涉及AI创作

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

list快速访问

上一篇: Python标准库collections:高级容器类型 下一篇: Python标准库functools详解

poll相关推荐