Python3 可迭代对象

本文中交替出现 Python 的编译模式和交互模式代码块,为便于区分,带有 >>> 的 Python 代码块为交互模式,其余 Python 代码块为编译模式。

可迭代对象是Python3 最伟大的发明,是Python3区别于其它编程语言的最显著特征。掌握好可迭代对象才是真正学好了Python3.

可迭代对象(Iterable)

定义

可迭代对象(Iterable)是指在 Python 中能够使用迭代器进行遍历的对象。它包括了各种容器对象,如列表(list)、元组(tuple)、集合(set)、字典(dict)以及字符串等。

可迭代对象的特点是可以通过 for 循环来遍历其中的元素,或者使用内置的 iter() 函数将其转换为迭代器对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 列表是可迭代对象
my_list = [1, 2, 3, 4, 5]
for item in my_list:
print(item)

# 元组也是可迭代对象
my_tuple = (1, 2, 3, 4, 5)
for item in my_tuple:
print(item)

# 字符串是可迭代对象
my_string = "Hello"
for char in my_string:
print(char)

基本概念和操作

在 Python 中,可迭代对象(Iterable) 是一个可以被逐个取出元素的对象,常用于 for 循环、生成器表达式、函数 iter() 中。


判断是否是可迭代对象

1
2
3
4
print(isinstance([1, 2, 3], Iterable))      # True(列表)
print(isinstance("hello", Iterable)) # True(字符串)
print(isinstance(123, Iterable)) # False(整数)
print(isinstance((x for x in range(10)), Iterable)) # True(生成器属于可迭代对象)

常见可迭代对象类型

类型 示例 说明
list [1, 2, 3] 可重复遍历,可变
tuple (1, 2, 3) 不可变
str "abc" 每个字符是一个元素
dict {"a": 1, "b": 2} 遍历时是键
set {1, 2, 3} 无序不重复元素
range range(10) 整数序列生成
generator (x for x in range(10)) 一次性遍历,惰性计算
file open('a.txt') 行级读取,每次一行
enumerate enumerate(lst) 下标+元素
zip zip(a, b) 元素打包

可迭代对象的高级应用

