概念
生成器表达式是列表推导式的一个拓展。生成器是特定的函数,允许你返回一个值,然后暂停代码的执行,稍后恢复。
列表推导式一个不足就是先构建整个列表。
生成器表达式通过结合列表推导和生成器解决这个问题。
语法和列表推导式非常类似,不过它并不真正创建数字列表而是返回一个生成器,这个生成器在每次计算出一个条目后把这个条目 产生yield出来。生成器使用了 延迟计算(lazy evaluation)。
从语法上讲生成器是一个带yield语句的函数。
一个函数或者子程序只返回一次,但一个生成器(yield语句功能)能暂停执行、保存当前执行环境并返回一个中间结果。当生成器的next()方法被调用的时候 他会准确的回到上次暂停时的状态和位置继续执行。
https://www.oschina.net/translate/improve-your-python-yield-and-generators-explained http://python.jobbole.com/81911/
生成器表达式使用形式
(expr for iter_var in iterable if cond_expr)
sum( len(word) for line in data for word in line.split())
如果想创建一个比较大的序列,使用生成器表达式的代码会执行很久,这时候可以编写一个生成器函数。
生成器函数
生成器函数和普通函数类型,但是他的返回值使用yield语句声明而不是使用return。
- yield 生成器的运行机制: 当你问生成器要一个数时,生成器会执行,直至出现 yield 语句,生成器把 yield 的参数给你,之后生成器就不会往下继续运行。 当你问他要下一个数时,他会从上次的状态。开始运行,直至出现yield语句,把参数给你,之后停下。如此反复直至退出函数。
- yield的使用: 在python中,当你定义一个函数,使用了yield关键字时,这个函数就是一个生成器,它的执行会和其他普通的函数有很多不同,函数返回的是一个对象,而不是你平常所用return语句那样,能得到结果值。如果想取得值,那得调用next()函数。
>>> def myrange(first=0,last = 10,step=1):
number = first
while number <last:
yield number
number += step
>>> myrange
<function myrange at 0x000000BF182A0E18>
>>> for x in myrange(6):
print (x)
6
7
8
9
>>> type(myrange())
<class 'generator'>
python2中
myrange = class generator(object)
| Methods defined here:
|
| __getattribute__(...)
| x.__getattribute__('name') <==> x.name
|
| __iter__(...)
| x.__iter__() <==> iter(x)
|
| __repr__(...)
| x.__repr__() <==> repr(x)
|
| close(...)
| close() -> raise GeneratorExit inside generator.
|
| next(...)
| x.next() -> the next value, or raise StopIteration
|
| send(...)
| send(arg) -> send 'arg' into generator,
| return next yielded value or raise StopIteration.
|
| throw(...)
| throw(typ[,val[,tb]]) -> raise exception in generator,
| return next yielded value or raise StopIteration.
python3中
>>> help(c)
Help on generator object:
myrange = class generator(object)
| Methods defined here:
|
| __del__(...)
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __iter__(self, /)
| Implement iter(self).
|
| __next__(self, /)
| Implement next(self).
|
| __repr__(self, /)
| Return repr(self).
|
| close(...)
| close() -> raise GeneratorExit inside generator.
|
| send(...)
| send(arg) -> send 'arg' into generator,
| return next yielded value or raise StopIteration.
|
| throw(...)
| throw(typ[,val[,tb]]) -> raise exception in generator,
| return next yielded value or raise StopIteration.
可以 看出python2和python3对于该类的方法有所不同。
- gen.next()
- next(gen)
分析示例
def gen():
while True:
try:
yield 'normal value'
yield 'normal value 2'
print('here')
except ValueError:
print('we got ValueError here')
except TypeError:
break
g=gen()
print(next(g))
print(g.throw(ValueError))
print(next(g))
print(g.throw(TypeError))
- 可以通过generator.send(arg)来传入参数,协程模型。.next()相当于.send(None)
- 可以通过generator.throw(exception)来传入一个异常。throw语句会消耗掉一个yield
- 可以通过generator.close()关闭生成器
>>> g = gen()
>>> print(next(g))
normal value
>>> print (g.throw(ValueError))
we got ValueError here
normal value
>>> print (next(g))
normal value 2
>>> print (g.throw(TypeError))
Traceback (most recent call last):
File "<pyshell#200>", line 1, in <module>
print (g.throw(TypeError))
StopIteration
- print(next(g)):会输出normal value,并停留在yield ‘normal value 2’之前。
- 由于执行了g.throw(ValueError),所以会跳过所有后续的try语句,也就是说yield ‘normal value 2’不会被执行,然后进入到except语句,打印出we got ValueError here。然后再次进入到while语句部分,消耗一个yield,所以会输出normal value。
- print(next(g)),会执行yield ‘normal value 2’语句,并停留在执行完该语句后的位置。
- g.throw(TypeError):会跳出try语句,从而print(‘here’)不会被执行,然后执行break语句,跳出while循环,然后到达程序结尾,所以跑出StopIteration异常。
随机抽取全部成员
>>> def getRandElement(lst):
import random
while len(lst) > 0:
yield lst.pop(random.randint(0,len(lst)-1))
>>> gen = getRandElement([1,2,3,432423])
>>> next(gen)
432423
>>> next(gen)
2
>>> next(gen)
1
>>> next(gen)
3
>>> next(gen)
Traceback (most recent call last):
File "<pyshell#284>", line 1, in <module>
next(gen)
StopIteration
生成器作用
- 异步操作 Async Operation (I/O bound or memory efficien)
- 生成器主要的作用就是延迟计算,因此在构造大的数据集合时在内存和效率方面都有很大的提升
- 实现协程的功能,降低线程间或进程间上下文切换的开销
生成器
生成器其实就是一种特殊的迭代器。它使一种更为高级、更为优雅的迭代器。使用生成器让我们可以以一种更加简洁的语法来定义迭代器。 让我们先明确以下两点:
- 任意生成器都是迭代器(反过来不成立)
- 任意生成器,都是一个可以延迟创建值的工厂