看如下程序:

# 定义一个生成斐波那契数列的生成器函数
def fibonacci():
    a, b = 0, 1
    while True: # 1、死循环?
        yield a
        a, b = b, a + b

# 调用生成器函数 → 得到生成器对象(而非直接返回数列值)
gen = fibonacci()
print(gen)  # 2、输出是什么?

程序中我打了两个问号:1、死循环?2、输出是什么?
对于第2个问号(2、输出是什么?),一运行便知:<generator object fibonacci at 0x0000017FF0903850>(地址可能不同)。即:这里直接打印 gen 就会显示生成器对象的信息,而不是斐波那契数列的具体值——这是生成器“惰性计算”的特性决定的(不会提前生成数据,而是生成生成器的对象,然后由生成器的对象按需生成数据)。

为回答第一个问号(),我们比较returnyield两关键字。
在 Python 中,y ieldreturn 都是用于在函数中返回值的关键字,但它们的行为和适用场景有本质区别,核心差异在于是否终止函数执行以及返回值的方式

1. 基本功能与函数类型

  • return:用于普通函数,作用是返回一个值并立即终止函数,函数的局部状态(如变量、执行位置)会被销毁。
  • yield:用于生成器函数(包含 yield 的函数),作用是返回一个值并暂停函数执行,同时保存函数当前的状态(局部变量、执行位置等),下次调用时从暂停处继续执行。

2. 执行流程对比

(1)return 的执行流程
def return_func():
    print("步骤1")
    return 1  # 返回值并终止函数
    print("步骤2")  # 永远不会执行

result = return_func()
print(result)  # 输出:步骤1 → 1
  • 函数执行到 return 时,立即返回值并结束,后续代码不再执行。
  • 再次调用函数时,会重新从头开始执行。
(2)yield 的执行流程
def yield_func():
    print("步骤1")
    yield 1  # 返回值并暂停
    print("步骤2")
    yield 2  # 返回值并暂停
    print("步骤3")

# 调用生成器函数,返回生成器对象(不执行函数体)
gen = yield_func()

# 第一次触发:执行到第一个yield,返回1并暂停
print(next(gen))  # 输出:步骤1 → 1

# 第二次触发:从暂停处继续,执行到第二个yield,返回2并暂停
print(next(gen))  # 输出:步骤2 → 2

# 第三次触发:从暂停处继续,执行完剩余代码,无更多yield,抛出StopIteration
print(next(gen))  # 输出:步骤3 → 报错(StopIteration)
  • 生成器函数被调用时,不会立即执行,而是返回一个生成器对象。
  • 每次通过 next(生成器) 或迭代触发时,函数执行到下一个 yield 处暂停,返回值并保存状态。
  • 直到函数执行完毕(无更多 yield),再次调用会抛出 StopIteration 异常。

3. 返回结果的差异

  • return:直接返回一个具体的值(或 None),调用函数后立即得到结果。

    def add(a, b):
        return a + b
    
    print(add(2, 3))  # 直接得到结果:5
    
  • yield:返回的是一个生成器对象(一种特殊的迭代器),而非直接返回值。需要通过迭代(如 for 循环)或 next() 方法逐步获取值。

    def generate_numbers(n):
        for i in range(n):
            yield i
    
    # 生成器对象本身不是结果,需要迭代获取
    gen = generate_numbers(3)
    print(next(gen))  # 0
    print(next(gen))  # 1
    

4. 内存与适用场景

  • return:适合返回有限且少量的数据,因为它会一次性将所有结果加载到内存中(例如返回一个列表)。

    def get_list(n):
        return [i for i in range(n)]  # 一次性生成所有数据,占用内存
    
    print(get_list(5))  # [0, 1, 2, 3, 4]
    
  • yield:适合返回大量数据、无限序列,或需要按需生成数据的场景(节省内存)。因为它不会一次性生成所有数据,而是“按需产出”。

    def infinite_numbers():
        i = 0
        while True:
            yield i  # 无限生成数据,不占用大量内存
            i += 1
    
    # 取前5个值,无需生成所有数据
    gen = infinite_numbers()
    for _ in range(5):
        print(next(gen), end=" ")  # 0 1 2 3 4
    

这样功能就回答了文章开头提出的第一个问题(1、死循环?):它并是不去执行死循环,而是根据需要执行“有限”步骤。

5. 其他关键区别

  • 在生成器中使用 return:生成器函数中也可以用 return,但它不会返回值(会被忽略),而是直接触发 StopIteration 异常,终止生成器。

    def gen_with_return():
        yield 1
        return  # 触发StopIteration
        yield 2  # 不会执行
    
    gen = gen_with_return()
    print(next(gen))  # 1
    print(next(gen))  # 报错:StopIteration
    
  • yield 不能在普通函数中使用:如果普通函数(无 yield)中使用 yield,会报错;反之,生成器函数中可以没有 return(默认执行到末尾触发 StopIteration)。

特性 return yield
函数类型 普通函数 生成器函数
执行效果 返回值并终止函数 返回值并暂停函数(保存状态)
返回结果 直接返回具体值 返回生成器对象(需迭代取值)
内存占用 一次性加载所有结果,占用内存较多 按需生成,内存占用低
适用场景 返回有限/少量数据,立即获取结果 大量数据、无限序列、按需生成

简单说:return 是“一去不返”(终止函数),yield 是“藕断丝连”(暂停并可恢复)。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