Python自定义迭代器
在这篇文章中,我们将学习什么是迭代器,以及如何在名为__iter__
和__next__
的类方法的帮助下创建一个自定义迭代器。我们还将学习如何在Python的生成器的帮助下创建一个自定义迭代器。
在Python中借助于类方法__iter__
和__next__
创建一个自定义迭代器
现在当你说到迭代器时,顾名思义,它将被用来进行迭代。
如果你来自C、C++和Java等语言,我们有一个共同的概念:++
。当我们谈论迭代的时候,还有一个概念是已知的:for
循环。
比方说,我们有一个包含5个元素的列表。使用一个循环,我们可以从第一个元素迭代到最后一个元素。
这样,我们就有了一个带有一些数值的列表,如果我们想用索引号逐一打印它们。
如果我们传递我们的索引0,它将给我们提供第一个元素,2。如果我们使用索引值1,它将为我们提供第二个元素,5。
Numbers=[2,5,10,3,1]
print(Numbers[0])
print(Numbers[1])
输出:
2
5
另一种打印数值的方法是使用循环。我们可以对一个列表进行迭代并打印所有的值。
Numbers=[2,5,10,3,1]
for i in Numbers:
print(i)
输出:
2
5
10
3
1
现在我们还有一种方法:通过使用迭代器。一般来说,迭代器在for
循环的背后工作。
我们将使用iter()
函数来理解一个迭代器,它将把我们的列表转换成一个迭代器。这个迭代器不会给我们所有的值,它每次只给一个值。
Numbers=[2,5,10,3,1]
ITR=iter(Numbers)
print(ITR)
我们可以看到它正在打印一个迭代器的对象。
<list_iterator object at 0x000001FEDCFF7310>
但是,如果你想要这个值,你可以设置ITR.__next__()
,这是一个内建的方法。它将在特定对象上第一次调用__next__()
方法时给我们第一个值;这与我们使用索引值的方式相同,但好处是我们不必使用索引值。
umbers=[2,5,10,3,1]
ITR=iter(Numbers)
print(ITR.__next__())
输出:
2
当我们在下一个执行行中执行ITR.__next__()
,它将给出下一个值。在这个场景背后,迭代器将有多个值,所以当我们调用__next__()
方法时,它将拾取一个值。
再说,当我们调用__next__()
,它知道i
的最后一个值,这意味着它将保留最后一个值的状态。这就是迭代器的魅力;当我们再次调用该函数时,它将保留旧值。
我们可以使用一个类来创建我们的迭代器。使用该类,我们可以单独打印前10个值。
为了达到这个目的,我们将有一个名为TopValues
的类,在这个类中,我们将指定一个计数器。
为此,我们将使用__init__
函数,在这里我们将定义我们的计数器变量self.N=1
;显然,计数器将从1开始初始化。我们需要两个重要方法来创建我们的自定义迭代器。
第一个是iter()
方法,它将给我们迭代器的对象,然后next()
方法将提供下一个值或对象。在__next__
方法中,我们没有返回self.N
,而是使用了一个叫做VALUE
的变量,我们将把self.N
,在下一行中,我们把self.N
递增为1。
这样,它将在每一个下一次迭代中被递增,然后返回VALUE
,而不是self.N
,因为self.N
在下一次迭代中被递增。
class TopValues:
def __init__(self):
self.N=1
def __iter__(self):
return self
def __next__(self):
VALUE=self.N
self.N+=1
return VALUE
我们的迭代器现在已经准备好了,我们可以创建一个TopValues
类的对象。让我们使用一个循环,因为通常当你有一个迭代器时,我们可以使用循环。
T_Val=TopValues()
for i in T_Val:
print(i)
现在当我们执行这段代码时,我们会得到成千上万的值。
1
2
3
4
5
....
1000
让我们试着理解发生了什么。为了检查迭代器是否工作,我们将使用__next__()
。
print(T_Val.__next__())
这一行将打印第一个迭代值,1
,但循环出了什么问题?问题在于,这个循环将从起点走到终点;我们假设终点是10,但我们没有提到应该在哪里停止。
当我们使用循环时,它将调用next()
函数,这就是它的工作方式。for
循环内部使用next()
函数;因此,它将反复调用这个next()
函数。
我们必须在__next__
方法里面应用一个条件。
我们还必须设置else
块;在这个块里面,我们将引发一个异常。否则,在打印了10个值之后,循环将打印None
。
class TopValues:
def __init__(self):
self.N=1
def __iter__(self):
return self
def __next__(self):
if self.N<=10:
VALUE=self.N
self.N+=1
return VALUE
else:
raise StopIteration
T_Val=TopValues()
for i in T_Val:
print(i)
输出:
1
2
3
4
5
6
7
8
9
10
在Python生成器的帮助下创建一个自定义迭代器
现在让我们试着创建一个生成器函数来做同样的事情。生成器要简单得多,因为它为我们处理了__iter__()
和__next__()
方法。
如果我们试着写一个名为Our_Gen()
的生成器函数,我们将在这个函数中传递参数。
由于我们是在列表上循环,所以我们是一次产生一个项目。而且,当没有更多的项目可以循环时,它会自动处理,并引发一个异常来停止迭代。
现在我们在Our_Gen()
函数上循环,所以它应该一次打印出一个项目。如果我们运行它,我们可以看到我们一次得到一个。
def Our_Gen(n_list):
for i in n_list:
yield i
Func=Our_Gen([2,5,10,3,1])
for i in Func:
print(i)
输出:
2
5
10
3
1
为了确保我们的next()
函数仍然在工作。执行后,我们得到五个元素我们得到一个停止迭代的异常。
def Our_Gen(n_list):
for i in n_list:
yield i
Func=Our_Gen([2,5,10,3,1])
print(Func.__next__())
print(Func.__next__())
print(Func.__next__())
print(Func.__next__())
print(Func.__next__())
print(Func.__next__())
输出:
2
5
10
3
1
Traceback (most recent call last):
File "c:UsersDellDesktopdemodemo.py", line 56, in <module>
print(Func.__next__())
StopIteration
生成器比类更容易编写。但是根据你的用例,你可能需要知道如何在一个类中做__iter__()
方法和__next__()
方法。
你可以从这里阅读更多关于创建一个自定义迭代器的信息。