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))

 

posted @ 2019-08-16 17:03  大胖猴  阅读(1095)  评论(0编辑  收藏  举报