本篇文章将讨论使用 yield
语句和 next()
函数在 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 中,生成器用于创建迭代器。 它们与常规功能相同; 唯一的区别是使用 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 语句编写一个简单的函数。