概念

生成器表达式是列表推导式的一个拓展。生成器是特定的函数,允许你返回一个值,然后暂停代码的执行,稍后恢复。 列表推导式一个不足就是先构建整个列表。

生成器表达式通过结合列表推导和生成器解决这个问题。

语法和列表推导式非常类似,不过它并不真正创建数字列表而是返回一个生成器,这个生成器在每次计算出一个条目后把这个条目 产生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)
  • 生成器主要的作用就是延迟计算,因此在构造大的数据集合时在内存和效率方面都有很大的提升
  • 实现协程的功能,降低线程间或进程间上下文切换的开销

生成器

生成器其实就是一种特殊的迭代器。它使一种更为高级、更为优雅的迭代器。使用生成器让我们可以以一种更加简洁的语法来定义迭代器。 让我们先明确以下两点:

  • 任意生成器都是迭代器(反过来不成立)
  • 任意生成器,都是一个可以延迟创建值的工厂

results matching ""

    No results matching ""