Python中yield关键字的功能解析

Python中yield关键字的功能解析

技术背景

在Python编程中,yield关键字是一个强大且独特的特性,它主要用于创建生成器(generator)。生成器是一种特殊的迭代器,允许我们逐个生成值,而不是一次性生成所有值。这在处理大量数据或无限序列时非常有用,因为它可以节省内存并提高性能。

实现步骤

1. 理解迭代器和生成器

  • 迭代器(Iterable):可以使用for...in...循环遍历的对象,如列表、字符串、文件等。迭代器实现了__iter__()方法,该方法返回一个迭代器对象。
  • 生成器(Generator):是一种特殊的迭代器,它可以通过生成器函数或生成器表达式创建。生成器只在需要时生成值,而不是一次性生成所有值。

2. 使用yield创建生成器函数

当一个函数中包含yield关键字时,该函数就成为了一个生成器函数。调用生成器函数时,它不会立即执行函数体,而是返回一个生成器对象。

1
2
3
4
5
6
def create_generator():
mylist = range(3)
for i in mylist:
yield i*i

mygenerator = create_generator() # 创建一个生成器对象

3. 迭代生成器

可以使用for循环或next()函数来迭代生成器对象。每次调用next()函数或进行一次for循环迭代时,生成器函数会从上次暂停的位置继续执行,直到遇到下一个yield语句。

1
2
for i in mygenerator:
print(i)

核心代码

简单的生成器函数示例

1
2
3
4
5
6
7
8
9
10
def makeRange(n):
i = 0
while i < n:
yield i
i += 1

# 使用生成器函数
gen = makeRange(5)
for num in gen:
print(num)

生成器在实际代码中的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Node:
def __init__(self, _leftchild=None, _rightchild=None, _median=0, _values=[]):
self._leftchild = _leftchild
self._rightchild = _rightchild
self._median = _median
self._values = _values

def _get_dist(self, obj):
# 这里简单返回0作为示例
return 0

def _get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild

# 调用示例
node = Node()
result, candidates = [], [node]
obj = None
while candidates:
node = candidates.pop()
distance = node._get_dist(obj)
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))

最佳实践

节省内存

当处理大量数据时,使用生成器可以避免一次性将所有数据加载到内存中。例如,读取大文件时,可以逐行处理而不是一次性将整个文件读入内存。

1
2
3
4
5
6
7
8
9
def read_large_file(file_path):
with open(file_path, 'r') as file:
for line in file:
yield line

# 使用生成器逐行处理文件
for line in read_large_file('large_file.txt'):
# 处理每一行数据
print(line)

实现无限序列

生成器可以用于实现无限序列,如斐波那契数列。

1
2
3
4
5
6
7
8
9
10
def fib():
last, cur = 0, 1
while True:
yield cur
last, cur = cur, last + cur

# 使用斐波那契数列生成器
fib_gen = fib()
for i in range(10):
print(next(fib_gen))

常见问题

生成器只能迭代一次

生成器是一次性使用的迭代器,一旦迭代完成,就不能再次迭代。如果需要多次使用生成器的结果,可以将其转换为列表。

1
2
3
4
5
gen = makeRange(5)
list_result = list(gen)
# 可以多次使用list_result
for num in list_result:
print(num)

理解yieldreturn的区别

return语句会终止函数的执行并返回一个值,而yield语句会暂停函数的执行并返回一个值,下次调用时会从暂停的位置继续执行。

1
2
3
4
5
6
7
8
9
10
11
# 使用return的函数
def return_function():
return 1

# 使用yield的生成器函数
def yield_function():
yield 1

print(return_function()) # 输出: 1
gen = yield_function()
print(next(gen)) # 输出: 1

生成器的异常处理

当生成器耗尽时,会抛出StopIteration异常。在使用next()函数时,需要注意捕获该异常。

1
2
3
4
5
6
7
gen = makeRange(2)
try:
print(next(gen))
print(next(gen))
print(next(gen)) # 这里会抛出StopIteration异常
except StopIteration:
print("生成器已耗尽")

Python中yield关键字的功能解析
https://119291.xyz/posts/2025-04-15.python-yield-keyword-functionality-analysis/
作者
ww
发布于
2025年4月15日
许可协议