Python|小黑板,划重点了——python生成器

Python|小黑板,划重点了——python生成器

文章图片

Python|小黑板,划重点了——python生成器

老板下达了一个任务 , 说是要每天遍历一百万数据 , 找到日志中重要地段的信息 , 重新记录存放?到底要怎么搞呢?
小张回答说列表生成式不就可以嘛 , 老板笑而不语 。 小王答曰用生成器吧 。 此时 , 老板开心地点了点头 。
小张不明白 , 列表就可以很好处理的问题 , 为什么要用生成器呢?
后来 , 小张明白了......

生成器 generator我们知道 , 通过列表生成式 , 我们可以直接创建一个列表 。 但是 , 受客观条件影响 , 我们使用的机器都是受到内存限制 , 所以列表容量肯定是有限的 。 这样生成一个列表不仅占用内存 , 如果我们只需要访问一部分值 , 还会造成大量的内存浪费 。
在Python2中可以做一个尝试 , 感兴趣的不妨试试 。
打开IDE交互界面 , 进入Python交互窗口 , range(1000000)试试 , 不行可以range(10000000)再试试 , 那时候就可以很明显的感受到内存计算的差别了 。
正是因为这个缺点 , 在python3中对range进行了优化 , range(10000)得到的结果是range(010000) , 这样的一个生成式了 。
所以 , 如果列表元素可以按照某种算法推算出来 , 那我们是否可以在循环的过程中不断推算出后续的元素呢?
像上面这个循环 , 每次循环只是+1而已 , 我们完全可以写一个算法 , 让他执行一次就自动1 , 这样就不必创建完整的 , 从而节省大量的空间 。
在 Python中 , 这种一边循环一边计算后面元素的机制 , 称为生成器: generator

生成器的生成要创建一个 gonerator , 有很多种方法 。
第一种方法很简 , 只要把一个列表生成式的改成()的形式 , 就创建了个gonerator
>>> [ x for x in range(10)

[0 1 2 3 4 5 6 7 8 9

>>> ( x for x in range(10))
<generator object <genexpr> at 0x000002C103210E40>
>>> g = ( x for x in range(10))

如上面的代码所示 , 我们可以直接得出列表的所有元素 。 那么 , 生成器要怎么访问呢?
生成器的元素获取next()生成器的元素 , 如果要一个一个打印出来 , 可以通过next()函 , 获得generator的下一个返回值 。
>>> g = ( x for x in range(10))
>>> next(g)
0
>>> next(g)
1
>>> next(g)
2
>>> next(g)
3
>>> next(g)
4
>>> next(g)
5
>>> next(g)
6
>>> next(g)
7
>>> next(g)
8
>>> next(g)
9
>>> next(g)
Traceback (most recent call last):
 File \"<pyshell#13>\" line 1 in <module>
   next(g)
StopIteration

【Python|小黑板,划重点了——python生成器】此时 , 我们每一次调用next就会生成一个新的元素 , 直到最后的时候会抛出一个异常 , 而这个异常 , 我们可以通过后面的方法规避掉 。

for循环当然 , 上面这种不断调用next(g)实在是太变态了 。 正确的方法是使用tor循环 , 因为 gonorator也是可选代(遍历)对象 。
g = ( x for x in range(10))
for i in g:
   print(i)

0
1
2
3
4
5
6
7
8
9

通过for循环来迭代它 , 就不需要关心会不会抛异常了 。
生成器函数特点:动态获取数据 , 循环一次 , 计算一次 , 执行一次
生成器函数:具有yield语句 。
案例:生成器的思想解决斐波那契数列
原始的方法