Python 生成器:不是所有能遍历的对象都是生成器

这篇文章将从头到尾围绕一个核心问题展开:

在 Python 中,有哪些函数或模块中的函数是用生成器实现的?它们如何体现“生成器”的特点?

我们将明确区分:

  • ✅ 真正使用了 yield 或生成器表达式(generator expression)的函数;

  • ❌ 不包括普通的可迭代对象、迭代器对象(如 map, filter, zip, range 等);


一、先来回顾:生成器的本质是什么?

✅ 定义:

生成器是一种特殊的函数,它通过 yield 返回值,并能在多次调用之间保持状态。

你可以通过两种方式创建生成器:

  1. 生成器函数:包含 yield 的函数;

  2. 生成器表达式:类似列表推导式,但使用 () 而非 []

# 生成器函数
def my_gen():
    yield 1
    yield 2
    yield 3

# 生成器表达式
gen = (x * x for x in range(5))

📌 这两个才是真正的“生成器对象”。


二、哪些 Python 内置/标准库函数是用生成器实现的?

虽然 Python 很多函数返回的是“惰性求值的迭代器”,但真正以生成器方式实现的函数并不多。以下是几个典型例子:


✅ 示例1:os.walk()

import os

for root, dirs, files in os.walk('.'):
    print(root)
  • os.walk() 是一个生成器函数,它递归地遍历目录树;

  • 每次调用 next(),返回下一级目录的信息;

  • 它内部使用了 yield 来逐层生成结果。

🔍 查看源码你会发现它大致结构如下:

def walk(top):
    yield (top, list_of_dirs, list_of_files)
    for dir in list_of_dirs:
        yield from walk(os.path.join(top, dir))

📌 所以它是真正的生成器!


✅ 示例2:tokenize.generate_tokens()

import tokenize
from io import BytesIO

code = b"x = 1 + 2"
tokens = tokenize.generate_tokens(BytesIO(code).readline)

for token in tokens:
    print(token)
  • generate_tokens() 是一个生成器函数,用于逐个读取 Python 源代码中的 token;

  • 它通过 yield 返回每个 token;

  • 非常适合处理大文件或流式输入。


✅ 示例3:itertools 中部分函数的实现依赖生成器

虽然 itertools 函数返回的是迭代器对象,但很多底层实现是用生成器完成的。

比如 itertools.count()itertools.cycle()itertools.repeat() 等函数,在 CPython 实现中是用生成器逻辑模拟的。

虽然从用户角度看它们不是生成器对象,但从实现角度看,它们的行为和生成器一致。


三、常见误解澄清:这些不是生成器!

函数类型是否是生成器
map()迭代器
filter()迭代器
zip()迭代器
range()序列类型
open() 行迭代文件迭代器
列表推导式 [x*x for x in ...]列表
生成器表达式 (x*x for x in ...)生成器表达式

📌 特别注意:

  • 生成器表达式虽然名字里有“生成器”,但它是一个表达式,最终产生的是一个生成器对象;

  • map, filter 等只是惰性迭代器,不是生成器对象


四、实战技巧:如何判断一个函数是否是生成器?

你可以用以下方法检查一个函数是否是生成器函数:

✅ 方法1:查看函数是否是 types.GeneratorType

import types

def my_gen():
    yield 1

print(isinstance(my_gen(), types.GeneratorType))  # True

✅ 方法2:检查函数是否含有 yield

def is_generator_function(func):
    return func.__code__.co_flags & 0x20  # CO_GENERATOR 标志位

def my_gen():
    yield 1

print(is_generator_function(my_gen))  # True

五、一句话总结

生成器函数必须包含 yield,且调用后返回的是一个生成器对象。

在 Python 标准库中,真正用生成器实现的函数不多,但功能强大,如 os.walk()tokenize.generate_tokens()


📌 推荐阅读资源

  • 书籍:
    • 《流畅的 Python》(Luciano Ramalho)

    • 《Python Cookbook》

  • 工具:
  • 实战项目:
    • 实现一个自己的 walk() 函数;

    • 用生成器构建日志分析系统;

    • 使用生成器优化数据流水线处理流程;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之之为知知

给之之买个冰淇淋吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值