1. 生成器:
1.1 起源:
如果列表中有一万个元素, 我们只想要访问前面几个元素, 对其进行相关操作, 通过 for 循环方式效率太低, 并且后面的元素会浪费内存, 还会受到内存限制, 所以产生生成器来解决这个问题.
1.2 啥是生成器:
通过某种算法推演出我们所需要的内容, 而不必创建所有的列表元素. 这种一边循环一遍计算的机制叫做生成器(generator). 通过使用 yield 返回值函数, 每次调用 yield 都会暂停, 将值返回出去进行计算处理. 生成器类似于返回值为数组的一个函数, 这个函数可以接受参数, 可以被调用, 但是, 不同于一般的函数会一次性返回包括了所有数值的数组, 生成器一次只能产生一个值, 这样消耗的内存数量将大大减小. 生成器也是一个更加复杂的迭代器.
1.3 创建生成器:
方法一: 把列表生成式的 [ ] 改为 ( ) 即可.
generator_item = ( i*i for i in range(10)) 输出:<generator object <genexpr> at 0x000002A4CBF9EBA0>
如果要一个个打印出来, 可以通过 next()函数获得 generator 的下一个返回值
- print(next(generator_item)) ==> 1
- print(next(generator_item)) ==> 4
- print(next(generator_item)) ==> 9
- ......
通过这种方式 (调用 next() 方法) , 最后会报错 StopIteration , 所以一般不用这种方法, 一般用 for 循环遍历生成器
方法二: 通过函数的形式创建, 典型例子, 斐波那契数列
- def fib(max):
- n,a,b =0,0,1
- while n < max:
- yield b
- a,b =b,a+b
- n = n+1
- return 'done'
- g = fib(6)
- while True:
- try:
- x = next(g)
- print('generator:',x)
- except StopIteration as e:
- print("生成器返回值:",e.value)
- break
2. 迭代器:(迭代就是循环)
2.1 定义: 迭代器包含有 next 方法的实现, 在正确的范围内返回期待的数据以及超出范围后能够抛出 StopIteration 的错误停止迭代.
2.2 我们已经知道, 可以直接作用于 for 循环的数据类型有以下几种:
一类是集合数据类型, 如 list,tuple,dict,set,str 等
一类是 generator, 包括生成器和带 yield 的 generator function
这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable
可以使用 isinstance()判断一个对象是否为可 Iterable 对象
生成器不但可以作用于 for 循环, 还可以被 next()函数不断调用并返回下一个值, 直到最后抛出 StopIteration 错误表示无法继续返回下一个值
使用 iter()函数可以将序列转化为迭代器
2.3 小结
凡是可作用于 for 循环的对象都是 Iterable 类型;
凡是可作用于 next()函数的对象都是 Iterator 类型, 它们表示一个惰性计算的序列;
集合数据类型如 list,dict,str 等是 Iterable 但不是 Iterator, 不过可以通过 iter()函数获得一个 Iterator 对象
3. with 上下文管理器
一些不得不知道的知识:
上下文管理协议: context mangement protocol. 协议, 包含了某些方法, 大家都应该跟着去做的. 在这里就是 __enter__和__exit__两个方法.
上下文管理器: 支持上下文管理协议的对象, 这种对象实现了__enter__和__exit__方法.
as 的作用: 将返回的对象赋给一个变量, 以方便以后的使用.
with 是一个对象
运行步骤:
1. 当进入语句块时, 先执行__enter__方法, 把文件打开, 并返回该文件对象
2. 执行代码块内容
3. 离开代码块的时候, 执行__exit__方法, 关闭文件.
在执行过程中, 无论遇到什么异常, 都是要离开代码块的, 这个时候就由__exit__方法接管了. 可以在__exit__中定义, 让异常显示出来.
来源: https://www.cnblogs.com/champion-yang/p/10688823.html