可迭代对象和迭代器

ZaynPei Lv6

可迭代对象 (Iterable) 是指那些能够逐一返回其内部成员的对象(返回迭代器)。换句话说,任何你可以用 for 循环进行遍历的对象,都是可迭代对象。

常见的可迭代对象

常见的可迭代对象包括:

  • 序列 (Sequence):如列表 (list)、元组 (tuple)、字符串 (str)。
  • 集合 (Set):如 set、frozenset。
  • 映射 (Mapping):如字典 (dict)。
  • 文件对象。
  • 通过 yield 关键字创建的生成器 (Generator)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 列表是可迭代的
my_list = [1, 2, 3]
for item in my_list:
print(item)

# 字符串是可迭代的
my_string = "hello"
for char in my_string:
print(char)

# 字典是可迭代的(默认遍历键)
my_dict = {'a': 1, 'b': 2}
for key in my_dict:
print(key)

# 如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()。
for value in my_dict.values():
print(value)
for k, v in my_dict.items():
print(k, v)

如何判断一个对象是可迭代对象

你可以使用 collections.abc.Iterableisinstance来检查一个对象是否是可迭代的:

1
2
3
4
from collections.abc import Iterable
print(isinstance([1, 2, 3], Iterable)) # True,列表是可迭代的
print(isinstance("hello", Iterable)) # True,字符串是可迭代的
print(isinstance(42, Iterable)) # False,整数不是可迭代的

迭代器协议 (Iterator Protocol)

一个对象之所以“可迭代”,是因为它遵守了 Python 的迭代器协议。这个协议规定了对象如何支持迭代。我们可以从两个角度来理解这个协议:

  • 可迭代对象 (Iterable)
    • 定义:一个对象如果实现了 iter() 方法,那么它就是可迭代对象。
    • 作用:iter() 方法的职责是返回一个迭代器 (Iterator) 对象。
    • List、Tuple、String、Dict、Set 等内置类型都实现了 iter() 方法,因此它们都是可迭代对象。
  • 迭代器 (Iterator)
    • 定义:一个对象如果同时实现了 iter() 和 next() 方法,那么它就是迭代器。
    • iter() 的作用:对于迭代器本身,其 iter() 方法通常只是返回它自己 (self)。
    • next() 的作用:这是迭代器的核心。每次调用该方法时,它会返回序列中的下一个元素。当所有元素都返回完毕后,再次调用 next() 会抛出 StopIteration 异常,以告知外部调用者迭代已经结束。
    • Generator 对象就是一种特殊的迭代器,它们是通过生成器函数创建的。

需要注意的是, List、Tuple、String、Dict、Set等内置类型不是迭代器,因为它们没有实现 next() 方法, 也就意味着他们不能通过next()逐个访问下一元素(因为他们本身就是有限的集合, 没有必要逐个生成逐个next()访问).

可以使用isinstance()判断一个对象是否是Iterator对象:

1
2
3
4
5
6
7
8
9
>>> from collections.abc import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

for 循环的幕后工作原理

当我们使用 for 循环时,Python 解释器在背后实际上执行了以下步骤:

  1. 获取迭代器:调用可迭代对象的 iter() 方法来获取一个迭代器。

  2. 循环取值:在一个循环中,不断地调用迭代器的 next() 方法来获取下一个元素。

  3. 处理异常:当 next() 方法抛出 StopIteration 异常时,for 循环会捕获这个异常并优雅地结束循环。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    my_list = [10, 20, 30]

    # 1. 获取迭代器
    # 这相当于调用了 my_list.__iter__()
    my_iterator = iter(my_list)

    # 2. 循环取值和处理异常
    while True:
    try:
    # 相当于调用了 my_iterator.__next__()
    item = next(my_iterator)
    print(item)
    except StopIteration:
    # 3. 迭代结束,跳出循环
    break