Python中的生成器
□ 生成器generator
□ 生成器指的是生成器对象,可以由生成器表达式,也可以由yield关键字得到一个生成器函数,
调用这个函数得到一个生成器对象.
□ 生成器函数
□ 函数体中包含yield关键字的函数,返回生成器对象,生成器的函数体不会立即被执行
□ 生成器对象是一个可迭代对象
□ 生成器对象是延迟计算,惰性求值的
举例:1
def inc():
for i in range(5):
yield i
print(type(inc))
print(type(inc()))
x = inc()
print(type(x))
print(next(x))
for m in x:
print(m, '*')
for m in x:
print(m, '**')
如下所示:
inc是一个function
inc()函数返回值为生成器,这是由于yield关键字
next()方法可以从生成器中取出元素,当元素都被取出之后,生成器内便不再有元素.无法再次进行迭代
举例:2
def gen():
print("line 1")
yield 1 # 暂停执行,并且返回1
print("line 2")
yield 2 # 暂停执行,并且返回2
print("line 3")
return 3 # 结束函数
next(gen()) # line 1
next(gen()) # line 1
g = gen()
print(next(g)) # line 1
print(next(g)) # line 2
print(next(g)) # StopIteration 异常
结果如下,每次调用生成器函数,会返回一个新的生成器对象,如果在一个函数中有多个yield,则从当前位置执行到yield时,会暂停执行,并且把yield后的值返回:如下面打印的1和2
再次执行next函数时,会从yield语句的后(下一行)开始执行,执行到下一个yield关键字,renturn关键字仍然可以终止程序,但是return后的值将不会被捕获(并没有返回3不是吗),并且return会导致无法获取下一个值,抛出StopIteration异常
将上面报错的地方改为print(next(g, ‘End’)),此处’End’为默认值,如果生成器迭代结束,返回默认值,而不是报错
举例:3
def fnc():
for x in range(3):
ret = yield x
print(ret)
it = fnc()
print(next(it)) # call_1
print(next(it)) # call_2
print(next(it)) # call_3
print(next(it)) # call_4
我们来分析一下下面的结果:
□ 第一次调用next时当执行到ret = yield x时,所执行的操作为:
1.声明一个名为ret的变量,此时变量值为None
2.yield x的执行,暂停程序并且返回x的值打印0,注意这里只是返回给调用方打印出来,而不是赋值给ret
□ 第二次调用next时:
1.从上次暂停位置后面开始,即print(ret),此时由于ret在call_1中并没有得到赋值,所以依然为None
2.此次循环结束,执行到下一次循环,重复call_1的操作,ret还是未赋值,yield 返回1
□ 第三次调用next:
同call_2,打印ret的值为None,重复call_1的操作,ret未赋值,yield 返回2
□ 第四次调用next:
同call_2,打印ret的值为None,由于循环结束,即生成器迭代结束,没有元素可以迭代,但是next的目的是要从生成器中取值,所以本次抛出StopIteration异常
yield from
def inc():
for x in range(1000):
yield x
# 等价于
def inc():
yield from range(1000)
yield from是python3.3出现的新语法
yield from itertable 是 for item in itaerable: yield item的语法糖