列表/字典推导式
列表推导式 样例
1 | # >> 实现列表自加一 |
字典推导式 样例
1 | In [5]: {k:k+1 for k in info} |
生成器
- 生成器是一个特殊的程序,可以被用作控制循环的迭代行为.
- python 中生成器是迭代器的一种,使用 yield 返回值函数,每次调用 yield 会暂停,
- 而可以使用 next()函数和 send()函数恢复生成器。
- 生成器可以节省大量内存。
生成器表达式
把一个列表生成式的[]中括号改为()小括号,就创建一个 generator
1 | #列表生成式 |
生成器表达式使用
使用next()获取生成器的下一个返回值
1 | generator_ex = (x*x for x in range(4)) |
创建生成器后,一般使用for循环
实现。
生成器函数
使用yield 构造生成器函数
yield 是一个类似 return 的关键字,迭代一次遇到 yield 的时候就返回 yield 后面或者右面的值。
而且下一次迭代的时候,从上一次迭代遇到的 yield 后面的代码开始执行
任何使用了 yield 的函数就是生成器,生成器就是一个返回迭代器的函数,或者说生成器就是一个迭代器。
1 | def fib(max): |
小结
生成器的用法
- next() 返回生成器下个值
- close() 关闭生成器。生成器被关闭后,再次调用 next()方法,不管能否遇到 yield 关键字,都会立即抛出 StopIteration 异常。
- send() 可以通过 send()方法,向生成器内部传递参数.继续运行 yield 之后的代码。
- throw() 除了向生成器函数内部传递参数,还可以传递异常。
生成器用法样例
1 | #! -*- coding:utf-8 -*- |
生成器的分类
- 生成器函数: 也是用 def 定义的,利用关键字 yield 一次性返回一个结果,阻塞,重新开始
- 生成器表达式: 返回一个对象,这个对象只有在需要的时候才产生结果
生成器的优点
- 节省内存。大量数据时尤为明显。
- 节省代码,减少代码量同时提高代码可读性。
- 模拟并发。
模拟并发。Python 虽然支持多线程,但是由于 GIL(全局解释锁,Global Interpreter Lock)的存在,同一个时间,只能有一个线程在运行,所以无法实现真正的并发。这时就出现了协程。复杂解释不说了,简单说协程就是你可以暂停执行的函数”。也就是 yield。
Python 实现协程最简单的方法,就是使用 yield。当一个函数在执行过程中被阻塞时,就用 yield 挂起,然后执行另一个函数。当阻塞结束后,可以用 next()或者 send()唤醒。相比多线程,协程的好处是它在一个线程内执行,避免线程之间切换带来的额外开销,而且协程不存在加锁的步骤。
迭代器
迭代器包含有 next 方法的实现,在正确的范围内返回期待的数据以及超出范围后能够抛出 StopIteration 的错误停止迭代。
Iterable 可迭代对象
使用 isinstance()判断一个对象是否为可 Iterable 对象
1 | # Iterable 可迭代对象 |
Iterator 迭代器
一个实现了 iter 方法的对象是可迭代的,一个实现 next 方法并且是可迭代的对象是迭代器。
可以被 next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
所以一个实现了 iter 方法和 next 方法的对象就是迭代器。
1 | In [6]: from collections import Iterator |
迭代器和可迭代对象之间的转换
Iterable 转为 Iterator: iter([1,2,3])
Iterator 转为 Iterable: list((x+1 for x in range(10)))
1 | In [11]: isinstance(iter([]), Iterator) |
总结
- 凡是可作用于 for 循环的对象都是 Iterable 类型;
- 凡是可作用于 next()函数的对象都是 Iterator 类型,它们表示一个惰性计算的序列;
- 集合数据类型如 list、dict、str 等是 Iterable 但不是 Iterator,不过可以通过 iter()函数获得一个 Iterator 对象。
对 yield 的总结
(1)通常的 for..in…循环中,in 后面是一个数组,这个数组就是一个可迭代对象,类似的还有链表,字符串,文件。他可以是 a = [1,2,3],也可以是 a = [x*x for x in range(3)]。
它的缺点也很明显,就是所有数据都在内存里面,如果有海量的数据,将会非常耗内存。
(2)生成器是可以迭代的,但是只可以读取它一次。因为用的时候才生成,比如 a = (x*x for x in range(3))。!!!!注意这里是小括号而不是方括号。
(3)生成器(generator)能够迭代的关键是他有 next()方法,工作原理就是通过重复调用 next()方法,直到捕获一个异常。
(4)带有 yield 的函数不再是一个普通的函数,而是一个生成器 generator,可用于迭代
(5)yield 是一个类似 return 的关键字,迭代一次遇到 yield 的时候就返回 yield 后面或者右面的值。而且下一次迭代的时候,从上一次迭代遇到的 yield 后面的代码开始执行
(6)yield 就是 return 返回的一个值,并且记住这个返回的位置。下一次迭代就从这个位置开始。
(7)带有 yield 的函数不仅仅是只用于 for 循环,而且可用于某个函数的参数,只要这个函数的参数也允许迭代参数。
(8)send()和 next()的区别就在于 send 可传递参数给 yield 表达式,这时候传递的参数就会作为 yield 表达式的值,而 yield 的参数是返回给调用者的值,也就是说 send 可以强行修改上一个 yield 表达式值。
(9)send()和 next()都有返回值,他们的返回值是当前迭代遇到的 yield 的时候,yield 后面表达式的值,其实就是当前迭代 yield 后面的参数。
(10)第一次调用时候必须先 next()或 send(),否则会报错,send 后之所以为 None 是因为这时候没有上一个 yield,所以也可以认为 next()等同于 send(None)
yield 实现单线程并发
yield 单线程并发样例
1 | #! -*- coding:utf-8 -*- |
第三方函数库-greenlet
1 | """ |