定义生成器的方法非常简单,只要使用 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