一文了解Python生成器

188 阅读3分钟

Python生成器是什么?

Python生成器允许我们在需要时才生成值,而不是一次性创建所有值,这在处理大规模数据或者无限序列时尤为重要(其实就是Python比较占内存资源,处理不了大规模数据而设计的一种机制,数据按需生成)

生成器函数:yield关键字的魔法

生成器函数是定义生成器最直接的方式,它与普通函数的区别在于使用yield关键字而非return。当调用生成器函数时,它不会立即执行,而是返回一个生成器对象.

# 示例:生成斐波那契数列的生成器函数
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 使用生成器
fib_gen = fibonacci()
print(next(fib_gen))  # 输出: 0
print(next(fib_gen))  # 输出: 1
print(next(fib_gen))  # 输出: 1
print(next(fib_gen))  # 输出: 2

生成器函数的核心特性:

  • 执行yield时暂停,保存当前状态
  • 再次调用next()时从暂停处继续执行
  • 状态保存包括局部变量、执行位置

生成器表达式

生成器表达式提供了一种更加简洁的创建生成器的方式,语法类似列表推导式,使用圆括号而非方括号

# 示例:生成1到10的平方的生成器表达式
square_gen = (i ** 2 for i in range(1, 11))

# 遍历生成器
for num in square_gen:
    print(num, end=" ")  # 输出: 1 4 9 16 25 36 49 64 81 100

生成器表达式与列表推导式的区别

  • 生成器表达式是惰性求职,列表表达式是立即求职
  • 生成器表达式不存储所有元素,内存效率更高
  • 生成器表达式只能迭代一次,列表可以多次迭代

生成器的高级用法

  • 生成器作为协程 -生成器可以接受外部发送的值,通过send()方法实现,这使得生成器可以作为协程使用。
def echo():
    while True:
        value = yield
        print(f"收到值: {value}")

# 创建协程
coroutine = echo()
next(coroutine)  # 启动协程

# 发送值到协程
coroutine.send("Hello")  # 输出: 收到值: Hello
coroutine.send("World")  # 输出: 收到值: World
  • 生成器链 可以将多个生成器连接起来,形成生成器链,实现数据的流水线处理
def numbers():
    for i in range(1, 6):
        yield i

def squared(gen):
    for num in gen:
        yield num ** 2

def even_only(gen):
    for num in gen:
        if num % 2 == 0:
            yield num

# 连接生成器
num_gen = numbers()
square_gen = squared(num_gen)
even_gen = even_only(square_gen)

# 遍历结果
for num in even_gen:
    print(num)  # 输出: 4, 16

生成器的优势

  • 内存效率高:无需一次性创建所有数据,适合处理大数据集
  • 延迟计算:按需生成数据,提高程序响应速度
  • 无限处理:可以生成理论上无限的序列,如随机数生成
  • 流式处理:适合处理流式数据,如日志文件,网络数据