python之生成器简介

一。生成器与yield
若函数体包含yield关键字,再调用函数,并不会执行函数体代码,得到的返回值即生成器对象

>>> def my_range(start,stop,step=1):
...     print('start...')
...     while start < stop:
...         yield start
...         start+=step
...     print('end...')
... 
>>> g=my_range(0,3)
>>> g
<generator object my_range at 0x104105678>

生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器

>>> g.__iter__
<method-wrapper '__iter__' of generator object at 0x1037d2af0>
>>> g.__next__
<method-wrapper '__next__' of generator object at 0x1037d2af0>

因而我们可以用next(生成器)出发生成器所对应函数的执行

>>> next(g) # 触发函数执行直到遇到yield则停止,将yield后的值返回,并在当前位置挂起函数
start...
0
>>> next(g) # 再次调用next(g),函数从上次暂停的位置继续执行,直到重新遇到yield...
1
>>> next(g) # 周而复始...
2
>>> next(g) # 触发函数执行没有遇到yield则无值返回,即取值完毕抛出异常结束迭代
end...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

既然生成器对象属于迭代器,那么必然可以使用for循环迭代,如下:

>>> for i in countdown(3):
...     print(i)
... 
countdown start
3
2
1
Done!

有了yield关键字,我们就有了一种自定义迭代器的实现方式。yield可以用于返回值,但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值

二yield表达式的应用
在函数内可以采用表达式形式的yield

def eater():
    print('ready to eat')
    while True:
        food=yield 
        print('get the food: %s,and start to eat' %food)

可以拿到函数的生成器对象持续为函数体send值,如下:

g=eater() #得到生成器对象
print(g)#<generator object eater at 0x0000000001E166D8>
next(g)#ready to eat    需要事先初始化一次,让函数挂起在food=yield,等待调用g.seed()方法为期传值
print(g.send('包子'))#get the food: 包子,and start to eat
print(g.send('鸡腿'))#get the food: 鸡腿,and start to eat

针对表达式形式的yield,生成器对象必须事先被初始化一次,让函数挂起在food=yield的位置,等待调用g.send()方法为函数体传值,g.send(None)等同于next(g)

我们可以编写装饰器来完成为所有表达式形式yield对应生成器的初始化操作,如下:

def init(func):#func=eater的内存地址
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper

@init  #   eater=init(eater)====>eater=wrapper的内存地址
def eater():
    print('ready to eat')
    while True:
        food=yield
        print('get the food %d,and start to eat' %food)

eater()#   此时此处的eater已被装饰器偷换成wrapper
#执行开始
#wrapper()
#g = func(*args, **kwargs)#func=eater的内存地址
#print('ready to eat')
#food=yield
#执行到这里因为遇到了yield,所以暂停了

表达式形式的yield也可以用于返回多次值,即变量名=yield 值的形式,如下:

def eater():
    print('ready to eat')
    food_list=[]
    while True:
        food=yield food_list
        food_list.append(food)
        print(food_list)

e=eater()
print(next(e))
e.send('卫龙') 
e.send('烧麦')
e.close()#关闭后不能传值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值