Python 迭代器与可迭代对象
目录
学习目标
- 理解可迭代对象(Iterable)和迭代器(Iterator)的概念
- 掌握
iter()和next()函数的使用 - 学会自定义迭代器
- 理解迭代器的工作原理和优势
1. 可迭代对象(Iterable)
可迭代对象是指可以使用 for 循环遍历的对象。
1.1 常见的可迭代对象
# 列表
my_list = [1, 2, 3]
for item in my_list:
print(item)
# 字符串
my_str = "Hello"
for char in my_str:
print(char)
# 字典(迭代的是键)
my_dict = {"a": 1, "b": 2}
for key in my_dict:
print(key)
# 元组
my_tuple = (10, 20, 30)
for num in my_tuple:
print(num)
# 集合
my_set = {1, 2, 3}
for item in my_set:
print(item)1.2 如何判断是否为可迭代对象
使用 collections.abc 模块中的 Iterable 进行判断:
from collections.abc import Iterable
# 判断对象是否可迭代
print(isinstance([1, 2, 3], Iterable)) # True
print(isinstance("hello", Iterable)) # True
print(isinstance({"a": 1}, Iterable)) # True
print(isinstance(100, Iterable)) # False
print(isinstance(3.14, Iterable)) # False2. 迭代器(Iterator)
迭代器是一个可以记住遍历位置的对象,它从集合的第一个元素开始访问,直到所有元素被访问完结束。
2.1 迭代器的两个核心方法
# iter() - 获取迭代器
# next() - 获取下一个元素
my_list = [1, 2, 3]
iterator = iter(my_list)
print(next(iterator)) # 1
print(next(iterator)) # 2
print(next(iterator)) # 3
# print(next(iterator)) # StopIteration 异常!2.2 迭代器的工作原理
def manual_iteration():
"""手动模拟 for 循环的迭代过程"""
my_list = ["a", "b", "c"]
iterator = iter(my_list)
while True:
try:
item = next(iterator)
print(f"获取到: {item}")
except StopIteration:
print("迭代结束")
break
manual_iteration()输出:
获取到: a
获取到: b
获取到: c
迭代结束2.3 如何判断是否为迭代器
from collections.abc import Iterator, Iterable
my_list = [1, 2, 3]
# 列表是可迭代对象,但不是迭代器
print(isinstance(my_list, Iterable)) # True
print(isinstance(my_list, Iterator)) # False
# 通过 iter() 获取迭代器
iterator = iter(my_list)
print(isinstance(iterator, Iterator)) # True
print(isinstance(iterator, Iterable)) # True(迭代器也是可迭代对象)3. 自定义迭代器
通过实现 __iter__() 和 __next__() 方法来自定义迭代器。
3.1 自定义范围迭代器
class MyRange:
"""自定义范围迭代器"""
def __init__(self, start, end, step=1):
self.start = start
self.end = end
self.step = step
self.current = start
def __iter__(self):
"""返回迭代器对象自身"""
self.current = self.start # 重置位置
return self
def __next__(self):
"""返回下一个元素"""
if self.current >= self.end:
raise StopIteration
value = self.current
self.current += self.step
return value
# 使用自定义迭代器
for num in MyRange(0, 5):
print(num, end=" ") # 0 1 2 3 4
print()
# 支持步长
for num in MyRange(0, 10, 2):
print(num, end=" ") # 0 2 4 6 83.2 自定义列表反向迭代器
class ReverseIterator:
"""反向迭代器"""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
self.index = len(self.data)
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index -= 1
return self.data[self.index]
# 反向迭代
my_list = ["apple", "banana", "cherry"]
for item in ReverseIterator(my_list):
print(item)输出:
cherry
banana
apple3.3 自定义斐波那契数列迭代器
class FibonacciIterator:
"""斐波那契数列迭代器"""
def __init__(self, max_count):
self.max_count = max_count
self.count = 0
self.a, self.b = 0, 1
def __iter__(self):
self.count = 0
self.a, self.b = 0, 1
return self
def __next__(self):
if self.count >= self.max_count:
raise StopIteration
value = self.a
self.a, self.b = self.b, self.a + self.b
self.count += 1
return value
# 生成前10个斐波那契数
fib = FibonacciIterator(10)
print("斐波那契数列:", list(fib))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]4. 迭代器的优势
4.1 惰性计算(Lazy Evaluation)
# 列表会一次性占用大量内存
big_list = list(range(1000000))
# 迭代器按需生成,节省内存
big_iterator = iter(range(1000000))
# 每次只取一个值
print(next(big_iterator)) # 0
print(next(big_iterator)) # 14.2 无限序列
class InfiniteCounter:
"""无限计数器"""
def __init__(self, start=0):
self.current = start
def __iter__(self):
return self
def __next__(self):
value = self.current
self.current += 1
return value
# 取前5个
from itertools import islice
counter = InfiniteCounter()
first_five = list(islice(counter, 5))
print(first_five) # [0, 1, 2, 3, 4]4.3 只能遍历一次
iterator = iter([1, 2, 3])
# 第一次遍历
for item in iterator:
print(item) # 1 2 3
# 第二次遍历 - 迭代器已耗尽
for item in iterator:
print(item) # 无输出5. 可迭代对象 vs 迭代器
| 特性 | 可迭代对象 (Iterable) | 迭代器 (Iterator) |
|---|---|---|
__iter__() |
有 | 有 |
__next__() |
无 | 有 |
| 可重复使用 | 是 | 否(一次性) |
| 示例 | list, str, dict | iter(list) 的结果 |
# 可迭代对象每次调用 iter() 都返回新迭代器
my_list = [1, 2, 3]
iter1 = iter(my_list)
iter2 = iter(my_list)
print(iter1 is iter2) # False(不同对象)
# 迭代器调用 iter() 返回自身
iterator = iter(my_list)
print(iter(iterator) is iterator) # True(同一个对象)6. 内置迭代工具
6.1 enumerate
fruits = ["apple", "banana", "cherry"]
# 同时获取索引和值
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 指定起始索引
for index, fruit in enumerate(fruits, start=1):
print(f"{index}: {fruit}")6.2 zip
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
cities = ["北京", "上海", "广州"]
# 并行迭代多个序列
for name, age, city in zip(names, ages, cities):
print(f"{name}, {age}岁, {city}")
# 使用 zip 创建字典
info = dict(zip(names, ages))
print(info) # {'Alice': 25, 'Bob': 30, 'Charlie': 35}6.3 itertools 模块
import itertools
# count - 无限计数
for i in itertools.count(10, 2):
if i > 20:
break
print(i, end=" ") # 10 12 14 16 18 20
print()
# cycle - 无限循环
for i, char in enumerate(itertools.cycle("AB")):
if i >= 6:
break
print(char, end=" ") # A B A B A B
print()
# chain - 连接多个迭代器
for item in itertools.chain([1, 2], [3, 4], [5, 6]):
print(item, end=" ") # 1 2 3 4 5 6
print()
# combinations - 组合
for combo in itertools.combinations([1, 2, 3], 2):
print(combo, end=" ") # (1, 2) (1, 3) (2, 3)
print()
# permutations - 排列
for perm in itertools.permutations([1, 2, 3], 2):
print(perm, end=" ") # (1, 2) (1, 3) (2, 1) (2, 3) (3, 1) (3, 2)本节小结
- 可迭代对象:能被
for循环遍历的对象,实现了__iter__()方法 - 迭代器:实现了
__iter__()和__next__()的对象,只能遍历一次 - 自定义迭代器:通过实现这两个魔术方法创建自己的迭代器
- 优势:惰性计算节省内存、支持无限序列
- 工具:
enumerate、zip、itertools等内置工具非常实用
练习
- 创建一个自定义迭代器
Countdown,实现倒计时功能(从 n 到 0) - 实现一个迭代器,可以遍历文件的每一行并返回行号和内容
- 使用
itertools生成扑克牌的所有组合 - 写一个迭代器,能够遍历二叉树的节点(先序遍历)