[关闭]
@songying 2018-07-18T18:32:07.000000Z 字数 1550 阅读 1845

python生成器

python高级特性


http://pyzh.readthedocs.io/en/latest/the-python-yield-keyword-explained.html
https://foofish.net/what-is-python-generator.html

首先, 所有的生成器都是迭代器, 因为生成器完全实现了迭代器的接口。

在python中, 有两种不同的方式提供生成器:
1. 生成器表达式
2. 生成器函数

什么是生成器?

生成器是可以迭代的,但是你 只可以读取它一次 ,因为它并不把所有的值放在内存中,它是实时地生成数据:

  1. >>> mygenerator = (x*x for x in range(3))
  2. >>> for i in mygenerator :
  3. ... print(i)
  4. 0
  5. 1
  6. 4

看起来除了把 [] 换成 () 外没什么不同。但是,你不可以再次使用 for i in mygenerator , 因为生成器只能被迭代一次:先计算出0,然后继续计算1,然后计算4,一个跟一个的…

生成器表达式

虽然,可以使用列表推导来初始化序列类型,但是当列表长度很大的时候, 生成器表达式更适合。

因为列表推导式返回的是一个序列对象, 而生成器表达式返回的是一个生成器对象,正如在生成器中描述的那样,生成器对内存更友好。

详细来说, 生成器表达式背后遵守了迭代器协议,可以逐个地产出元素,而不是先建立一个完整的列表,然后再把这个列表传递到某个构造函数里。前面那种方式显然能够节
省内存。

语法

将列表推导中的[]改为()就是生成器表达式

  1. (expr for iter_var in iterable if cond_expr)
  1. tuple(ord(value) for value in values)

yield - 生成器函数

yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器。此时,这个函数就称为生成器函数。

  1. >>> def createGenerator() :
  2. ... mylist = range(3)
  3. ... for i in mylist :
  4. ... yield i*i
  5. ...
  6. >>> mygenerator = createGenerator() # create a generator
  7. >>> print(mygenerator) # mygenerator is an object!
  8. <generator object createGenerator at 0xb7555c34>
  9. >>> for i in mygenerator:
  10. ... print(i)
  11. 0
  12. 1
  13. 4

这个例子没什么用途,但是它让你知道,这个函数会返回一大批你只需要读一次的值.

为了精通 yield ,你必须要理解:当你调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象,这有点蹊跷不是吗。

那么,函数内的代码什么时候执行呢?当你使用for进行迭代的时候.

现在到了关键点了!

第一次迭代中你的函数会执行,从开始到达 yield 关键字,然后返回 yield 后的值作为第一次迭代的返回值. 然后,每次执行这个函数都会继续执行你在函数内部定义的那个循环的下一次,再返回那个值,直到没有可以返回的。

如果生成器内部没有定义 yield 关键字,那么这个生成器被认为成空的。这种情况可能因为是循环进行没了,或者是没有满足 if/else 条件。

深入生成器函数

  1. 语法上与函数类似: 生成器函数与常规函数的差别在于: 生成器使用yield返回一个值,而常规函数使用return返回一个值。
  2. 自动实现迭代器协议。
  3. 状态挂起: yield语句会挂起该生成器函数的状态,保留足够的信息, 以便之后从它离开的地方继续执行。

使用生成器的注意事项

  1. 生成器只能遍历一次
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注