Python iter() 语法
iter() 是 Python 的一个内置函数,它用于获取一个可迭代对象对应的迭代器。
语法:
iter(iterable, sentinel)说明:
iter() 函数接收以下 2 个参数。
iterable(必选):它是一个可迭代对象。Python 常见的内置可迭代对象有:列表、元组、字符串、字典等。sentinel(可选):用于设置结束值(即哨兵值)。如果 iter() 设置了第 2 个参数,那么当使用循环遍历迭代器时,如果当前循环值与 sentinel 值相同时,循环就会结束。
如果一个对象是可迭代对象,那么它就肯定实现了 __iter__() 方法,该方法会返回一个迭代器。迭代器的内部实现了 __next__() 方法,该方法返回迭代的下一个值。当迭代器没有值可以迭代时,__next__() 方法会抛出 StopIteration 异常。
注意:
- iter() 返回的迭代器是惰性求值的,它不会一次性生成所有元素并存储在内存中。
- 一旦迭代器被遍历完,它就耗尽了,无法再次使用,需要重新调用 iter() 来获取一个新的迭代器。
Python iter() 摘要
| 使用频率 | 高 |
|---|---|
| 官方文档 | 查看 |
| 相关函数 | next()、aiter()、anext() |
Python iter() 示例
接下来,我们通过几个简单的例子来讲解一下 Python iter() 函数是如何使用的。
示例 1:iter() 的参数是可迭代对象
# 列表
nums = [1, 2, 3, 4, 5]
print(iter(nums))
# 元组
colors = ('red', 'green', 'blue')
print(iter(colors))
# 字符串
s = 'Python'
print(iter(s))
# 字典
users = {'Jack': 1001, 'Lucy': 1002, 'Tony': 1003}
print(iter(users))
# range 对象
items = range(5)
print(iter(items))运行结果如下。
<list_iterator object at 0x000001D16722C9A0>
<tuple_iterator object at 0x000001D16722C9B0>
<str_iterator object at 0x000001D16722C9C0>
<dict_keyiterator object at 0x000001D167222D40>
<range_iterator object at 0x000001D1670A3CB0>分析:
从上面可以知道,不同可迭代对象对应的迭代器是不一样的。常见的可迭代对象对应的迭代器如下表所示。
| 可迭代对象 | 对应的迭代器 |
|---|---|
| list | list_iterator |
| tuple | tuple_iterator |
| str | str_iterator |
| dict | dict_keyiterator |
| range | range_iterator |
示例 2:iter() 的参数是非可迭代对象
year = 2024
print(iter(2024))运行结果如下。
(报错) TypeError: 'int' object is not iterable分析:
并非所有对象都是可迭代的,只有可迭代对象才能使用 iter() 函数(或 __iter__() 方法)。如果对一个不可迭代的对象使用 iter() 函数,则 Python 会直接报错(抛出 TypeError 异常)。
到这里小伙伴肯定会问:“使用 iter() 函数来获取一个可迭代对象的迭代器,到底有什么用呢?” 其实只有获取了迭代器,才可以使用 next() 函数来不断获取下一次的迭代结果。
示例 3:next() 获取迭代结果
colors = ['红', '绿', '蓝']
result = iter(colors)
print(next(result))
print(next(result))
print(next(result))运行结果如下。
红
绿
蓝示例 4:iter() 带第 2 个参数
class Double:
def __init__(self):
self.start = 1
def __iter__(self):
return self
def __next__(self):
self.start *= 2
return self.start
__call__ = __next__
result = iter(Double(), 32)
for x in result:
print(x)运行结果如下。
2
4
8
16分析:
在上面例子中,我们使用 iter() 函数的第 2 个参数(即 sentinel 参数)来停止迭代。当迭代到 32 时,就会停止迭代。
iter() 函数和 __iter__() 方法
如果想要获取一个可迭代对象对应的迭代器,除了 iter() 函数之外,我们还可以使用 __iter__() 方法。两者功能是等价的,只是语法不一样而已。
示例 5:iter() 和 __iter__()
colors = ['红', '绿', '蓝']
print(iter(colors))
print(colors.__iter__())运行结果如下。
<list_iterator object at 0x000002904CAB9BA0>
<list_iterator object at 0x000002904CAB9BA0>常见问题
1. 为什么有时候我们需要手动获取迭代器?
在 Python 中,当我们使用 for 循环遍历一个可迭代对象(比如列表、字符串等)时,Python 背后会自动调用 iter() 来获取迭代器,然后不断调用 next() 来获取下一个元素,直到出现 StopIteration 异常。
那么,为什么我们还需要手动调用 iter() 来获取迭代器,或者手动调用 next() 呢?主要有以下几个原因:
- 精细控制迭代流程:有时候我们可能不希望一次性遍历完所有元素。手动获取迭代器并使用 next() 可以让我们在特定条件下停止、暂停或按需获取下一个元素,实现更复杂的逻辑。
- 处理无限序列:如果有一个会无限生成数据的可迭代对象(比如一个从传感器不断读取数据的对象),我们不能用 for 循环去遍历它,因为它永远不会停止。这时,我们可以手动获取迭代器,然后只在需要的时候调用 next()。
- 理解迭代机制:显式地使用 iter() 和 next() 有助于我们深入理解 Python 迭代协议的底层工作原理,这对于编写高效且符合 Python 习惯的代码非常有帮助。
- 构建复杂的数据处理管道:在函数式编程或构建数据流时,我们可能需要将迭代器作为参数传递给其他函数,或者在不同的阶段对同一个迭代器进行操作,手动获取迭代器会让你有更大的灵活性。
2. 如何自定义迭代器?
如果希望自定义类对象能够像 Python 内置的列表或字符串一样,支持 for 循环遍历,或者能够被 iter() 函数处理,我们就需要使得该类成为一个可迭代对象,并且能够返回一个迭代器。
想要实现这一点,我们需要在类中自行实现 __iter__() 和 __next__() 这两个 “魔法方法”:
__iter__():这个方法必须返回一个迭代器对象。通常,如果类本身就实现了 __next__() 方法,那么 __iter__() 可以简单地返回 self。如果迭代逻辑比较复杂,你也可以返回一个单独的迭代器类实例,或者一个生成器(使用 yield 关键字)。__next__():这个方法负责返回序列中的下一个元素。当没有更多元素可以返回时,它必须抛出 StopIteration 异常,以此来通知迭代结束。
