生成器(generator)

生成器

生成器就是一个带yield的函数(只要函数包含yield,函数调用就会返回一个生成器对象),普通的函数只能返回一次,但一个生成器能够暂停执行并返回一个中间的结果,当生成器的next()方法被调用的时候,会从离开的地方继续执行,并且能够上次调用的所有局部变量保持不变。说得直白点,生成器就是一个特殊的函数,它能产生一列的结果而不只是产生单一结果。
生成器也是一个迭代器,拥有next方法并且行为与迭代器完全相同,可用于for循环中(for循环每次自动调用next方法直到抛出StopIteration异常),并且定义一个生成器比定义一个迭代器简单很多

生成器的优点
  1. 可以保留函数的参数
  2. 每次调用next方法时,所使用的参数都是上一次调用所保留下来的,而不是新创建的,并且可以多次调用
  3. 生成器的定义比迭代器的定义简单
  4. 占用空间小,每次调用才产生值,而不是产生完全后返回
简单的生成器

生成器可以看作是一个迭代器,拥有next()方法,当一个真正的返回(调用return)或者函数结束没有更多的值返回时(调用next()),会抛出StopIteration异常

用生成器实现斐波那契系数

def fab(max):
    a = 1
    b = 1
    i = 0
    while i<max:
        yield b
        a,b = b,a+b
        i += 1

it = fab(5)

for i in range(7):
    print it.next()

# 1
# 2
# 3
# 5
# 8
# Traceback (most recent call last):
#   File "test.py", line 13, in <module>
#     print it.next()
# StopIteration
生成器的特性

1.当第1次调用生成器函数的时候,并不运行函数(如函数中有print语句,并不执行),**只是构建生成器对象*,并将生成器返回**,生成器函数可带参数也可不带参数

>>> def fab(max):
...     a,b,i = 1,1,0
...     while i<max:
...             yield b
...             a,b = b,a+b
...             i +=1
... 
>>> f = fab(10)
>>> type(f)
<type 'generator'>

2.当第1次调用生成器的next方法时,生成器才开始执行生成器函数(并不是构建,此时运行1中说的print语句),直到遇到yield暂停执行,并将yield的参数作为此次next的返回值

>>> f.next()
1

3.之后每次调用next方法,生成器将恢复环境并从上次运行的地方开始重新开始执行,直到再次遇到yield时暂停,并且将yield的参数作为next的返回值。

>>> f.next()
2

4.当调用next方法时生成器结束(遇到空的return语句或到达函数末尾),此次next将会抛出StopIteration异常
5.生成器函数中不允许有参数的return语句,如果出现,将会抛出SyntaxError: 'return' with argument inside generator错误

def fab(max):
    a = 1
    b = 1
    while i<max:
        yield b
        a,b = b,a+b
        i += 1
    return False

it = fab(5)
#   File "test.py", line 8
#     return False
# SyntaxError: 'return' with argument inside generator

6.生成器函数在每次暂停执行时,函数体内的所有变量都将被封存(freeze)在生成器中,并将在恢复执行时还原,并且类似于闭包,即使是同一个生成器函数返回的生成器,封存的变量也是互相独立的。

增强的生成器

send():将值返回给生成器
throw():在生成器中抛出异常
close():要求生成器退出

1.send(value)

send是除了next方法以外另一个恢复生成器的方法;此时,yield必须是一个表达式,yield表达式返回的值就是调用send方法的参数,生成器从yield开始运行,直到再次遇到yield,并将yield的参数作为send方法的返回值

  1. 调用send传入非None,生成器必须处于挂起状态,否则将抛出异常。不过,未启动的生成器仍可以使用None作为参数调用send
  2. 如果使用next恢复生成器,yield表达式的值将是None
def gener():
    name = 'not input'
    while True:
        name = yield name
        if name == None:
            name = "not input"
        else:
            name = "I'm " + name


it = gener()

print it.send(None)
print it.send("zhainankl")
print it.next()

# not input
# I'm zhainankl
# not input
2.close()

这个方法用于关闭生成器。对关闭的生成器后再次调用next或send将抛出StopIteration异常。

3.throw(type, value=None, traceback=None):

这个方法用于在生成器内部(生成器的当前挂起处,或未启动时在定义处)抛出一个异常。

利用yield模拟线程并发

def thread1():
    for x in range(4):
        yield  x
        

def thread2():
    for x in range(4,8):
        yield  x
        

threads=[]
threads.append(thread1())
threads.append(thread2())


def run(threads): #写这个函数,模拟线程并发
    pass

run(threads)
def run(threads):
    for t in threads:
        try:
            print t.next()
        except StopIteration:
            pass
        else:
            threads.append(t)

参考

  1. Python函数式编程指南(四):生成器
  2. Python之美[从菜鸟到高手]--生成器之全景分析

转载于:https://www.cnblogs.com/happpyboy/p/4355727.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值