列表生成式
通过上一篇介绍 列表生成式文章可以知道,它可以快速创建我们需要的列表
局限性
- 受内存限制,列表生成式创建的列表的容量肯定有限的
- 不仅占用很大的存储空间,如果我们仅仅需要访问前几个元素,那后面绝大多数元素占用的空间都白白浪费了
什么是生成器
- 若列表元素可以按照某种算法算出来,就可以在循环的过程中不断推算出后续需要用的元素,而不必创建完整的 list,从而节省大量的空间
- 边循环边计算的机制,叫生成器(generator)
最简单的生成器
L = [x * x for x in range(10)]print(L)print(type(L))L = (x * x for x in range(10))print(L)print(type(L))# 输出结果[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]<class \'list\'><generator object <genexpr> at 0x000001D607541EB8><class \'generator\'>
只要把一个列表生成式的[]改成(),就创建了一个 generator
如何打印生成器每个元素
直接简单 for 循环
L2 = (x * x for x in range(10))for i in L2:print(i)
next() 方法
可以获取 generator 的下一个元素
基本不会使用这个
L2 = (x for x in range(10))print(next(L2))print(next(L2))print(next(L2))print(next(L2))print(next(L2))print(next(L2))# 输出结果012345
还有另一个方法 .__next()__
L2 = (x for x in range(10))print(L2.__next__())print(L2.__next__())print(L2.__next__())print(L2.__next__())print(L2.__next__())print(L2.__next__())# 输出结果012345
生成器的迭代原理
generator 能够迭代的关键就是 next() 方法,通过重复调用 next() 方法,直到捕获一个异常
yield 函数
- 带有 yield 的函数不再是一个普通函数,而是一个生成器 generator
- yield 相当于 return 返回一个值,并且记住这个返回值的位置,下次迭代时,代码会从 yield 的下一条语句开始执行,直到函数结束或遇到下一个 yield
普通的斐波拉契数列
1, 1, 2, 3, 5, 8, 13, 21, 34, …,除第一个和第二个数外,任意一个数都可由前两个数相加得到
# 斐波拉契数列def fib(max):n, a, b = 0, 0, 1while n < max:print(b)a, b = b, a + bn = n + 1fib(8)# 输出结果1123581321
它和生成器很像,知道第一个元素值,就可以推算后面的任意个元素了
是用 yield 的斐波拉契数列
def fib(max):n, a, b = 0, 0, 1while n < max:yield ba, b = b, a + bn = n + 1fib(8)print(fib(8))# 输出结果1123581321<generator object fib at 0x00000246A5001EB8>
生成器的执行流程
函数是顺序执行,遇到 return 或者最后一行执行完就返回
而生成器的执行流程是
- 每次调用 next() 或 for 循环的时候执行,遇到 yield 就返回
- 一个生成器里面可以有多个 yield
- 再次执行时从上次返回的 yield 语句处继续执行
# 执行流程def odd():print(\'step 1\')yield 1print(\'step 2\')yield 3print(\'step 3\')yield 5L = odd()for i in L:print(i)# 输出结果step 11step 23step 35
生成器的工作原理
- 它是在 for 循环过程中不断计算下一个元素,并在适当的条件结束 for 循环
- 对于函数改成的 generator 来说,,遇到 return 语句或者执行到函数最后一行时,就是结束 generator 的指令,for 循环随之结束
生成器的优点
在不牺牲过多速度情况下,释放了内存,支持大数据量的操作
不使用生成器下的代码
from tqdm import tqdma = []for i in tqdm(range(10000000)):temp = [\'你好\'] * 2000a.append(temp)for ele in a:continue
运行结果
可以看到开始运行大数据量循环代码后,内存暴增,并且占满了电脑所有内存,很明显这是不合理且不可接受的!
使用生成器的代码
def test():for i in tqdm(range(10000000)):temp = [\'你好\'] * 2000yield tempa = test()for ele in a:continue
运行结果
内存丝滑的很,奈斯!
生成器的应用场景
当然就是需要处理大数据量的场景了,比如一个文件有几百万行数据,或者有几百万个文件需要分别读取处理