枚举(enumerate
1
2
3
lst = ["a", "b", "c"]
for index, value in enumerate(lst):
print(index, value)

输出:

1
2
3
0 a
1 b
2 c
同时遍历多个序列(zip
1
2
3
4
5
6
7
names = ["Tom", "Jerry"]
scores = [90, 85]

for name, score in zip(names, scores):
print(name, score)

[print(f"{name} {score}") for name, score in zip(names, scores)]

输出:

1
2
3
4
Tom 90
Jerry 85
Tom 90
Jerry 85
解包可迭代对象(* 运算符)
1
2
3
a, b, *rest = [1, 2, 3, 4, 5]
print(a, b) # 1 2
print(rest) # [3, 4, 5]

迭代器(Iterator)

定义

迭代器(Iterator)是一种可以实现惰性计算的对象,可以被用来遍历可迭代对象中的元素。迭代器是一种特殊的对象,它实现了 __iter__()__next__() 方法,这使得它可以被 next() 函数调用,并且可以逐个返回元素,直到没有元素可返回时抛出 StopIteration 异常。

迭代器的主要特点是它只在需要时才生成下一个值,这种延迟计算的方式使得迭代器在处理大数据集时非常高效,因为它不会一次性将所有数据都加载到内存中,而是按需生成和处理数据。

1
2
3
4
5
6
7
8
my_list = [1, 2, 3, 4, 5]
my_iterator = iter(my_list) # 使用iter()函数将列表转换为迭代器

print(next(my_iterator)) # 输出迭代器的下一个元素
print(next(my_iterator)) # 输出迭代器的下一个元素
print(next(my_iterator)) # 输出迭代器的下一个元素
print(next(my_iterator)) # 输出迭代器的下一个元素
print(next(my_iterator)) # 输出迭代器的下一个元素

基本操作

将可迭代对象转为迭代器:iter()

1
2
3
4
5
s = "hello"
it = iter(s) # 将字符串变成迭代器

print(next(it)) # h
print(next(it)) # e

可迭代对象与迭代器对比

概念 是否惰性计算 是否可 next() 是否可 for
Iterable ❌ 否 ❌ 不可 ✅ 可以
Iterator ✅ 是 ✅ 可以 ✅ 可以
1
2
3
4
5
6
7
8
lst = [1, 2, 3]
it = iter(lst)

print(isinstance(lst, Iterable)) # True
print(isinstance(lst, Iterator)) # False

print(isinstance(it, Iterator)) # True
print(next(it)) # 1

使用for 循环操作迭代器关系

1
2
3
4
5
6
7
# 等价于 for i in [1, 2, 3]
it = iter([1, 2, 3])
while True:
try:
print(next(it))
except StopIteration:
break

Python 3 中返回迭代器的内置函数及其应用示例

以下是在 Python 3 中返回迭代器(而非列表)的常用内置函数,它们具有惰性求值特性,适用于大数据处理:

1. map(function, iterable, ...)

返回将函数应用于每个元素的迭代器

1
2
3
4
5
6
7
8
# 计算数字的平方
squares = map(lambda x: x**2, [1, 2, 3, 4])
print(next(squares)) # 输出: 1
print(list(squares)) # 输出: [4, 9, 16] (注意第一个元素已消耗)

# 多序列并行处理
combined = map(lambda a, b: f"{a}-{b}", ['A', 'B'], [1, 2])
print(list(combined)) # 输出: ['A-1', 'B-2']

2. filter(function, iterable)

返回满足条件元素的迭代器

1
2
3
4
5
6
7
# 筛选偶数
numbers = filter(lambda x: x % 2 == 0, range(10))
print(list(numbers)) # 输出: [0, 2, 4, 6, 8]

# 筛选非空字符串
words = filter(None, ["", "hello", None, "world"])
print(list(words)) # 输出: ['hello', 'world']

3. zip(*iterables)

返回聚合多个可迭代对象的迭代器

1
2
3
4
5
6
7
8
9
10
# 合并姓名和年龄
names = ["Alice", "Bob"]
ages = [25, 30]
zipped = zip(names, ages)
print(dict(zipped)) # 输出: {'Alice': 25, 'Bob': 30}

# 不等长序列处理
numbers = [1, 2, 3]
letters = ['a', 'b']
print(list(zip(numbers, letters))) # 输出: [(1, 'a'), (2, 'b')]

4. enumerate(iterable, start=0)

返回带索引的元素迭代器

1
2
3
4
5
6
7
8
9
10
11
# 带索引遍历
fruits = ['apple', 'banana', 'cherry']
for i, fruit in enumerate(fruits, 1):
print(f"{i}. {fruit}")
# 输出:
# 1. apple
# 2. banana
# 3. cherry

# 创建索引字典
print(dict(enumerate(fruits))) # 输出: {0: 'apple', 1: 'banana', 2: 'cherry'}

5. reversed(sequence)

返回反向访问的迭代器

1
2
3
4
5
6
7
8
# 反向遍历列表
colors = ['red', 'green', 'blue']
reversed_colors = reversed(colors)
print(list(reversed_colors)) # 输出: ['blue', 'green', 'red']

# 反向字符串处理
text = "Python"
print(''.join(reversed(text))) # 输出: 'nohtyP'

6. iter(object[, sentinel])

返回对象的迭代器

1
2
3
4
5
6
7
8
# 基础用法
numbers = iter([10, 20, 30])
print(next(numbers)) # 输出: 10

# 带哨兵值 - 读取文件直到空行
with open('data.txt') as f:
for line in iter(f.readline, ''):
print(line.strip())

7. dict.keys(), dict.values(), dict.items()

返回字典视图对象(可迭代)

1
2
3
4
5
6
7
8
9
10
11
12
# 动态字典操作
person = {'name': 'Alice', 'age': 25, 'job': 'Engineer'}

# 键迭代器
print(list(person.keys())) # 输出: ['name', 'age', 'job']

# 值迭代器
print(list(person.values())) # 输出: ['Alice', 25, 'Engineer']

# 键值对迭代器
for key, value in person.items():
print(f"{key}: {value}")

关键特性总结

这些函数均返回的是迭代器,比如map对象也是返回一个迭代器。

函数 返回类型 内存效率 是否一次性 典型应用场景
map() map对象 ✅ 高效 ✅ 是 数据转换/批量操作
filter() filter对象 ✅ 高效 ✅ 是 条件筛选/数据清洗
zip() zip对象 ✅ 高效 ✅ 是 多序列合并/矩阵转置
enumerate() enumerate对象 ✅ 高效 ✅ 是 带索引遍历/创建索引映射
reversed() 反向迭代器 ✅ 高效 ✅ 是 逆序处理/栈操作
iter() 迭代器 ✅ 高效 ✅ 是 自定义迭代/分块读取
dict.views() 字典视图 ✅ 动态 ❌ 可重用 字典遍历/实时更新

使用注意事项

  1. 一次性消耗:这些迭代器大多只能遍历一次

    1
    2
    3
    mapped = map(str, [1, 2])
    list(mapped) # ['1', '2']
    list(mapped) # [] 已耗尽
  2. 惰性求值:元素只在请求时计算

    1
    2
    # 不会立即执行所有平方计算
    big_squares = map(lambda x: x**2, range(1000000))
  3. 类型转换:需要持久化结果时转换为容器类型

    1
    filtered = tuple(filter(lambda x: x > 5, [3, 6, 8]))
  4. 内存优势:处理大文件时特别高效

    1
    2
    3
    4
    5
    # 仅需少量内存处理大文件
    with open('huge.log') as f:
    error_lines = filter(lambda line: 'ERROR' in line, f)
    for error in error_lines:
    process(error)

这些迭代器返回函数是 Python 函数式编程的核心工具,特别适合处理大数据流和构建高效的数据处理管道。


生成器(Generator)

生成器(Generator)是一种特殊的迭代器,它可以在需要时动态生成值,而不是一次性将所有值存储在内存中。生成器使用 yield 关键字来定义生成值的逻辑,每次调用生成器的 __next__() 方法时,它会从上一次的 yield 语句处继续执行,直到遇到下一个 yield 或者函数结束。

生成器在实现上更加简洁和高效,因为它不需要显式地维护整个序列,而是在每次迭代中动态生成下一个值,这种惰性计算的方式使得生成器非常适合处理大数据集或者无限序列。

Python 中有两种定义生成器的方式

生成器函数

使用 def 关键字定义的函数,其中包含 yield 语句来产生值。

1
2
3
4
5
6
7
8
9
def my_generator():
yield 1
yield 2
yield 3

gen = my_generator()
print(next(gen)) # 输出:1
print(next(gen)) # 输出:2
print(next(gen)) # 输出:3

生成器表达式

类似于列表推导式,使用圆括号来生成一个生成器。

1
2
3
4
5
gen = (x ** 2 for x in range(5))
print(next(gen)) # 输出:0
print(next(gen)) # 输出:1
print(next(gen)) # 输出:4
print(next(gen)) # 输出:9

生成器的应用

1. 生成器函数创建的数据

使用 yield 关键字定义的函数返回的对象:

1
2
3
4
5
6
7
8
9
10
def count_down(n):
while n > 0:
yield n
n -= 1

# 调用生成器函数返回生成器对象
gen = count_down(3) # 属于生成器
print(next(gen)) # 输出: 3
print(list(gen)) # list相当于一次性全部消费生成器。输出: [2, 1],因为3被消费了
print(type(gen)) # <class 'generator'>
1
2
3
3
[2, 1]
<class 'generator'>

2. 生成器表达式创建的数据

使用类似列表推导式但用圆括号 () 包裹的表达式:

1
2
3
4
5
gen = (x**2 for x in range(1, 4))  # 属于生成器
print(type(gen)) # <class 'generator'>
print(next(gen)) # 1
print(list(gen)) # [4, 9]
# 生成器是迭代器的一种特殊形式

生成器的核心特征

  1. 惰性计算
    只在调用 next() 时生成值(不提前计算所有结果)

    1
    2
    gen = (x for x in range(3))
    print(next(gen)) # 0(首次调用时计算)
  2. 一次性使用
    遍历结束后不可复用:

    1
    2
    3
    gen = (x for x in range(2))
    list(gen) # [0, 1]
    list(gen) # [](已耗尽)
  3. 内存高效
    不存储完整数据集(对比列表推导式):

    1
    2
    3
    import sys
    sys.getsizeof([x for x in range(1000000)]) # 一个列表,约 8 MB
    sys.getsizeof((x for x in range(1000000))) # 一个娇小的生成器,约 128 Bytes

常见误辨别的非生成器案例

对象类型 是否生成器 原因
range(5) 返回 range 对象(惰性序列)
zip([1,2], [3,4]) 返回 zip 对象(迭代器)
open('file.txt') 返回文件对象(迭代器)
列表 [x for x in...] 列表推导式返回完整列表对象
(x for x in range(5)) 似乎只有这个内置函数返回生成器

快速检测方法

1
2
3
4
5
6
import types
def is_generator(obj):
return isinstance(obj, types.GeneratorType)

print(is_generator((x for x in []))) # True
print(is_generator([1,2,3])) # False

Python面向对象:自定义类分别实现可迭代对象、迭代器、生成器

下面我将设计四个自定义类,分别演示不同迭代特性的实现方式,并提供详细的使用示例:

1. 仅实现 __getitem__ 的可迭代对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class SequenceIterable:
"""通过下标访问的可迭代对象 (非迭代器)"""
def __init__(self, *args):
self.data = list(args)

def __getitem__(self, index):
# 支持切片和索引访问
if isinstance(index, slice):
return self.data[index]
return self.data[index]

def __len__(self):
return len(self.data)

# 演示
seq = SequenceIterable(10, 20, 30, 40, 50)

print("1. 下标访问的可迭代对象:")
print(f"索引访问: seq[2] = {seq[2]}") # 30
print(f"切片操作: seq[1:4] = {seq[1:4]}") # [20, 30, 40]
print(f"长度: {len(seq)}") # 5

# 可迭代但非迭代器
print("遍历结果:")
for item in seq:
print(item, end=" ") # 10 20 30 40 50
print("\n" + "-"*50)

输出

1
2
3
4
5
6
7
1. 下标访问的可迭代对象:
索引访问: seq[2] = 30
切片操作: seq[1:4] = [20, 30, 40]
长度: 5
遍历结果:
10 20 30 40 50
--------------------------------------------------

2. 实现 __iter__ 的可迭代对象(非迭代器)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class ClassicIterable:
"""经典可迭代对象 (非迭代器)"""
def __init__(self, start, end):
self.start = start
self.end = end

def __iter__(self):
# 返回独立的迭代器实例
return RangeIterator(self.start, self.end)

class RangeIterator:
"""配套迭代器"""
def __init__(self, start, end):
self.current = start
self.end = end

def __iter__(self):
return self

def __next__(self):
if self.current >= self.end:
raise StopIteration
value = self.current
self.current += 1
return value

# 演示
iterable = ClassicIterable(5, 10)

print("2. 经典可迭代对象:")
print("第一次遍历:")
for num in iterable:
print(num, end=" ") # 5 6 7 8 9

print("\n第二次遍历 (可复用):")
for num in iterable:
print(num, end=" ") # 5 6 7 8 9

print("\n" + "-"*50)

输出

1
2
3
4
5
6
7
8
--------------------------------------------------
PS E:\education\quzia_pac\pythonforhyr> python .\1.py
2. 经典可迭代对象:
第一次遍历:
5 6 7 8 9
第二次遍历 (可复用):
5 6 7 8 9
--------------------------------------------------

3. 同时实现 __iter____next__ 的迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class SquareIterator:
"""自身就是迭代器"""
def __init__(self, max_value):
self.current = 0
self.max = max_value

def __iter__(self):
return self

def __next__(self):
if self.current >= self.max:
raise StopIteration
result = self.current ** 2
self.current += 1
return result

# 演示
iterator = SquareIterator(5)

print("3. 自身迭代器:")
print("第一次遍历:")
for square in iterator:
print(square, end=" ") # 0 1 4 9 16

print("\n第二次遍历 (已耗尽):")
print("剩余元素:", list(iterator)) # [] (空列表)

# 手动迭代演示
iterator2 = SquareIterator(3)
print("\n手动迭代:")
print(next(iterator2)) # 0
print(next(iterator2)) # 1
print(next(iterator2)) # 4
# print(next(iterator2)) # 触发 StopIteration
print("-"*50)

输出

1
2
3
4
5
6
7
8
9
10
11
3. 自身迭代器:
第一次遍历:
0 1 4 9 16
第二次遍历 (已耗尽):
剩余元素: []

手动迭代:
0
1
4
--------------------------------------------------

4. 生成器类(使用 yield

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class PrimeGenerator:
"""生成器类 (无限素数序列)"""
def __init__(self):
self.primes = []
self.current = 2

def __iter__(self):
while True:
if all(self.current % p != 0 for p in self.primes if p*p <= self.current):
self.primes.append(self.current)
yield self.current
self.current += 1

# 演示
print("4. 生成器类 (无限素数):")
primes = PrimeGenerator()
prime_iter = iter(primes)

print("前10个素数:")
for _ in range(10):
print(next(prime_iter), end=" ") # 2 3 5 7 11 13 17 19 23 29

print("\n下一个素数:", next(prime_iter)) # 31

# 使用itertools获取更多
import itertools
print("第11-15个素数:", list(itertools.islice(prime_iter, 4))) # [37, 41, 43, 47]
print("-"*50)

输出

1
2
3
4
5
6
4. 生成器类 (无限素数):
前10个素数:
2 3 5 7 11 13 17 19 23 29
下一个素数: 31
第11-15个素数: [37, 41, 43, 47]
--------------------------------------------------

类型验证代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from collections.abc import Iterable, Iterator
import types

# 类型验证函数
def check_type(obj, name):
print(f"\n{name}类型验证:")
print(f"是可迭代对象? {isinstance(obj, Iterable)}")
print(f"是迭代器? {isinstance(obj, Iterator)}")
print(f"是生成器? {isinstance(obj, types.GeneratorType)}")

# 验证各个实例
check_type(SequenceIterable(1, 2, 3), "SequenceIterable")
check_type(ClassicIterable(1, 5), "ClassicIterable")
check_type(iter(ClassicIterable(1, 5)), "ClassicIterable的迭代器")
check_type(SquareIterator(3), "SquareIterator")
check_type(iter(PrimeGenerator()), "PrimeGenerator迭代器")

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SequenceIterable类型验证:
是可迭代对象? True
是迭代器? False
是生成器? False

ClassicIterable类型验证:
是可迭代对象? True
是迭代器? False
是生成器? False

ClassicIterable的迭代器类型验证:
是可迭代对象? True
是迭代器? True
是生成器? False

SquareIterator类型验证:
是可迭代对象? True
是迭代器? True
是生成器? False

PrimeGenerator迭代器类型验证:
是可迭代对象? True
是迭代器? True
是生成器? True

关键区别总结:

  1. 可迭代对象

    • 实现了 __iter__()__getitem__()
    • 可通过 iter() 获取迭代器
    • 可多次遍历(如 ClassicIterable
  2. 迭代器

    • 同时实现 __iter__()__next__()
    • __iter__() 返回自身
    • 一次性使用(如 SquareIterator
  3. 生成器

    • 特殊迭代器
    • 使用 yield 关键字实现
    • 自动维护状态(如 PrimeGenerator
    • 类型为 types.GeneratorType
  4. 下标访问对象

    • 仅实现 __getitem__()
    • 支持索引和切片
    • 可迭代但 isinstance(obj, Iterable) 返回 False

表格总结

Python3 可迭代对象(Iterable)、序列(Sequence)、迭代器(Iterator)、生成器(generator)的关键定义和包含类型:

概念 定义 包含类型/实现要求 核心特性
可迭代对象 (Iterable) 能够一次返回一个成员的对象,支持 for...in 循环遍历 序列list, str, tuple, bytes
非序列dict, 文件对象
自定义类:实现了 __iter__()__getitem__() 方法的类。
可通过 iter(obj) 转换为迭代器;isinstance 检测仅对实现 __iter__() 方法的有效
序列 (Sequence) 可迭代对象的子集,支持高效整数索引访问和长度获取 list, str, tuple, bytes 必须实现:
__getitem__()(索引访问)
__len__()(长度获取)
注意:dict 不是序列
迭代器 (Iterator) 表示数据流的对象,通过 next() 逐个返回元素,耗尽后抛出 StopIteration 内置转换iter(可迭代对象)(如 list_iterator
自定义类:同时实现 __iter__()(返回自身)和 __next__() 方法
一次性消费(遍历后不可复用)
迭代器本身也是可迭代对象。
生成器 (Generator) 特殊的迭代器,由包含 yield 的函数或生成器表达式创建 生成器函数def gen(): yield ...
生成器表达式(x for x in range(n))
惰性求值(按需生成值)
继承迭代器的所有特性

关键特性:

  1. 包含关系 :生成器、迭代器、序列均属于可迭代对象。
    生成器 ⊂ 迭代器 ⊂ 可迭代对象
    序列 ⊂ 可迭代对象

  2. 转换关系

    • 可迭代对象 → 迭代器:iter(可迭代对象)
    • 序列 → 迭代器:iter(序列)(如 iter([1,2,3])
  3. 判断方法

    • 可迭代对象iter(obj) 不报错即为可迭代(最可靠)
    • 迭代器isinstance(obj, Iterator) 且实现 __next__()
    • 生成器isinstance(obj, types.GeneratorType)

⚠️ 注意

  • 仅实现 __getitem__() 的类是可迭代对象,但 isinstance(obj, Iterable) 返回 False
  • 迭代器必须同时实现 __iter__()(返回自身)和 __next__() 才能被正确识别。
  • 生成器是语法糖,本质是实现了 __iter__()__next__() 的迭代器。

参考文献:

Python详解可迭代对象(Iterable)、序列(Sequence)、迭代器(Iterator)、生成器(generator)_可迭代序列-CSDN博客

【Python入门第十三讲】可迭代对象(Iterable)、迭代器(Iterator)和生成器(Generator)-腾讯云开发者社区-腾讯云