Python 生成器
生成器
1. 什么是生成器
生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值。
2 创建生成器
生成器可以通过生成器表达式和生成器函数获取到
生成器表达式
创建生成器对象和创建列表生成式特别像
# 创建列表生成式
>>> list_num = [x for x in range(10)]
>>> list_num
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 生成器
>>> glist_num = (x for x in range(10)) # 只需要把中括号换成小括号就成了生成器
>>> glist_num
<generator object <genexpr> at 0x7fc3d7375830>
>>> glist_num.__next__()
0
>>> glist_num.__next__()
1
>>> next(glist_num)
2
>>> next(glist_num)
3
# 生成器表达式内部的代码只有在迭代取值的时候才会执行
使用next()
和使用__next__()
一样
生成器函数
生成器函数指的是函数体中包含yield
关键字的函数
定义生成器函数和定义普通函数一样。
# 1 生成器函数
>>> def my_func():
print("Hello")
yield
>>> my_func()
<generator object my_func at 0x7fc3d6c70e08>
>>> res = my_func()
>>> res
<generator object my_func at 0x7fc3d6c70e60>
>>> next(res)
Hello
>>>
>>> next(res)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# 生成器函数(yield有返回值)
def my_func():
print("Hello")
yield 1
res = my_func()
r = res.__next__() # 会执行 print("Hello")
print(r) # r为yield的返回值
# 执行结果:
Hello
1
# 生成器函数(yield多个返回值)
def my_func():
print("Hello")
yield 1,2
res = my_func()
r = res.__next__()
print(r)
# 执行结果:
Hello
(1, 2)
#函数中只有一个yield所以只能执行一次__next__()方法
def my_func():
print("Hello")
yield 1,2
res = my_func()
print(res.__next__())
print(res.__next__()) # 调用两次就会报错
#执行结果:
Hello
(1, 2)
Traceback (most recent call last):
File "b.py", line 8, in <module>
print(res.__next__())
StopIteration
# 有多个yield
def my_func():
print("Hello")
yield 1,2
print("world")
yield 'a','b'
res = my_func()
print(res.__next__()) # 每执行一个__next__代码往下运行到yield停止 返回后面的数据
print(res.__next__()) # 每执行一个__next__代码往下运行到yield停止 返回后面的数据
注意:当函数体内含有yield
关键字 那么在第一次调用函数的时候,并不会执行函数体代码,而是将函数变成了生成器(迭代器).
每执行一个__next__
代码往下运行到yield停止 返回后面的数据.
yield
不但能返回值,而且还能给它传值
yield
传值
使用send
给yield
传值
示例:
def my_define(name):
print("%s is doing work" % name)
while True:
play = yield
print("%s is do %s" %(name, play))
res = my_define("Hans")
res.__next__()
res.__next__()
# 执行结果:
Hans is doing work
Hans is doing None
# 给yield传值:
def my_define(name):
print("%s is doing work" % name)
while True:
play = yield
print("%s is do %s" %(name, play))
res = my_define("Hans")
res.__next__()
res.__next__()
# 给yield传两个值:write和coding
res.send("write")
res.send("coding")
# 执行结果:
Hans is doing work
Hans is do None
Hans is do write
Hans is do coding
3 生成器练习
模拟range功能
# 代码
def my_range(start, stop=None, step = 1):
if not stop:
stop = start
start = 0
while start < stop:
yield start
start += step
print("一个参数")
for i in my_range(3):
print(i)
print("两个参数")
for i in my_range(1,3):
print(i)
print("三个参数")
for i in my_range(1, 10, 2):
print(i)
# 执行结果:
一个参数
0
1
2
两个参数
1
2
三个参数
1
3
5
7
9
求和(面试题)
# 代码:
def add(n, i):
return n + i
def test():
for i in range(4):
yield i
g = test()
for n in [1, 10]:
g = (add(n, i) for i in g)
res = list(g)
print(res)
#从下面的结果中选择一个:
#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23]
#D. res=[21,22,23,24]
# 解析:
def add(n, i):
return n + i
# 调用之前是函数 调用之后是生成器
def test():
for i in range(4):
yield i
g = test() # 初始化生成器对象
for n in [1, 10]:
g = (add(n, i) for i in g)
"""
第一次for循环
g = (add(n, i) for i in g)
第二次for循环
g = (add(10, i) for i in (add(10, i) for i in g))
"""
res = list(g)
print(res)
#执行结果为:[20,21,22,23], 答案选C
#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23]
#D. res=[21,22,23,24]
4 yield和return的区别
yield
- 可以返回值(支持多个,并且组织成元组)
- 函数体代码遇到yield不会结束而是阻塞
- yield可以将函数变成生成器 并且还支持外界传值
return
- 可以返回值(支持多个并且组织成元组)
- 函数体代码遇到return直接结束
5 生成器和迭代器总结
迭代器对象 生成器对象 我们都可以看成是"工厂",只有当我们所要数据的时候工厂才会加工出"数据"
主要目的就是节省空间