python中创建和使用迭代器

450 阅读3分钟

迭代

在计算机中,迭代一般是指反复重复循环,直到到达某个条件为止。在python中可以理解为,能用于for循环的,是可以迭代的。

迭代 iterative

可迭代对象 iterable

迭代器 iterator

迭代器和可迭代对象

一般来说,我们认为能够用于for循环的,就是可迭代对象,能使用next()调用下一个对象的,就是迭代器。这里我们可以发现,之前我们提到的生成器,也是迭代器。

当然,在python中,我们也可以通过代码来判断一个对象是否是可迭代对象,或者是迭代器。

from collections.abc import Iterable, Iterator
 
 
def check_iterable(x, name):
	if isinstance(x, Iterable):
		print(name, "是可迭代对象")
	else:
		print(name, "不是可迭代对象")
 
 
def check_iterator(x, name):
	if isinstance(x, Iterator):
		print(name, "是迭代器")
	else:
		print(name, "不是迭代器")
 
 
if __name__ == "__main__":
	t1 = [i for i in range(5)]
	check_iterable(t1, "列表")
	check_iterator(t1, "列表")
 
	t2 = (i for i in range(5))
	check_iterable(t2, "生成器")
	check_iterator(t2, "生成器")
 
	t3 = {i: i + 1 for i in range(5)}
	check_iterable(t3, "字典")
	check_iterator(t3, "字典")

我们执行这个程序,得到了这样的结果

列表 是可迭代对象

列表 不是迭代器

生成器 是可迭代对象

生成器 是迭代器

字典 是可迭代对象

字典 不是迭代器

转换为迭代器

同样是可以通过for循环遍历,为什么生成器就是迭代器,但是列表和字典就不是迭代器呢?

原因是,迭代器从一开始的时候,并没有得到全部的结果,而是通过调用next()得到了下一个结果。虽然迭代器可以被遍历,列表同样也可以被遍历,但是,它们不是一回事。比如,之前我们在生成器中提到的,迭代器可以表示一个无穷无尽的数列,但是列表显然不可以,所以,列表也不会是迭代器。

但是,我们可以通过iter(),创建迭代器对象,比如说,我们通过iter()将列表转换为迭代器。

from collections.abc import Iterator
 
 
def check_iterator(x, name):
	if isinstance(x, Iterator):
		print(name, "是迭代器")
	else:
		print(name, "不是迭代器")
 
 
if __name__ == "__main__":
	t1 = [i for i in range(5)]
	check_iterator(t1, "列表转换前")
 
	t2 = iter(t1)
	check_iterator(t2, "列表转换后")
 
	print(t2)
 
	print(next(t2))

从这里,我们可以看出,转换前的列表不是迭代器,使用iter转换后是迭代器,同时也可以使用next()函数。

创建迭代器

如果你要创建一个类作为迭代器,那么要实现两个方法

iter() 该方法返回一个迭代器,此处可以返回自己

next() 该方法返回下一个迭代器对象

其中,如果你要为迭代器设置终止标志的话,需要抛出StopIteration异常,通过for循环遍历该迭代器时,会在StopIteration处结束

from collections.abc import Iterator
 
 
def check_iterator(x, name):
	if isinstance(x, Iterator):
		print(name, "是迭代器")
	else:
		print(name, "不是迭代器")
 
 
class XiaIterator:
	"""
	作者:瞎老弟
	时间:2021-10-29
	联系方式:qq1413274264
	说明:一个自建的迭代器类
	"""
 
	def __init__(self, num):
		self.num = num
 
	def __iter__(self):
		self.s = 0
		return self
 
	def __next__(self):
		if self.s < self.num:
			self.s += 1
			return self.s
		else:
			# 通过for循环使用,会在StopIteration处停止
			# 如果是通过next()调用,会在最后抛出StopIteration异常
			raise StopIteration
 
 
if __name__ == "__main__":
	for i in XiaIterator(20):
		print(i)
 
	check_iterator(XiaIterator(20), "瞎老弟自建的迭代器类")

补充说明

你可能在其他地方,也能看到老版本的写法,如下所示

from collections.abc import Iterator 新版本是这样写的

from collections import Iterator 老版本是这样写的

这两种方式没什么区别,是一样的,只不过后面的那种在python的新版本中不再允许被使用了而已,如果你使用的是3.8以及以前的python版本,使用老版本的写法也是一样的。