1

Python中的迭代器 - 深蓝小佛

 2 years ago
source link: https://www.cnblogs.com/amoyshmily/p/16047536.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Python中的迭代器

迭代器:iterator
可迭代对象:iterable

在本文中,我们将学习迭代器是如何工作的,以及如何使用 __iter__()__next__() 方法构建自己的迭代器。

迭代器(Iterator)是可以迭代的对象,在 Python 中无处不在。它们在 for 循环、推导式、生成器等中得到了优雅的实现,但却隐藏在显而易见的地方。

Python 中的迭代器只是一个可以迭代的对象。一个每次仅仅返回一个元素的对象(有点像挤牙膏)。从技术上讲,Python 迭代器对象必须实现两个魔法方法:__iter__()__next__()方法,统称为迭代器协议(iterator protocol)。

如果我们可以从一个对象中得到一个迭代器,那么这个对象就被称为可迭代对象(iterable)。Python 中的大多数内置数据结构(容器)都是可迭代对象,比如 list列表、 tuple元组、 str字符串等等。iter ()函数(反过来调用__iter__()方法)从它们中返回一个迭代器。

遍历迭代器

我们使用 next() 函数手动遍历迭代器的所有元素。当我们到达结尾时,如果没有更多的数据要返回,它将引发 StopIteration异常。

python
# 定义一个列表 my_list = [4, 7, 0, 3] # 使用iter()返回一个迭代器对象 my_iter = iter(my_list) # 使用next()方法依次遍历 print(next(my_iter)) # 将打印 4 print(next(my_iter)) # 将打印 7 # next(obj) 和 obj.__next__()效果一样 print(my_iter.__next__()) # 将打印 0 print(my_iter.__next__()) # 将打印 3 next(my_iter) # 将会引起 StopIteration 异常

输出结果:

4
7
0
3
Traceback (most recent call last):
  File "<string>", line 24, in <module>
    next(my_iter)
StopIteration

一种更优雅的自动迭代方式是使用 for 循环。这样一来,我们可以遍历任何可以返回迭代器的对象,例如列表、字符串、文件等等。

python
# 定义一个列表 my_list = [4, 7, 0, 3] # 使用for循环遍历 for i in my_list: print(i)

迭代器中的for循环

正如我们在上面的例子中看到的,for循环能够自动遍历列表。实际上,for 循环可以遍历任何可迭代的对象。让我们仔细看看 for 循环是如何在 Python 中实现的。

python
# 从可迭代对象中创建一个迭代器对象 iter_obj = iter(iterable) # 开启无限循环 while True: try: # 遍历元素 element = next(iter_obj) # 对元素进行一些操作 pass except StopIteration: # 如果引起StopIteration则终止循环 break

由此可见,for 循环在内部通过对可迭代对象(iterable)调用 iter()方法,来创建出一个迭代器(iterator)对象 iter_obj

笑不活的是,这个 for循环实际上竟是一个无限 while循环......意不意外,惊不惊喜😂。

自定义迭代器

在 Python 中,从零开始构建迭代器很容易,我们只需要实现 __iter__()__next__() 方法。

  • __iter__()方法返回迭代器对象本身. 如果需要,可以执行一些初始化。

  • __next__()方法必须返回序列中的下一项。在到达结尾时,以及在随后的调用中,它必须引发StopIteration 异常。

下面,我们展示一个例子,它将给出每次迭代中2的下一次幂。其中幂指数从零开始到用户设置的数字。

python
class PowTwo: """2的迭代器指数类""" def __init__(self, max=0): self.max = max def __iter__(self): self.n = 0 return self def __next__(self): if self.n <= self.max: result = 2 ** self.n self.n += 1 return result else: raise StopIteration # 创建可迭代对象 numbers = PowTwo(3) # 获得一个迭代器 i = iter(numbers) # 获取下一个元素 print(next(i)) print(next(i)) print(next(i)) print(next(i))

执行后,输出结果:

1
2
4
8

我们还可以使用 for 循环迭代迭代器类。

python
for i in PowTwo(5): print(i)

执行后输出结果:

1
2
4
8
16
32

无限迭代器

迭代器对象中的项不必用尽。可以有无限迭代器(它永远不会结束)。在处理这样的迭代器时,我们必须小心。

下面是演示无限迭代器的一个简单示例。

内置函数 iter()还有一种用法是:

python
iter(callable, sentinel) -> iterator

也就是说,它在调用时可以接收两个参数 ,其中第一个参数必须是可调用对象(函数) ,第二个参数必须是哨兵。迭代器调用这个函数,直到返回的值等于哨兵。

我们知道python中的 int()函数默认总是返回0。因此,将它作为 iter(int,1)传递将返回一个调用 int()的迭代器,直到返回的值等于1。这种情况从来没有发生,我们得到了一个无限迭代器。

不仅如此,我们还可以构建自己的无限迭代器。

python
class InfIter: """一个用来返回所有的奇数的无限迭代器类""" def __iter__(self): self.num = 1 return self def __next__(self): num = self.num self.num += 2 return num

执行后输出结果:

1
3
5
...

其中...表示后续输出无穷无尽。

因此,在遍历这些类型的无限迭代器时,要注意包含终止条件。

其实,Python中还有一种更简单的创建迭代器的方法,就是使用生成器 generator

---END


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK