yield


1.基本使用

函数中,只要有yield,那么返回就是一个yield_obj生成器(==generator==)对象,不会执行函数内部的代码

yield_obj.__next__() == next(yield_obj) 这两个一样的
首次通过yield_obj.__next__()方法会执行yield以上的代码,遇到yield然后返回,
再次执行yield_obj.__next__()方法会执行yield以下的代码,与yield以上的代码,遇到yield然后返回,
再次执行yield_obj.__next__()方法会执行yield以下的代码,与yield以上的代码,遇到yield然后返回,
再次执行......

以此类推
def func():
    while True:
        print('yield 上面代码')
        yield
        print('yield 下面代码')
yield_obj = func()#这一步不会执行函数,而是返回generator对象
print('========首次__next__()========')
yield_obj.__next__()
print('========再次__next__()========')
yield_obj.__next__()
print('========再次__next__()========')
yield_obj.__next__()

#执行结果:
'''
========首次__next__()========
yield 上面代码
========再次__next__()========
yield 下面代码
yield 上面代码
========再次__next__()========
yield 下面代码
yield 上面代码
'''

2.generator对象遍历

#generator生成器对象是可以直接通过 for item in iterable 遍历的

def func():
    for i in range(5):
        yield i
generator_obj = func()#返回一个generator对象
for item in generator_obj:
    print('item',item)

#执行结果:
'''
item 0
item 1
item 2
item 3
item 4
'''

3.yield左右两边的数据

yield右边可以接返回值(与return类似),yield左边可以通过“=”接收yield_obj.send()发送的数据

def func():
    while True:
        print('yield 上面代码')
        res = yield 'yield返回值'
        print(f'yield 下面代码 send:{res}') # yield 下面代码 send:send发送
yield_obj = func()
print('========yield返回值========')
print(yield_obj.__next__()) # yield返回值
print('========send发送========')
print(yield_obj.send('send发送'))

#执行结果
'''
========yield返回值========
yield 上面代码
yield返回值
========send发送========
yield 下面代码 send:send发送
yield 上面代码
yield返回值
'''
  • 注意:yield_obj.send()发送也可以不使用res接收,那么作用跟yield_obj.next()一样了,就是切换到yield下面的代码执行
def func():
    while True:
        print('yield 上面代码')
        yield 'yield返回值'#没有接收send发送,跟yield_obj.__next__()效果一致
        print(f'yield 下面代码')
yield_obj = func()
print('========yield返回值========')
print(yield_obj.__next__()) # yield返回值
print('========send发送========')
print(yield_obj.send('send发送'))

#执行结果:
'''
========yield返回值========
yield 上面代码
yield返回值
========send发送========
yield 下面代码
yield 上面代码
yield返回值
'''

4.yield from

基本使用

yield from 后面可以跟的可以是==生成器== 、==元组==、 ==列表==、==range()函数==产生的序列等可迭代对象

作用

简化了代码
def my_generator():
    yield from generator1()  #yield from iterable本质上等于 for item in iterable: yield item的缩写版

    #例如:yield from range(10) 等于 for i in range(10): yield i
    yield from range(10)

    for i in range(10):
        yield i
return的返回值

遍历一个生成器对象,无法获取生成器return的返回值

def my_generator():
    for i in range(5):
        if i == 2:
            return '我被迫中断了'
        else:
            yield i

def wrap_my_generator():  # 定义一个包装“生成器”的生成器,它的本质还是生成器
    result = yield from my_generator()  # 自动触发StopIteration异常,并且将return的返回值赋值给yield from表达式的结果,即result
    print('result',result)
    yield result#再yield出去,就可以遍历获取到

my_g = my_generator()
wrap_g = wrap_my_generator()

print('=======================方式一=======================')
#方式一:遍历无法获取
for j in my_g:
    print(j)
    # yield无法获取生成器return的返回值
    # 遇到return,只是会终止迭代,而不会触发异常,故而也就没办法获取return的值

print('=======================方式二=======================')
#生成器执行一次过后,就没有值了,所以要再创建一个生成器对象
my_g = my_generator()
#方式二:这样才会触发StopIteration,拿到返回值
try:
    print(next(my_g))   #每次迭代一个值,则会显式触发StopIteration
    print(next(my_g))
    print(next(my_g))
    print(next(my_g))
    print(next(my_g))
except StopIteration as exc:
    print('exc.value',exc.value)     #获取返回的值

#执行结果:
'''
=======================方式一=======================
0
1
=======================方式二=======================
0
1
exc.value 我被迫中断了
=======================方式三=======================
0
1
result 我被迫中断了
我被迫中断了
'''
数据传输的管道

其实yield from最重要的作用就是提供了一个“数据传输的管道”

def average():
    while True:
        num = yield 666
        print('数据实际上传送到这了',num)

def wrap_average(generator):
    yield from generator

wrap_g = wrap_average(average())


next(wrap_g)
wrap_g.send('send')#回到yield下面继续执行
#传送给wrap_average()生成器的,实际上是传送给了average()生成器

#执行结果:
'''
数据实际上传送到这了 send
'''