1 生成器的引入
在Python中,常常需要使用可迭代对象,例如我们创建了一个如下的列表可迭代对象:
nums = [num for num in range(10)]
print(nums) # 输出 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
乍一看,没啥问题,但是倘若我们创建的列表是这样的呢?
nums = [num for num in range(10000000)]
print(nums) # 输出 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ..., 10000000]
nums
变量存放在内存中,此时内存占用非常大!
综上所述:对于海量数据,列表对象占用大量内存!因此Python中引入了生成器(Generator)。
2 创建生成器
2.1 方法一
将列表生成式的[]
改成()
,例如:
nums = (num for num in range(10000000))
print(nums) # 输出 <generator object <genexpr> at 0x7fc81069a040>
此时nums
就是一个生成器。
2.2 方法二
含有yield
关键字的函数(替换为原先的return
关键字),调用该函数将返回一个生成器:
def generator_nums(n):
for i in range(n):
yield i
nums = generator_nums(10000000)
print(nums) # 输出 <generator object generator_nums at 0x7fc811265ac0>
3 使用生成器
开头引入生成器就已经提到过,生成器可以作为可迭代对象使用(其实生成器就是一个迭代器),例如
from typing import Iterator
def generator_nums(n):
for i in range(n):
yield i
nums = generator_nums(10000000)
print(isinstance(nums, Iterator)) # 输出 True
for num in nums:
print(num)
更底层的情形下,生成器可用nums.__next__()
或next(nums)
来取值。遍历到生成器结尾时,会抛出异常StopIteration
:
def generator_nums(n):
for i in range(n):
yield i
nums = generator_nums(10000000)
for i in range(5):
num = nums.__next__()
print(f"循环第{i}次,生成器取值为{num}")
for j in range(5, 10):
num = next(nums)
print(f"循环第{j}次,生成器取值为{num}")
上述代码打印结果如下:
循环第0次,生成器取值为0
循环第1次,生成器取值为1
循环第2次,生成器取值为2
循环第3次,生成器取值为3
循环第4次,生成器取值为4
循环第5次,生成器取值为5
循环第6次,生成器取值为6
循环第7次,生成器取值为7
循环第8次,生成器取值为8
循环第9次,生成器取值为9