Python yield 使用浅析

本文介绍了Python中yield的作用,带有yield的函数会被解释器视为generator,调用时返回iterable对象。在for循环中,每次执行到yield就返回迭代值,下次从下条语句继续。使用yield可让函数获得迭代能力,代码更简洁,执行流程更清晰,还举例说明了在文件读取中的应用。

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

摘自菜鸟教程

简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class Fab(object): 

    def __init__(self, max): 
        self.max = max 
        self.n, self.a, self.b = 0, 0, 1 

    def __iter__(self): 
        return self 

    def next(self): 
        if self.n < self.max: 
            r = self.b 
            self.a, self.b = self.b, self.a + self.b 
            self.n = self.n + 1 
            return r 
        raise StopIteration()

for n in Fab(5): 
    print n

又要获得 iterable 的效果,yield 就派上用场了
仅仅把 print b 改为了 yield b,就在保持简洁性的同时获得了 iterable 的效果。

#!/usr/bin/python
# -*- coding: UTF-8 -*-

def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        yield b      # 使用 yield
        # print b 
        a, b = b, a + b 
        n = n + 1

for n in fab(5): 
    print n

yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。

我们可以得出以下结论:

一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值

yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。

另一个例子
另一个 yield 的例子来源于文件读取。如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取

def read_file(fpath): 
    BLOCK_SIZE = 1024 
    with open(fpath, 'rb') as f: 
        while True: 
            block = f.read(BLOCK_SIZE) 
            if block: 
                yield block 
            else: 
                return
<think>嗯,用户想了解Python中的yield关键字及其用法和工作原理。我需要根据提供的引用资料来整理回答。首先,yield在函数中使用,可以将函数变成生成器。生成器每次调用时执行到yield返回数据,下次继续从yield之后执行。根据引用2,yield相当于一个return,但函数会记住状态,下次从yield后面继续执行。比如在truncation函数中,每次yield返回列表的一部分,每次调用next时继续循环。这应该说明生成器的执行流程。引用3提到yield将函数变为迭代器,每次迭代返回数据,下次接着执行。可能需要用例子说明,比如生成斐波那契数列,或者全排列,如引用4中的例子。全排列生成器用递归和yield来逐步产生结果,这样更节省内存。引用5说明yield的工作流程,函数暂停,下次继续执行。比如在getSeq函数中,每次返回index后暂停,下次继续循环。这可能要结合代码示例解释。 用户可能需要了解基本用法、执行流程、与return的区别、应用场景。需要分点回答,结构清晰。例如,先解释生成器概念,再说明yield如何工作,然后对比普通函数,最后给出应用场景和例子。 要注意引用中的例子,比如引用2中的truncation函数,每次yield返回列表的一部分,说明生成器如何分段处理数据,节省内存。引用4的全排列例子展示递归中使用yield,生成大量结果而不占用过多内存。另外,用户可能想知道为什么使用yield而不是返回列表,应该提到内存效率和惰性计算的优点。比如处理大数据时,生成器逐个产生结果,避免一次性加载所有数据到内存。可能还需要提到生成器的两种创建方式:函数带yield,或者生成器表达式。但用户问题可能更关注函数中的yield。需要确保回答覆盖yield的基本机制、执行过程、优势,以及实际应用例子。可能最后生成相关问题,比如yield和return的区别,生成器的应用场景,如何实现协程等。</think>### Pythonyield关键字的用法与工作原理 #### 1. **基本概念** `yield`是Python中用于定义生成器(Generator)的关键字。当一个函数包含`yield`语句时,该函数会变成一个生成器,**每次调用时返回一个值并暂停执行**,下次调用时从暂停位置继续执行[^2][^3]。 --- #### 2. **执行流程** - **初始化**:调用生成器函数时,返回一个生成器对象,但函数内部代码**不会立即执行**。 - **首次触发**:通过`next()`或`for`循环触发时,函数从开头执行到第一个`yield`语句,返回数据并暂停。 - **后续触发**:再次调用`next()`时,函数从上次暂停的`yield`之后继续执行,直到遇到下一个`yield`[^2][^5]。 **示例代码**: ```python def simple_generator(): yield "第一次暂停" yield "第二次暂停" gen = simple_generator() print(next(gen)) # 输出:第一次暂停 print(next(gen)) # 输出:第二次暂停 ``` --- #### 3. **与普通函数的区别** | 特性 | 普通函数 | 生成器函数 | |--------------------|----------------------------|------------------------------| | 返回值 | 通过`return`返回单一结果 | 通过`yield`多次返回值 | | 状态保留 | 每次调用重新初始化 | 保留上次执行状态 | | 内存占用 | 一次性处理所有数据 | 惰性计算,按需生成数据 | --- #### 4. **核心应用场景** 1. **处理大型数据集** 生成器逐项生成数据,避免一次性加载到内存。例如读取大文件: ```python def read_large_file(file_path): with open(file_path, 'r') as f: for line in f: yield line.strip() ``` 2. **无限序列生成** 如斐波那契数列: ```python def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b ``` 3. **协程与异步编程** `yield`可用于实现简单的协程调度[^5]。 --- #### 5. **进阶用法示例** - **递归生成器**:生成全排列(引用[^4]): ```python def perm(items, n=None): if n is None: n = len(items) for i in range(len(items)): v = items[i:i+1] if n == 1: yield v else: rest = items[:i] + items[i+1:] for p in perm(rest, n-1): yield v + p ``` - **状态管理**:分段处理数据(引用[^2]): ```python def truncation(): trunc_list = list(range(100)) for i in range(len(trunc_list)//5): yield trunc_list[i*5 : (i+1)*5] ``` --- #### 6. **注意事项** - 生成器**只能遍历一次**,遍历结束后需重新创建。 - 可通过`send()`方法向生成器发送数据,实现双向通信[^5]。 - 使用`yield from`可简化嵌套生成器的调用。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值