Python 中的迭代器


2021年8月23日, Learn eTutorial
1982

在本 Python 教程中,您将掌握 Python 中迭代器的优雅概念。您还将借助 __iter__() 和 __next__() 方法以及非常方便的示例,在 Python 中构建自己的迭代器。

在进入主题之前,让我们快速回顾一下什么是迭代以及什么是 Python 中的可迭代对象,我们已经在 Python 循环教程中讨论过。迭代是重复一组代码多次或直到满足特定条件的过程(例如:for 循环和 while 循环)。可迭代对象指的是可以重复或迭代的对象(例如:字符串、列表、元组等)。 

什么是迭代器

在 Python 编程语言中,迭代器是一个用于在迭代中遍历可迭代对象的对象。迭代器存储迭代的状态,因此它一次返回一个项目。在 Python 中,迭代器在循环、推导式、生成器等中被内在实现。

如何创建迭代器

从技术上讲,迭代器对象必须实现迭代器协议,该协议包含两个函数 __iter__() 和 __next__()。iter() 函数将可迭代对象转换为迭代器,而 next() 函数调用可迭代对象中的下一个项目。

Str_list = ['Yellow','Orange','Red']

it_obj = iter(Str_list)

print(it)

print(next(it_obj))
print(next(it_obj))
print(next(it_obj))
print(next(it_obj)) 

输出:

Yellow
Orange
Red
Traceback (most recent call last):
  File "iter_ex.py", line 17, in 
    print(next(it))
StopIteration

在上面的代码片段中,您可以看到迭代器的创建及其实施。

  • 首先,我们定义了一个名为 Str_list 的列表,它包含三个字符串元素 ‘Yellow’、‘ Orange’ 和 ‘Red’。
  • 其次,我们借助 iter() 函数创建了迭代器 it_obj,该函数在这里将列表转换为迭代器。
  • 第三,我们使用函数 print(it),期望结果是迭代器的值,即列表中的第一个元素(yellow)。但实际上,它打印的是迭代器对象。
  • 因此,为了获取迭代器的值,Python 有一个名为 next() 的内置函数。print(next(it_obj)) 打印列表中的第一个元素,即 Yellow。 
  • 下一个 print(next(it_obj)) 打印列表中的下一个元素,即 Orange。
  • 再下一个 print(next(it_obj)) 打印列表中的下一个元素,即 Red。
  • 最后一次 print(next(it_obj)) 最终引发了一个 StopIteration 异常,因为列表已到达末尾,没有更多的值可以返回。

由此我们了解到,通过使用 next() 函数,我们可以手动地遍历可迭代对象中的项目。

为了使其更方便,我们有另一种优雅的迭代方式,那就是 for 循环迭代。同样的例子可以用 for 循环自动实现,如下所示。

Str_list = ['Yellow','Orange','Red']

for i in Str_list:
 print(i) 

输出

Yellow
Orange
Red

for 循环的内部工作原理

在解释 FOR 循环在 Python 内部如何工作之前,请先查看下面的代码片段并进行分析。

Str_list = ['Yellow','Orange','Red']

it_ob = iter(Str_list)

while True:
 try:
     i = next(it_ob)
     print(i)
 except StopIteration:
     break 

输出

Yellow
Orange
Red

这就是 for 循环的内部实现方式。for 循环会内在地创建一个迭代器对象,然后在 while 循环中使用 next() 函数来迭代像列表这样的可迭代对象。当可迭代对象到达末尾并尝试再次迭代时,程序将停止并引发异常。

如何在 python 中创建自己的迭代器

我们已经看到了迭代器在内置结构上的工作方式。现在让我们尝试创建自己的迭代器,即用户定义的版本。我们需要记住的一件事是,在创建迭代器时,我们必须实现迭代器协议。具体来说,我们必须使用 iter() 和 next()。
因此,让我们创建一个迭代器来产生偶数平方的结果。输出将采用以下形式。

class Pow:
    def __iter__(self):
    self.a = 0
    return self

  def __next__(self):
     x = self.a**2
     self.a =  self.a + 2
     return x
    
even = Pow()
it_ob = iter(even)

print(next(it_ob))
print(next(it_ob))
print(next(it_ob))
print(next(it_ob))
print(next(it_ob)) 

输出

0
4
16
36
64

什么是无限迭代器

当您观察上面的代码时,可以注意到代码中没有包含终止步骤,这意味着迭代器将无限迭代。为了清楚地理解这一点,让我们使用‘for 循环’来迭代我们的类 Pow

for i in Pow():
 print(i) 

输出

0
4
16
36
64
100
.
.
.

那些无限迭代的迭代器被称为无限迭代器。在编码时,这不是一种好的做法,因此我们必须小心地在程序中包含终止语句。

如何停止迭代

所以现在我们意识到我们需要停止迭代以防止永不结束的迭代。为了实现这一点,我们在 next() 函数内部使用 StopIteration 语句,如下面的代码片段所示。

class Pow:
  def __init__(self, max =0):
     self.max = max

  def __iter__(self):
    self.a = 0
    return self

  def __next__(self):
    if self.a<=self.max:
     x = self.a**2
     self.a =  self.a + 2
     return x
    else:
     raise StopIteration

even = Pow(5)
it_ob = iter(even)

print(next(it_ob))
print(next(it_ob))
print(next(it_ob))
print(next(it_ob))
print(next(it_ob)) 

输出

0
4
16
Traceback (most recent call last):
  File "iter_ex.py", line 47, in 
    print(next(it_ob))
  File "iter_ex.py", line 39, in __next__
    raise StopIteration
StopIteration

使用 for 循环实现的相同代码如下


for i in Pow(8):
 print(i) 

输出

0
4
16
36
64

在程序中利用迭代器的主要好处是它们可以节省资源,这意味着除了单个内存外,不需要特殊的内存来获取所有元素。理论上,它表示可以在有限的内存中存储无限的元素。