异步编程 Python asyncio 小白学习 – yield生成器详解

定义生成器的方法非常简单,只要使用 yield 关键词即可。yield是生成、产生的意思,在Python中,它作为一个关键词,是生成器的标志。

def generator_func():
    yield 0
    yield 1
    yield 2


gen_obj = generator_func()
print(type(gen_obj))
print(gen_obj.__class__)
print(gen_obj.__class__.__class__)
print(hasattr(gen_obj, '__iter__'))
print(hasattr(gen_obj, '__next__'))

输出结果:

<class ‘generator’>
<class ‘generator’>
<class ‘type’>
True
True

可以看出gen_obj是一个生成器对象,生成器必是迭代器(但是迭代器不一定是生成器),在进行如下操作:

print(next(gen_obj))
print(next(gen_obj))
print(next(gen_obj))

输出结果:

0
1
2

继续执行:

print(next(gen_obj))

输出结果:

Traceback (most recent call last):
File “E:/pycharmprojects/python_learning/generator/yield_func.py”, line 24, in
print(next(gen_obj))
StopIteration

在函数 generator_func() 中,关键词 yield 发起了一条语句,其作用是返回指定对象。从这点来看,颇类似于 return 。当然,二者肯定有区别的,下面就将它们进行对比。

def return_test(n):
    print('starting...')
    while n > 0:
        print('before return')
        return n
        n -= 1
        print('after return')


return_value = return_test(3)
print(return_value)

输出结果:

starting…
before return
3

显然,当代码执行到return时,返回n的值,函数退出,后面的两条语句并没有执行。

将 return 改为 yield :

def yield_test(n):
    print('starting...')
    while n > 0:
        print('before return')
        yield n
        n -= 1
        print('after return')


yield_obj = yield_test(3)  # 相当于实例化一个生成器对象,并没有执行函数
print(yield_obj.__next__())  # 或者直接用next(yield_obj),开始执行函数
print(yield_obj.__next__())
print(yield_obj.__next__())

输出结果:

starting…
before return
3

after return
before return
2

after return
before return
1

根据输出结果,这说明 yield 的作用不仅仅是返回指定对象,还有一个作用,就是让函数“暂停”,可以形象地说是“挂起”,但不是结束函数。当再次“激活”,就从“挂起”位置继续执行了。

当继续执行时:

print(yield_obj.__next__())

输出结果:

after return

Traceback (most recent call last):
File “E:/pycharmprojects/python_learning/generator/compare2.py”, line 22, in
print(yield_obj.next())
StopIteration

把上面的代码拓展一下如下:

def yield_test(n):
    print('starting...')
    while n > 0:
        print('before return')
        yield n
        n -= 1
        print('after return')


yield_obj = yield_test(3)  # 相当于实例化一个生成器对象,并没有执行函数
print(yield_obj.__next__())  # 或者直接用next(yield_obj),开始执行函数
print('第1次返回')
print(yield_obj.__next__())
print('第2次返回')
print(yield_obj.__next__())
print('第3次返回')

运行结果如下:

D:\asyncio\venv\Scripts\python.exe D:/asyncio/testYield.py
starting...
before return
3
第1次返回
after return
before return
2
第2次返回
after return
before return
1
第3次返回

Process finished with exit code 0