当我们需要处理一个大量的数据集合时,一次性将其全部读入内存并处理可能会导致内存溢出。此时,我们可以采用迭代器Iterator
和生成器Generator
的方法,逐个地处理数据,从而避免内存溢出的问题。
迭代器是一个可以逐个访问元素的对象,它实现了python
的迭代协议,即实现了__iter__()
和__next__()
方法。通过调用__next__()
方法,我们可以逐个访问迭代器中的元素,直到所有元素都被访问完毕,此时再次调用__next__()
方法会引发StopIteration
异常。
生成器是一种特殊的迭代器,它的实现方式更为简洁,即通过yield
语句来实现。生成器函数使用yield
语句返回值,当生成器函数被调用时,它会返回一个生成器对象,通过调用__next__()
方法来逐个访问生成器中的元素,直到所有元素都被访问完毕,此时再次调用__next__()
方法会引发StopIteration
异常。
使用迭代器和生成器可以有效地避免内存溢出问题,并且代码实现也更为简洁、高效。在python中,很多内置函数和语言特性都支持迭代器和生成器的使用,例如for循环、列表推导式、生成器表达式等。
3.1 使用迭代器
迭代器可以通过内置函数iter()
进行创建,同时可以使用next()
函数获取下一个元素,如果迭代器没有更多的元素,则抛出StopIteration
异常在for
循环中,迭代器可以自动实现例如for x in my_iterable:
语句就可以遍历my_iterable
对象的所有元素。此外python
中还有一种特殊的迭代器,称为生成器(generator
),生成器是一种用简单的方法实现迭代器的方式,使用了yield
语句,生成器在执行过程中可以暂停并继续执行,而函数则是一旦开始执行就会一直执行到返回。
创建基本迭代器: 首先声明列表,然后使用__iter__
将其转为迭代器,并通过__next__
遍历迭代对象.
>>> list = [1,2,3,4,5,6,7,8,9,10]
>>>
>>> item = list.__iter__()
>>> type(item)
<class 'list_iterator'>
>>>
>>> item.__next__()
1
>>> next(item)
2
迭代器遍历日志文件: 使用迭代器可以实现对文本文件或日志的遍历,该方式可以遍历大型文件而不会出现卡死现象.
# 手动访问迭代器中的元素,可以使用next()函数
>>> with open("passwd.log") as fp:
... try:
... while True:
... print(next(fp))
... except StopIteration:
... print("none")
# 通过指定返回结束值来判断迭代结束
>>> with open("passwd.log") as fp:
... while True:
... line = next(fp,None)
... if line is None:
... break
... print(line)
循环遍历迭代元素: 由于迭代器遍历结束会报错,所以要使用try语句抛出一个StopIteration
结束异常.
>>> listvar = ["吕洞宾", "张果老", "蓝采和", "特乖离", "和香菇", "汉钟离", "王文"]
>>> item = listvar.__iter__()
>>>
>>> while True:
... try:
... temp = next(item)
... print(temp)
... except StopIteration:
... break
迭代器与数组之间互转: 通过使用enumerate方法,并将列表转为迭代器对象,然后将对象转为制定格式.
>>> listvar = ["吕洞宾", "张果老", "蓝采和", "特乖离", "和香菇", "汉钟离", "王文"]
>>>
>>> iter = enumerate(listvar) # 转换为迭代器
>>> dict = tuple(iter) # 转换为元组
>>> dict
((0, '吕洞宾'), (1, '张果老'), (2, '蓝采和'), (3, '特乖离'), (4, '和香菇'), (5, '汉钟离'), (6, '王文'))
>>>
>>> dict = list(iter)
>>> dict
[(0, '吕洞宾'), (1, '张果老'), (2, '蓝采和'), (3, '特乖离'), (4, '和香菇'), (5, '汉钟离'), (6, '王文')]
3.2 使用生成器
生成器是一种可以动态生成数据的迭代器,不同于列表等容器类型一次性把所有数据生成并存储在内存中,生成器可以在需要时动态生成数据,这样可以节省内存空间和提高程序效率.使用生成器可以通过for循环遍历序列、列表等容器类型,而不需要提前知道其中所有元素.生成器可以使用yield
关键字返回值,每次调用yield
会暂停生成器并记录当前状态,下一次调用时可以从上一次暂停的地方继续执行,而生成器的状态则保留在生成器对象内部.除了使用next()
函数调用生成器外,还可以使用send()
函数向生成器中发送数据,并在生成器内部使用yield
表达式接收发送的数据.
当我们调用一个生成器函数时,其实返回的是一个迭代器对象
只要表达式中使用了yield函数,通常将此类函数称为生成器(generator)
运行生成器时,每次遇到yield函数,则会自动保存并暂停执行,直到使用next()方法时,才会继续迭代
跟普通函数不同,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器
在学习生成器之前,需要一些前置知识,先来研究一下列表解析,列表解析是python迭代机制的一种应用,它常用于实现创建新的列表,因此要放置于[]中,列表解析非常灵活,可以用户快速创建一组相应规则的列表元素,且支持迭代操作.
列表生成式基本语法: 通过列表生成式,我们可以完成数据的生成与过滤等操作.
>>> ret = [item for item in range(30) if item >0]
>>> print(ret)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
>>>
>>> ret