迭代器和生成器
本文最后更新于:2024年5月18日 下午
应用场景:处理大量数据或需要节省内存
迭代器
迭代器是遵循迭代器协议的对象,即它们实现了__iter__()
和__next__()
两个方法。__iter__()
返回迭代器对象本身,__next__()
返回序列的下一个元素。如果没有更多元素可返回,则抛出StopIteration
异常。
iter( )
方法:
在Python中,iter()
函数用于获取一个迭代器。它通常与集合数据类型(如列表、元组、字典、集合等)一起使用,以获取这些数据类型的迭代器对象。
以下是iter()
函数的基本用法:
无参数调用:
iter()
可以不带参数调用,这时它会返回一个空的迭代器。1
iter()
调用具有
__iter__()
方法的对象:如果对象实现了__iter__()
方法,iter()
函数将调用这个方法来获取迭代器。1
my_iter = iter(my_object)
调用具有
__getitem__()
方法的对象:如果对象实现了__getitem__()
方法,iter()
函数会创建一个迭代器,尝试按顺序获取对象的元素。1
my_iter = iter(my_object)
调用带有两个参数:
iter()
也可以接受两个参数,其中第一个参数是函数,第二个参数是哨符(哨符(sentinel)是一个特殊的值,用于在迭代过程中指示何时停止。通常,哨符与iter()
函数的第二个参数一起使用,以创建一个迭代器,该迭代器重复调用函数直到它返回哨符值。这种用法允许创建一个基于某些条件停止的迭代器,而不是基于固定数量的元素或项。哨符通常用于文件处理,其中哨符可以是一个特殊的行或字符,指示文件的结束)。这种用法用于创建一个迭代器,该迭代器重复调用函数直到它返回哨符值。1
my_iter = iter(function, sentinel)
示例:
展示如何使用iter()
函数获取列表的迭代器
1 |
|
使用iter()
函数获取列表[1, 2, 3, 4, 5]
的迭代器后,我们使用next()
函数获取迭代器的下一个元素,得到的结果是1
。
也可以使用next()
函数连续调用迭代器来遍历列表中的所有元素。当没有更多元素可返回时,next()
函数会抛出StopIteration
异常。
next()
方法:
next()
函数用于获取迭代器的下一个元素。当你有一个迭代器对象时,你可以使用next()
函数来逐个访问其元素,直到没有更多元素可访问,此时next()
会抛出StopIteration
异常。
迭代器是一个实现了__next__()
方法的对象,该方法返回序列的下一个元素。next()
函数简单地调用迭代器的__next__()
方法。
迭代器用于遍历集合,如列表、元组、字典和集合等,而不需要在内存中存储整个集合。这意味着迭代器在处理大数据集时非常高效。
迭代器示例
用于创建一个可以生成斐波那契数列的迭代器:
1 |
|
在这个迭代器中:
__init__
方法初始化迭代器,设置要生成的斐波那契数的数量(n
),并初始化两个变量a
和b
,分别代表数列中的前两个数。__iter__
方法返回迭代器对象本身。__next__
方法计算下一个斐波那契数,并更新a
和b
的值。如果生成的斐波那契数的数量达到了指定的数量(n
),则抛出StopIteration
异常。
生成器
在Python中,生成器是一种特殊类型的迭代器,它使用yield
语句来生产一系列的值,用于迭代。生成器的优势在于它提供了惰性求值(lazy evaluation),这意味着它只在需要时生成值,而不是一次性生成所有值。这样做可以节省内存并提高效率。
生成器函数的定义与普通函数类似,但有以下特点:
- 包含
yield
关键字。 - 当函数被调用时,它返回一个生成器对象,但不会立即执行函数体。
- 当生成器对象的
__next__()
方法被调用时,函数体开始执行,直到遇到yield
语句,此时它返回yield
后的值并暂停执行。
下次调用__next__()
时,函数从上次暂停的地方继续执行,直到再次遇到yield
或函数结束。
yield
关键字
yield VS
return
return
作为结尾的普通函数直接返回所有结果,程序终止不再运行,并销毁局部变量;yield
会产生一个断点,暂停函数,挂起函数,保存当前状态。并且在yield
处返回某个值,返回之后程序就不再往下运行了。
示例:
1 |
|
结果:
程序开始执行以后,因为fun_yield中有yield关键字,所以函数并不会真的执行,而是先得到一个实例化的生成器对象,结果1可以看出不会真的运行。
直到调用next(),fun_yield正式开始执行,先执行函数中的print(“starting fun yield”),然后进入while循环,结果2可以看出
程序遇到yield关键字,然后把yield理解为return,return了一个4之后,程序停止,并没有执行后面的print(“判断yield之后是否继续执行”,res)操作,此时next(g)语句执行完成,所以输出的前两行,接下来准备运行第二次调用,结果3可以看出
执行下面的print(“生成器的返回值”,next(g)),这个时候和上面那个差不多,不过不同的是,这个时候是从上一次yield停止的断点开始执行,也就是要执行print(“判断yield之后是否继续执行”,res)操作,这时候要注意,这个时候赋值操作的右边是没有值的(因为刚才那个是return出去了,并没有给赋值操作的左边传参数,也就相当于说res里面是没有内容的),所以这个时候res赋值是None,所以接着下面的输出就是None,结果4可以看出
之后的程序会继续在while里执行,又一次碰到yield,这个时候同样return出4,结果5可以看出
生成器示例
1 |
|
使用生成器函数fibonacci_generator
,我们成功地生成了前10个斐波那契数:0, 1, 1, 2, 3, 5, 8, 13, 21, 34。
这个示例展示了生成器如何简化生成序列的过程,同时节省内存。由于生成器在迭代时只生成当前需要的值,因此它们在处理大数据集或无限序列时特别有用。