Python生成器
1. 生成器的概念
生成器是一类特殊的迭代器,它不需要再迭代器一样写
__iter__()和__next__()
方法了, 使用更加方便,它依然可以使用next函数和for循环取值
2. 创建生成器两种方法
-
- 第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
my_list = [i * 2 for i in range(5)] print(my_list) # 创建生成器 my_generator = (i * 2 for i in range(5)) print(my_generator) # next获取生成器下一个值 # value = next(my_generator) # # print(value) for value in my_generator: print(value) |
执行结果:
1 2 3 4 5 6 7 8 |
[0, 2, 4, 6, 8] <generator object <genexpr> at 0x101367048> 0 2 4 6 8 |
-
- 在def函数里面看到有yield关键字那么就是生成器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
def fibonacci(num): a = 0 b = 1 # 记录生成fibonacci数字的下标 current_index = 0 print("--11---") while current_index < num: result = a a, b = b, a + b current_index += 1 print("--22---") # 代码执行到yield会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行 yield result print("--33---") fib = fibonacci(5) value = next(fib) print(value) value = next(fib) print(value) value = next(fib) print(value) # for value in fib: # print(value) |
在使用生成器实现的方式中,我们将原本在迭代器__next__
方法中实现的基本逻辑放到一个函数中来实现,但是将每次迭代返回数值的return换成了yield,此时新定义的函数便不再是函数,而是一个生成器了。
简单来说:只要在def中有yield关键字的 就称为 生成器
3.生成器使用return关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
def fibonacci(num): a = 0 b = 1 # 记录生成fibonacci数字的下标 current_index = 0 print("--11---") while current_index < num: result = a a, b = b, a + b current_index += 1 print("--22---") # 代码执行到yield会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行 yield result print("--33---") return "嘻嘻" fib = fibonacci(5) value = next(fib) print(value) # 提示: 生成器里面使用return关键字语法上没有问题,但是代码执行到return语句会停止迭代,抛出停止迭代异常 # 在python3里面可以使用return关键字,python2不支持 # return 和 yield的区别 # yield: 每次启动生成器都会返回一个值,多次启动可以返回多个值,也就是yield可以返回多个值 # return: 只能返回一次值,代码执行到return语句就停止迭代 try: value = next(fib) print(value) except StopIteration as e: # 获取return的返回值 print(e.value) |
提示:
- 生成器里面使用return关键字语法上没有问题,但是代码执行到return语句会停止迭代,抛出停止迭代异常
- 在python3里面可以使用return关键字,python2不支持
yield和return的对比
- 使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)
- 代码执行到yield会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行
- 每次启动生成器都会返回一个值,多次启动可以返回多个值,也就是yield可以返回多个值
- return只能返回一次值,代码执行到return语句就停止迭代,抛出停止迭代异常
4. 使用send方法启动生成器并传参
send方法启动生成器的时候可以传参数
1 2 3 4 5 6 7 8 |
In [10]: def gen(): ....: i = 0 ....: while i<5: ....: temp = yield i ....: print(temp) ....: i+=1 ....: |
执行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
In [43]: f = gen() In [44]: next(f) Out[44]: 0 In [45]: f.send('haha') haha Out[45]: 1 In [46]: next(f) None Out[46]: 2 In [47]: f.send('haha') haha Out[47]: 3 In [48]: |
注意:如果第一次启动生成器使用send方法,那么参数只能传入None,一般第一次启动生成器使用next函数
小结
- 生成器创建有两种方式,一般都使用yield关键字方法创建生成器
- yield特点是代码执行到yield会暂停,把结果返回出去,再次启动生成器在暂停的位置继续往下执行