Python-生成器
Posted JerryZao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python-生成器相关的知识,希望对你有一定的参考价值。
1、生成器***
之前在列表解析中已经介绍了 生成器表达式。这里介绍生成器函数。
生成器:generator
生成器指的是生成器对象,可以有生成器表达式得到,可以使用yield 关键字得到一个生成器函数,调用这个函数就得到一个生成器对象。
生成器函数:
函数体重包含yield语句 的函数,返回生成器对象
生成器对象,是一个可迭代对象,是一个迭代器。
生成器对象,是惰性求值的
举例 1:
1 def fn(): 2 for i in range(5): 3 yield i 4 5 print(type(fn())) # <class ‘generator‘> 6 7 for x in fn(): 8 print(x) 9 print(‘-------------------------‘) 10 for x in fn():# 这个第二次还能继续循环迭代是因为第二次循环又重新调用了fn(),作为一个生成器对象 11 print(x) 12 print(‘-------------------------‘) 13 14 g = fn() # 15 16 for x in g: 17 print(x) 18 print(‘-------------------------‘) 19 for x in g: # 还是从之前的生成器中继续迭代 20 print(x)
举例2:
1 def fen(): 2 print(‘line 1‘) 3 yield 1 4 print(‘line 2‘) 5 yield 2 6 print(‘line 3‘) 7 for i in range(5): 8 print(i) 9 return 3 10 g = fen() 11 12 count = 0 13 for x in g: 14 count += 1 15 print(x,count) 16 17 # line 1 18 # 1 1 19 # line 2 20 # 2 2 21 # line 3 22 # 0 23 # 1 24 # 2 25 # 3 26 # 4
总结:
-
-
- 生成器函数中,使用过个yield 与,执行一次后会暂停执行,把yield表达式的值返回
- 再次执行会执行到下一个yield语句
- return 语句 依然可以终止函数运行,但return 语句的返回值不能被获取到
- return 会导致无法继续去哦去下一个值,抛出StopIteration 异常
- 如果 函数没有显示的return 语句,如果生成器函数执行到结尾一样会抛出StopIteartion异常
-
生成器函数总结:
- 包含yield 语句的生成器函数生成 生成器对象的时候,生成器函数的函数体不会立即执行
- next(generator) 会从函数的当前位置向后执行到之后碰到拿到的第一个yield语句,会弹出,并暂停函数执行。
- 再次调用next函数,和上一条处理过程一样
- 没有多余的yield 语句能被执行,继续调用next函数,会抛出StopIteration
举例 3:
1 def counter(): 2 i = 0 3 while True: 4 i += 1 5 yield i 6 def inc(c): 7 return next(c) 8 9 c = counter() #每次都要外部传参 10 print(inc(c)) # 1 11 print(inc(c)) # 2 12 13 def counter(): 14 i = 0 15 while True: 16 i += 1 17 yield i 18 def inc(): 19 c = counter() # 每次都重新调用,所以每次都拿到同样的值 20 return next(c) 21 22 print(inc()) # 1 23 print(inc()) # 1 24 print(inc()) # 1
举例 4:
1 ‘‘‘ 2 上面的优化: 3 1、不需要外部传参,感觉 inc() 像一个生成器对象 4 2、内层函数作为一个生成器函数,并且在同级进行调用,作为生成器对象 5 3、外层函数将生成器对象地址返回给 外层函数 6 4、全局调用外层函数,就相当于是一个生成器对象。 7 ‘‘‘ 8 def inc(): 9 def countes(): 10 i = 0 11 while True: 12 i += 1 13 yield i 14 c = countes() 15 return lambda :next(c) 16 17 foo = inc() 18 print((foo())) # 1 19 print((foo())) # 2
举例 5:
1 def fib(n): 2 a = 0 3 b = 1 4 for i in range(n): 5 a, b = b, a + b 6 yield a 7 8 foo = fib(5) 9 # for _ in range(5): 10 # print(next(foo)) 11 12 for i in foo: 13 print(i) 14 15 16 17 def fib(): 18 x = 0 19 y = 1 20 while True: 21 yield y 22 x, y = y, x + y 23 24 foo = fib() 25 for _ in range(5): 26 print(next(foo)) 27 28 print(‘-------‘) 29 30 for _ in range(10): 31 # next(foo) 32 print(next(foo),‘--‘) 33 34 # 1 35 # 1 36 # 2 37 # 3 38 # 5 39 # ------- 40 # 8 -- 41 # 13 -- 42 # 21 -- 43 # 34 -- 44 # 55 -- 45 # 89 -- 46 # 144 -- 47 # 233 -- 48 # 377 -- 49 # 610 --
生成器应用:yield引出的(遇到yield,会让出控制权)
-
- 协程Co-routine
- 生成器的高级用法
- 比进程、线程轻量级
- 是在用户空间调度函数的一种实现
- Python3 asyncIO 就是协程实现,已经加入标准库
- Python3.5 使用async,await关键字直接原生支持协程
- 协程调度器实现思路:
- 有两个生成器A,B
- next(A) 后,A 执行到了yield 语句暂停,然后去执行next(B),B执行到yield 语句也暂停,然后再次调用next(A),再调用next(B),周而复始,就实现了调度的效果,
-
1 # 在用户空间就做了调度 2 def a(): 3 for i in range(5): 4 yield i 5 6 def b(): 7 for i in range(5): 8 yield i 9 10 a = a() 11 b = b() 12 13 for i in range(10): 14 if i % 2 == 0: 15 print(next(a), ‘a‘) 16 else: 17 print(next(b), ‘b‘) 18 # 0 a 19 # 0 b 20 # 1 a 21 # 1 b 22 # 2 a 23 # 2 b 24 # 3 a 25 # 3 b 26 # 4 a 27 # 4 b
- 可以引入调度的策略来实现切换的方式
- 有两个生成器A,B
- 协程是一种非抢占式调度
- 协程效率是比较高的
- 协程Co-routine
yield from:
1 def inc(): 2 for x in range(100): 3 yield x 4 5 || 6 || 7 8 def inc(): 9 yield from range(100)
yield from 是Python3.3 出现的新的语法
yield from iteable 是 for item in iterable : yield item 形式的语法糖
从 可迭代 对象中一个个拿 元素
1 def counter(n): 2 for x in range(n): 3 yield x 4 5 def inc(n): 6 yield from counter(n) 7 8 foo = inc(10) 9 10 print(next(foo)) # 0 11 print(next(foo)) # 1
以上是关于Python-生成器的主要内容,如果未能解决你的问题,请参考以下文章