python语法——yield 使用解析

本文深入解析Python中生成器(generator)的概念与yield关键字的使用,通过实例展示生成器的工作原理,包括其与传统函数的区别,以及如何利用生成器实现高效的数据处理。

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

带有 yield 的函数是一种特殊函数,其返回的函数值是一个 generator(生成器)。

yield 示例

举例说明 yield 的用法:生成一个自增平方序列:

def square(n):
    for i in range(n):
        yield i*i # 将 i*i 放入到返回值的生成器序列中

if __name__=="__main__":
    gen = square(5)
    print(type(gen)) # 打印出 gen 的类型
    while True:
        print(gen.__next__())

结果输出:

<class 'generator'>
0
1
4
9
16
Traceback (most recent call last):
StopIteration

可以看出,虽然 square 这个函数没有 return 关键字,但实际上 square(5) 是一个生成器,里面数据的顺序是按照函数中 yield 的顺序来存放的。生成器能够迭代的关键是它有一个 __next__() 方法,工作原理就是通过重复调用这个方法,直到捕获一个异常。

区别:python3 中的生成器的迭代函数为 g.__next__()next(g),python2 为 g.next()

yield原理解释

可以将 yield 理解为特殊的 return,只不过可以 yield 很多次,然后使用 __next__() 方法来读取 yield 过的这些数据。

如果一直调用 __next__ 方法,当执行到没有可迭代的值后,程序就会报错:StopIteration,所以一般不会手动的调用__next__方法,而是使用for循环:

for i in gen:
    print(i)

生成器迭代一次(通过 nextfor 等)遇到 yield 时就返回 yield 后面的值。

重点是:下一次迭代时,从上一次迭代遇到的 yield 后面的代码开始执行。比如我们多加几个输出语句:

def square(n):
    for i in range(n):
        print(f'this is {i}')
        yield i*i # 将 i*i 放入到返回值的生成器序列中
        print(f'result is {i*i}')

if __name__=="__main__":
    gen = square(5)
    count = 0
    for i in gen:
        print(f'result:{i}')
        print(f'count:{count}\n')
        count += 1

结果为:

this is 0
result:0
count:0

result is 0
this is 1
result:1
count:1

result is 1
this is 2
result:4
count:2

result is 4
this is 3
result:9
count:3

result is 9
this is 4
result:16
count:4

result is 16

可以看到,第一次迭代和最后一次迭代的输出结果比较特殊。

第一次迭代时,生成器开始按照 square 内部代码运行,直到遇到 yield 为止,然后退出 square 函数,且返回 0

中间的几次迭代,生成器按照 square 内部代码运行,但是是从上一次 yield后一行print(f'result is {i*i}') 这一行开始执行,直到遇到 yield 为止。

最后一次只输出了 result is 16 ,这是为什么呢?

这是因为,最后一次迭代时,还是从 print(f'result is {i*i}') 开始执行,但是尝试返回到循环的开头时,发现已经不满足循环条件,因此直接退出,也不会再有 yield 的结果。

yield 中 return 的作用

既然带 yield 的函数不需要 return,那么如果强制加上 return 会如何?

这时,return 会导致提前结束生成器的迭代。

比如在程序多加一行 return

def square(n):
    for i in range(n):
        print(f'this is {i}')
        yield i*i 
        print(f'result is {i*i}')
        return i  # 多加一行return  

if __name__=="__main__":
    gen = square(5)
    count = 0
    for i in gen:
        print(f'result:{i}')
        print(f'count:{count}\n')
        count += 1

结果为:

this is 0
result:0
count:0

result is 0

第一次迭代是正常的,第二次迭代时,从 print(f'result is {i*i}') 开始运行,但是下一行 return 了,因此生成器认为整个迭代已经结束。这时候如果再调用 __next__() ,就会报错:StopIteration

区别:python3 中 yield 函数内 return + 某个值,作用与单独的 return 相同;但是 python2 只允许单独的 return,如果后面加某个值,会报错:SyntaxError: ‘return’ with argument inside generator

备注

  • 如一个函数中出现多个 yield__next__() 会停止在下一个 yield 前。
  • 使用生成器的好处:实时生成数据,不全存在内存中。
  • 使用生成器的坏处:只可以读取它一次,因为用的时候才生成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值