生成器:生成器是一类特殊的迭代器,就是需要在生成的时候才产生结果yield,而不是立即返回结果return。这样可以同时节省CPU和内存。
生成器自动实现了迭代器的两个方法:__iter__() 和 __next__()
有两种方法实现生成器:
- 生成器函数。使用yield返回结果。yield语句一次返回一个结果,在每个结果中间挂起函数的状态,下次调用时从他离开的地方继续执行。
- 生成器表达式。类似列表表达式,用()来表示。
1. 简单的生成器实例
如下代码定义了MyGenerator函数,for循环3次,yield返回值。
gen = MyGenerator() 创建生成器对象gen,但此时MyGenerator函数方法体并没有开始执行。
gen,__next__()激活生成器,打印generator start,并返回for循环第一次遍历的值:0
next(gen)和gen.__next__()作用是一样的,不过此时函数要从for第二次循环开始,不会打印generator start,而是输出值:1
gen.send(None),这个方法跟前面两个方法的作用也是一样的,send()方法传参为None时仅代表激活生成器(执行一次生成器的方法体),第三次输出:2
第四次会发生异常StopIteration,此异常用于标识迭代的完成,因为for循环只循环了3次,迭代结束,
def MyGenerator():
print("generator start")
for i in range(3):
yield i
gen = MyGenerator()
print(gen) # <generator object MyGenerator at 0xffffa7271900>
print(type(gen)) # <class 'generator'>
print(gen.__next__()) # 打印generator start, 打印 1
print(next(gen)) # 打印 2
print(gen.send(None)) # 打印 3
print(gen.__next__()) # 发生异常 StopIteration
输出:
<generator object MyGenerator at 0xffffa7271900>
<class 'generator'>
generator start
0
1
2
Traceback (most recent call last):
File "E:\code\test.py", line 10, in <module>
print(gen.__next__())
StopIteration
2. 生成器对象的send()方法实例
上个实例说明了gen.send(None)参数为空时,仅仅表示激活生成器,调用了生成器函数方法体。
当send()参数不为空时,该参数指定的是上一次被挂起的yield语句的返回值。
如下代码:
1. gen.send(None)激活生成器,打印generator start,代码执行到value = yield 666时,会返回666,并挂起
2.gen.send(888),给上一次挂起的yield设置返回值,则vaule=888,代码执行到value2 = yield value,打印:888,然后挂起
3.gen.send(999),给上一次挂起的yield设置返回值,则vaule2=999,代码执行到yield value,打印:999,然后挂起
4.gen.send(000),由于上次挂起的地方是程序的最后一段代码,且没可迭代的对象,则发生异常StopIteration,迭代结束。
def MyGenerator():
print("generator start")
value = yield 666
value2 = yield value
yield value2
gen = MyGenerator()
print(gen.send(None)) # 激活生成器,打印:generator start,打印:666
print(gen.send(888)) # 给上一次挂起的yield设置返回值,则vaule=888,打印:888
print(gen.send(999)) # 给上一次挂起的yield设置返回值,则vaule2=999 打印:999
print(gen.send(000)) # 迭代结束,发生异常StopIteration
输出:
generator start
666
888
999
Traceback (most recent call last):
File "E:\code\h_test.py", line 11, in <module>
print(gen.send(000)) # 迭代结束,发生异常StopIteration
StopIteration
3. yield from语法详解
yield from需要在方法体中使用,后面跟着的是可迭代对象,可以是迭代器、生成器。用来遍历输出值。
如下代码:创建了两个迭代对象和两个生成器,使用yield from来遍历它们的值
_list = ["a", "b", "c"] # 可迭代的列表
_dict = {"name": "zs", "age": 18} # 可迭代的字典
generator1 = (i for i in range(3)) # 生成器
# 生成器
def generator2():
for i in range(3, 6):
yield i
# 遍历输出单个迭代对象的值,该方法也是一个生成器
def func(iter_obj):
yield from iter_obj
# 遍历输出多个迭代对象的值,该方法也是一个生成器
def func2(*args, **kwargs):
for item in args:
yield from item
print(list(func(_list))) # 输出 a b c
print(list(func2(_list, _dict, generator1, generator2())))
输出:
['a', 'b', 'c']
['a', 'b', 'c', 'name', 'age', 0, 1, 2, 3, 4, 5]