Python中yield关键字的使用详解
技术背景
在Python编程中,yield
关键字是一个非常强大且独特的特性。要理解 yield
的作用,需要先了解可迭代对象(iterables)、迭代器(iterators)和生成器(generators)的概念。可迭代对象是指可以使用 for... in...
语句进行遍历的对象,如列表、字符串、文件等。迭代器是实现了 __next__()
方法的对象,它允许我们逐个访问可迭代对象中的元素。而生成器是一种特殊的迭代器,它可以在需要时生成值,而不是一次性将所有值存储在内存中,这在处理大量数据时非常有用。
实现步骤
可迭代对象
当创建一个列表时,可以逐个读取其元素,这种操作称为迭代。例如:
1 2 3
| mylist = [1, 2, 3] for i in mylist: print(i)
PYTHON
|
使用列表推导式创建的列表也是可迭代对象:
1 2 3
| mylist = [x*x for x in range(3)] for i in mylist: print(i)
PYTHON
|
生成器
生成器是一种特殊的迭代器,只能迭代一次,它不会将所有值存储在内存中,而是在需要时生成值。可以使用生成器表达式创建生成器:
1 2 3
| mygenerator = (x*x for x in range(3)) for i in mygenerator: print(i)
PYTHON
|
需要注意的是,生成器只能使用一次,再次迭代将不会有任何输出。
yield关键字
yield
是一个关键字,用于定义生成器函数。当函数中包含 yield
关键字时,该函数将返回一个生成器对象。例如:
1 2 3 4 5 6 7 8
| def create_generator(): mylist = range(3) for i in mylist: yield i*i
mygenerator = create_generator() for i in mygenerator: print(i)
PYTHON
|
核心代码
简单生成器函数示例
1 2 3 4 5 6 7 8 9
| def makeRange(n): i = 0 while i < n: yield i i += 1
gen = makeRange(5) for num in gen: print(num)
PYTHON
|
协程示例
1 2 3 4 5 6 7 8 9 10 11 12
| def bank_account(deposited, interest_rate): while True: calculated_interest = interest_rate * deposited received = yield calculated_interest if received: deposited += received
my_account = bank_account(1000, .05) first_year_interest = next(my_account) print(first_year_interest) next_year_interest = my_account.send(first_year_interest + 1000) print(next_year_interest)
PYTHON
|
最佳实践
处理大量数据
当需要处理大量数据时,使用生成器可以避免将所有数据存储在内存中,从而节省内存。例如,处理大文件时,可以逐行读取文件内容:
1 2 3 4 5 6 7 8 9
| def read_file(file_path): with open(file_path, 'r') as file: for line in file: yield line
file_gen = read_file('large_file.txt') for line in file_gen: pass
PYTHON
|
实现无限序列
生成器可以用于实现无限序列,如斐波那契数列:
1 2 3 4 5 6 7 8 9
| 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))
PYTHON
|
常见问题
生成器只能使用一次
生成器是一次性使用的迭代器,一旦耗尽,就不能再次使用。如果需要多次使用生成器的结果,可以将其转换为列表:
1 2 3 4
| gen = makeRange(5) result_list = list(gen) for num in result_list: print(num)
PYTHON
|
混淆可迭代对象、迭代器和生成器
可迭代对象是可以使用 for... in...
语句遍历的对象,迭代器是实现了 __next__()
方法的对象,而生成器是一种特殊的迭代器。需要注意它们之间的区别,避免混淆。
在生成器表达式或列表推导式中使用 yield
CPython 核心开发者正在讨论弃用在生成器表达式或列表推导式中使用 yield
的语法,因此不建议在这些场景中使用 yield
。