Python:生成器函数,yield from

本文详细介绍了Python中的生成器,包括生成器函数与普通函数的区别、yield与return的不同行为,以及如何使用生成器进行无限循环、处理递归问题。此外,还探讨了协程的概念,指出其比进程、线程更轻量级,并介绍了Python3的asyncio库对协程的支持。最后,重点讲解了Python3.3新增的`yield from`语法,它是简化迭代器元素传递的高效方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引入

生成器generator:生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这个函数得到一个生成器对象

生成器函数:

  • 函数体中包含yeild语句的函数,返回生成器对象
  • 生成器对象,是一个可迭代对象,是一个迭代器
  • 生成器对象,是延迟求值,惰性求值的

yield与return的比较

  • 遇到yield,函数就会让出此次操作,去执行函数体别的语句
  • return,直接打断函数的执行,返回结果

普通函数,生成器函数的比较

例子一: 单个yield,使用

def inc():
    for i in range(2):
        yield i
print(type(inc))
print(type(inc()))
x = inc()
print(type(x))
print(next(x))                #数值通过next()来调用
print(next(x))
print(next(x,"END"))          #取到最后没有元素,给个缺省值

结果:
<class 'function'>
<class 'generator'>
<class 'generator'>
0
1
END   
  • 普通函数调用使用fn(),函数会立即执行完毕,但是生成器函数可以使用next(),函数来多次执行

例子二:函数中使用多个yield
 

def gen():
    print('line 1')
    yield 1
    print('line 2')
    yield 2
    print('line 3')
    return 3
next(gen()) # line 1   
next(gen()) # line 1  重新调用了函数,所以会打印两次line 1
g = gen()
print(next(g))  # 答应line 1
print(next(g))  # 打印line 2
print(next(g))  # 报错StopIteration

结果:
line 1
line 1
line 1
1
line 2
2
line 3
StopIteration: 3
  • 生成器函数中,使用多个yield语句,执行一次后,会暂停使用,把yield表达式的值返回
  • 再次执行会执行到下一个yield语句
  • return语句依然可以终止函数运行,单return语句的返回值不能不能被获取到
  • return会导致无法继续获取下一个值,抛出Stoplteration异常
  • 如果函数没有显示的return语句,如果生成器函数执行到结尾,一样会抛出stopleteration

 生成器函数总结:

生成器函数:

  • 包含yield语句的生成器函数生成,生成器对象时候,生成器函数的函数的函数体不会立即执行
  • next(generator)会从函数的当前位置向后执行到之后碰到的第一个yield语句,会弹出值,并暂定函数执行
  • 再次调用next函数,和上一条一样的处理过程
  • 没有多余的yield语句能被执行,继续调用next函数,会抛出Stopleteration

生成器应用

应用于无限循环

 

def counter():
    i = 0
    while True:
        i += 1
        yield i
def inc(c):
    return next(c)
c = counter()
print(inc(c))
print(inc(c))
print(inc(c))

结果
1
2
3
  • counter() 函数负责生成数值,inc() 负责取值

 

计数器的应用

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


结果:
1
2
3
  • lambda表达式时匿名函数
  • return返回的时一个匿名函数

 

处理递归问题

def fib():
    x = 0
    y = 1
    while True:
        yield y
        x, y = y, x+y
foo = fib()
for _ in range(2):       #  循环取值
    print(next(foo))


for _ in range(2):       # 循环取值
    next(foo)
print(next(foo))        #  取第n个值

结果:


1
1
5


携程coroutine

  • 生成器的高级用法
  • 比进程、线程轻量级
  • 是在用户调度函数的一种实现
  • Python3 asyncio 就是协程实现,已经加入到标准库
  • Python3.5 使用async、await 关键字直接原生支持协程
  • 协程调度器实现思路
    • 有两个生成器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 interable : yield item 形式的语法

  • 从可迭代对象中一个个的拿元素
    def counter(n): # ࣿm֘ۨଙї֘
        for x in range(n):
            yield x
    def inc(n):
        yield from counter(n)
    foo = inc(10)
    print(next(foo))
    print(next(foo))
    
    结果:
    0
    1

     

 

举例:yield from
 

 
def inc():                                                def  inc():
    for x in range(1000):            #等价于                   yield from range(100)          
        yield x

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值