python 生成器函数
生成器generator
- 生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这个函数得到一个生成器对象
生成器函数
- 函数体中包含yield语句的函数,返回生成器对象
- 生成器对象,是一个可迭代对象,是一个迭代器
- 生成器对象,是延迟计算,惰性求值
举例:
def inc(): for i in range(5): yield i print(type(inc)) #函数类型 #<class 'function'> print(type(inc())) #生成器类型 #<class 'generator'> x = inc() print(type(x)) print(type(next(x))) for m in x : print(m,'*') for m in x : print(m, '**') """ #执行结果 <class 'function'> <class 'generator'> <class 'generator'> <class 'int'> 1 * 2 * 3 * 4 * """
y = (i for i in range(5)) print(type(y)) print(next(y)) print(next(y)) #执行结果 <class 'generator'> 0 1
- 普通函数调用fn(),函数会立即执行完毕,但是生成器函数可以使用next函数多次执行。
- 生成器函数等价于生成器表达式,只不过生成器函数可以更加的复杂
def gen(): print('line 1') yield 1 print('line 2') yield 2 print('line 3') yield 3 next(gen()) next(gen()) g = gen() print(next(g)) print(next(g)) print(next(g)) print(next(g,'End'))
- 在生成器函数中,使用多个yield语句,执行一次后会暂停执行,把yield表达式的值返回
- 再次执行会执行到下一个yield语句
- return 语句依然可以终止函数运行,但return语句的返回值不能被获取
- return会导致无法继续获取下一个值,抛出异常StopIteration
- 如果函数没有显示的return语句,如果生成器函数执行到结尾,一样会抛出异常StopIteration异常
生成器函数总结:
- 包含yield语句的生成器函数生成生成器对象的时候,生成器函数的函数体不会立即执行
- next(generator)会从函数的当前位置后执行到之后碰到的第一个yield语句,会弹出值,并暂停函数执行
- 再次调用next函数,和上一条一样的处理过程
- 没有多余的yield语句能被执行,继续调用next函数,会抛出异常StopIteration异常
计数器:
def inc(): def counter(): i=0 while True: i += 1 yield i c = counter() return lambda : next(c) foo = inc() print(foo()) print(foo()) print(foo())
- lambda 表达式是匿名函数
- return 返回一个匿名函数
生成器处理递归问题:
def fib(): x = 0 y = 1 while True: yield y x,y=y,x+y foo = fib() # for _ in range(5): # print(next(foo)) # for _ in range(100): # print(next(foo)) print(next(foo))
协程coroutine
- 生成器的高级用法
- 比进程、线程轻量级
- 是用户空间调度函数的一种实现
- Python3 asyncio 就是协程实现,已经加入到标准库
- Python3.5 async await 关键字直接原生支持协程
- 协程调度器实现思路:
- 有2个生成器A、B
- next(a)后,A执行到了yield语句暂停,然后去执行next(B),B执行到yield语句也暂停,然后再次调用next(A),再调用next(B)在,周而复始,就实现了调度的效果
- 可以引入调度的策略来实现切换的方式
- 协程是一种非抢占式调度
yield from
- yield from是Python 3.3出现的新的语法
- yield from iterable 是 for item in iterable: yield item 形式的语法糖
- 从可迭代对象中一个一个拿元素
def conuter(n): for x in range(n): yield x def inc(n): yield from conuter(n) foo = inc(10) print(next(foo)) print(next(foo)) print(next(foo))
碎片化时间学习和你一起终身学习