Python - 生成器:初学者温和入门指南

你好,有抱负的Python程序员!今天,我们将开始一段激动人心的旅程,深入了解Python生成器的世界。如果你之前从未听说过生成器,不用担心——我们将从头开始,逐步深入学习。在本教程结束时,你将能够像专业人士一样创建生成器!

Python - Generators

Python生成器是什么?

想象你正在阅读一本非常长的书。你不会一次性复印整本书(那样会浪费很多纸!),而是选择一次阅读一页。生成器在Python中的工作方式有点像这样!

生成器是一种特殊的函数,它允许我们随时间生成一系列值,而不是一次性计算所有值并将它们存储在内存中。它们就像魔法工厂,按需生成值。

为什么使用生成器?

  1. 内存效率:生成器对内存友好。它们不会一次性存储所有值在内存中。
  2. 性能:它们可以提升代码的性能,尤其是在处理大型数据集时。
  3. 简洁:生成器可以使你的代码更清晰、更易读。

让我们深入了解它们是如何工作的!

创建生成器

在Python中创建生成器主要有两种方法:

  1. 使用生成器函数
  2. 使用生成器表达式

生成器函数

生成器函数看起来就像一个普通函数,但使用的是yield关键字,而不是return。以下是一个简单示例:

def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1

# 使用我们的生成器
for number in count_up_to(5):
print(number)

输出:

1
2
3
4
5

在这个例子中,count_up_to是一个生成器函数。每次它产生一个值时,它都会暂停执行并记住其状态。下次调用时,它会从上次离开的地方继续。

生成器表达式

生成器表达式就像列表推导式,但使用圆括号而不是方括号。它们是一种紧凑的创建生成器的方式。以下是一个示例:

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

# 使用我们的生成器
for square in squares:
print(square)

输出:

0
1
4
9
16

这个生成器表达式动态创建一个平方数的序列,而不会一次性将它们全部存储在内存中。

生成器中的异常处理

生成器也可以处理异常,这非常酷!以下是一个示例:

def div_generator(a, b):
try:
result = a / b
yield result
except ZeroDivisionError:
yield "不能除以零!"

# 使用我们的生成器
g = div_generator(10, 2)
print(next(g))  # 输出:5.0

g = div_generator(10, 0)
print(next(g))  # 输出:不能除以零!

在这个例子中,我们的生成器优雅地处理了尝试除以零的情况。

普通函数与生成器函数

让我们比较一个普通函数和一个生成器函数,看看区别:

# 普通函数
def get_squares(n):
squares = []
for i in range(n):
squares.append(i**2)
return squares

# 生成器函数
def gen_squares(n):
for i in range(n):
yield i**2

# 使用普通函数
print(get_squares(5))  # 输出:[0, 1, 4, 9, 16]

# 使用生成器函数
for square in gen_squares(5):
print(square)  # 每个平方数在新的一行打印

主要区别在于:

  1. 内存使用:普通函数一次性创建并存储所有值,而生成器一次产生一个值。
  2. 语法:普通函数使用return,而生成器使用yield
  3. 迭代:生成器可以直接迭代,而普通函数的结果需要先存储在变量中。

异步生成器

Python 3.6引入了异步生成器,它们就像常规生成器,但是用于异步编程。它们使用async defyield

import asyncio

async def async_gen():
for i in range(3):
await asyncio.sleep(1)
yield i

async def main():
async for item in async_gen():
print(item)

asyncio.run(main())

这个例子模拟了一个异步操作,随时间产生值。

生成器方法

生成器有一些特殊的 方法,它们可能非常有用。以下是最常见的一些方法:

方法 描述
next() 从生成器中检索下一个项目
send() 向生成器发送一个值
throw() 在生成器内部抛出异常
close() 关闭生成器

以下是一个使用send()的快速示例:

def echo_generator():
while True:
received = yield
print(f"接收到的:{received}")

g = echo_generator()
next(g)  # 初始化生成器
g.send("你好")  # 输出:接收到的:你好
g.send("世界")  # 输出:接收到的:世界

就这样!你已经迈出了进入神奇的Python生成器世界的第一步。记住,熟能生巧,所以不要害怕尝试这些概念。在你意识到之前,你将使用生成器来解决Python程序中的各种有趣问题。祝你编程愉快!

Credits: Image by storyset