Python生成器类

本教程将讨论使用yield 语句和next() 函数在 Python 中创建一个生成器类。

要理解生成器,我们首先需要理解下面讨论的迭代器。

Python 迭代器

迭代器是用来逐一访问容器中元素的对象。我们可以使用for 语句在容器对象上循环,以逐个获得数值。

下面是一个例子的代码。

for element in [5, 6, 7]:
    print(element)

在上面的Python代码中,我们正在对元素列表进行循环,并逐一打印它们。让我们了解一下幕后发生了什么。

for 语句在给定的容器对象上调用iter() 函数,该函数包含一个方法__next__() ,它将逐一访问给定容器对象的每个元素。

__next__() 函数引发一个异常StopIteration 时,循环将终止,并且只有当给定的容器对象内没有更多的元素时,才会引发异常。

Python 还提供了内置函数next() ,可以用来调用__next__() 函数。要在一个容器对象上使用next() 函数,我们必须使用iter() 函数创建一个对象。

例如,让我们使用一个数字的列表,并调用next() 函数来逐一获得列表中的每个元素。请看下面的代码和输出。

My_list = [5,6,7]
iter_object = iter(My_list)
print(next(iter_object))
print(next(iter_object))
print(next(iter_object))
print(next(iter_object))

输出:

5
6
7
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-10-aa02bcda701b> in <module>
      4 print(next(iter_object))
      5 print(next(iter_object))
----> 6 print(next(iter_object))
StopIteration:

在上面的代码中,我们调用了next() 函数四次,分别返回给定列表对象中的三个元素。当我们第四次调用它时,它返回了StopIteration 异常,因为列表对象中没有更多的元素了。

我们也可以用一个循环来调用next() 函数。

使用try-except 语句,我们可以避免错误并使用异常名称来终止循环。例如,让我们用一个循环和一个try-except 语句重复上面的代码。

请看下面的代码和输出。

My_list = [5,6,7]
iter_object = iter(My_list)
for i in range(len(My_list)):
    try:
        print(next(iter_object))
    except StopIteration:
        break

输出:

5
6
7

在上面的代码中,我们使用了异常的名称,StopIteration ,来打破循环。上面的迭代器以正向顺序逐一返回值,但我们也可以定义自己的迭代器,它将根据我们的要求返回值。

我们必须定义三个函数,__init__(),__iter__(), 和__next__(), 来给一个类添加迭代器行为。例如,让我们创建一个返回斐波那契数的类。

请看下面的代码

class Fibexample:
    def __init__(self):
        self.x, self.y = 0, 1
    def __iter__(self):
        return self
    def __next__(self):
        r_value = self.x
        self.x, self.y = self.y, self.x+self.y
        return r_value
fib = Fibexample()
for i in range(7):
    print(next(fib))

输出:

0
1
1
2
3
5
8

只要调用next() 函数,上述类就会从斐波那契数列中返回一个数字。在上面的代码中,我们调用了next() 函数七次,返回斐波那契数列的前七个数字。

Python 生成器类

在 Python 中,生成器被用来创建迭代器。它们与普通函数相同;唯一的区别是使用yield 语句而不是return 语句。

yield() 语句将调用next() 函数,该函数返回一个迭代器对象。例如,让我们创建一个生成器函数,返回与上述代码相同的斐波那契数列。

请看下面的代码和输出。

def fibexample(data_input):
    x ,y = 0,1
    for index in range(data_input):
        z = x
        x, y = y, x+y
        yield z
obj = fibexample(7)
for i in obj:
    print(i)

输出:

0
1
1
2
3
5
8

在上面的代码中,fibexample() 函数将在一个迭代器对象中返回斐波那契数列的所需数字。我们可以使用一个循环来迭代该对象,以获得迭代器对象中存在的每个值。

生成器会记住数据值和最后一次执行next() 函数的情况,当再次调用next() 函数时,它将恢复原来的状态。

上述函数的结果与我们在迭代器例子中得到的结果相同,但与我们在迭代器例子中使用的代码相比,上述代码相对较短。使用生成器的好处是,__iter__()__next__() 函数将被自动创建,而且生成器还将处理StopIteration 异常。

所以,使用生成器编写迭代器很容易,因为使用生成器创建迭代器就像使用yield 语句编写一个简单的函数。