文章目录
1. 什么是生成器
上篇文章讲了Python迭代器;这篇文章就来研究一下生成器。
生成器:一种特殊的迭代器,含有yield的函数就是生成器。
特殊在哪里? 生成器是一个没有手动实现__iter__
和__next__
方法的迭代器。
下属代码就是一个生成器
def func():
x = 0
while True:
x += 1
yield x**2
# 生成器的使用方式
f = func() # func中含有yield,因此是一个生成器,同时func返回的是一个生成器对象
for i in range(10):
ret = next(f)
print(ret)
2. 创建生成器的方法
2.1 方法一
将列表生成式的[]
换成()
如下:
n = [x for x in range(10)]
print(n) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
m = (x for x in range(10))
print(m) # <generator object <genexpr> at 0x0000027D9AAFE660>
可以看到,m是一个生成器对象。
2.2 方法二
在函数中使用yield
如下:
def func():
for i in range(10):
yield i
f = func()
print(f) # <generator object func at 0x000001ABFCEC19E0>
f也是一个生成器对象;这里要明白,当函数中含有yield的时候,python会认为它是一个生成器,因此调用函数时,会返回一个生成器对象。
3. 生成器的使用
3.1 yield的作用
yield的作用:像return一样返回一个值,然后将程序的指针停在此处,下次调用时,将从指针处继续执行。
def func():
for i in range(10):
yield i
f = func()
print(next(f)) # 0
print(next(f)) # 1
print(next(f)) # 2
看上述代码,每次通过next调用生成器对象时,都会继续执行for循环,因此得到的最终结果是0 1 2
。
但是如果使用return的话
def func():
for i in range(10):
return i
f = func()
print(f) # 0
print(f) # 0
print(f) # 0
每次调用函数都会从开始执行,因此返回值i会不停的被覆盖成0。
yield和return的异同:
同:都会返回一个值
异:yield会暂停函数,下次调用可从暂停处继续;而return则是直接结束函数,下次调用从头开始。
3.2 调用生成器的两种方法
3.2.1 next(生成器对象)
在迭代器中,介绍过next()
函数,他会调用迭代器中的__next__
方法,从而进行一次值的获取。而生成器是一种特殊的迭代器,就可以理解为生成器就是迭代器。因此,生成器也可以使用next()
函数进行调用。
这里重申一下next的语法:
next(迭代器对象(生成器对象))
值的注意的是,生成器返回的值是一个生成器对象,因此无法像普通函数那样调用生成器;只能使用next()
函数进行调用。因此使用2.2中的生成器的方法如下
def func():
for i in range(10):
yield i
f = func()
print(next(f)) # 0
print(next(f)) # 1
print(next(f)) # 2
在使用next()
调用生成器的时候,程序会记住yield的断点位置,每次都能够从断点处继续执行。
3.2.2 生成器对象.send(value)
上面介绍了通过next()
函数调用生成器,其实也可以通过.send()
调用。
send()可以完成对生成器传入值的操作,next(x)其实就等于x.send(None)
比如:
def func():
for i in range(10):
m = yield i
print(m)
f = func()
print(next(f))
print(f.send('哈哈'))
print(f.send('呵呵'))
输出
0
哈哈
1
呵呵
2
注意:在首次调用生成器对象的时候,要使用next()或.send(None);如果使用send传入其他参数则程序会报错。
def func():
for i in range(10):
m = yield i
print(m)
f = func()
f.send('11')
报错
TypeError: can't send non-None value to a just-started generator
4. 生成器和迭代器的异同
同:都存储了生成一组数据的方法,节省存储空间
异:生成器可以做到对程序的暂停,且在暂停后可以自动保存数据,下次继续执行时,数据不会重置;而迭代器不能暂停程序的执行,运行过程中数据的保存需要靠自己来实现。