前言
生成器是 Python 的一种外围个性,容许咱们在申请新元素时再生成这些元素,而不是在开始时就生成所有元素。它在解决大规模数据集、实现节俭内存的算法和构建简单的迭代器模式等多种状况下都有着宽泛的利用。在本篇文章中,咱们将从实践和实际两方面来摸索 Python 生成器的深度用法。
生成器的定义和基本操作
生成器是一种非凡的迭代器,它们的创立形式是在函数定义中蕴含 yield
关键字。当这个函数被调用时,它返回一个生成器对象,该对象能够应用 next()
函数或 for
循环来获取新的元素。
def simple_generator():
yield "Python"
yield "is"
yield "awesome"
# 创立生成器
gen = simple_generator()
# 应用 next 函数获取元素
print(next(gen)) # 输入: Python
print(next(gen)) # 输入: is
print(next(gen)) # 输入: awesome
# 应用 for 循环获取元素
for word in simple_generator():
print(word)
# 输入:
# Python
# is
# awesome
当生成器耗尽(即没有更多元素产生)时,再次调用 next()
函数将引发 StopIteration
异样。这个异样能够由咱们手动捕捉,或者由 for
循环主动解决。
生成器的惰性求值和内存劣势
生成器的次要劣势之一是它们的惰性求值个性。也就是说,生成器只在须要时才计算和产生元素。这使得生成器在解决大规模数据时,能够大大降低内存使用量。与传统的数据结构(如列表)相比,生成器不须要在内存中存储所有元素,而是在每次迭代时动静计算出新的元素。
这种个性使得生成器在解决大规模数据流、实现简单的算法或构建动静的数据管道等场景中具备显著的劣势。
# 有限序列生成器
def infinite_sequence():
num = 0
while True:
yield num
num += 1
# 创立生成器
seq = infinite_sequence()
# 输入前 10 个元素
for i in range(10):
print(next(seq))
# 输入:
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
在这个例子中,infinite_sequence
是一个永不进行的生成器。只管它能够产生无穷多的元素,但因为生成器的惰性求值个性,它并不会导致内存
耗尽。
生成器表达式
生成器表达式是创立生成器的一种更简洁的形式。它们与列表推导式的语法类似,然而生成的是一个生成器对象,而不是一个残缺的列表。这使得生成器表达式在解决大规模数据时能够节俭大量的内存。
# 创立一个生成器表达式
gen_expr = (x**2 for x in range(1000000))
# 输入前 10 个元素
for i in range(10):
print(next(gen_expr))
# 输入:
# 0
# 1
# 4
# 9
# 16
# 25
# 36
# 49
# 64
# 81
在这个例子中,gen_expr
是一个生成器表达式,它能够生成 10^6 个元素的平方数。然而,因为生成器表达式的惰性求值个性,它并不会在内存中生成和存储所有这些元素。
生成器和协程
Python 的生成器还能够作为协程应用。协程是一种非凡类型的函数,它能够在其执行过程中挂起和复原,从而在单个线程中实现多任务合作式并发。这使得咱们能够应用生成器来实现简单的管制流程,如并发编程、异步 IO 等。
def coroutine_generator():
print("Starting")
while True:
value = (yield)
print(f"Received: {value}")
# 创立生成器
gen = coroutine_generator()
# 启动生成器
next(gen) # 输入: Starting
# 向生成器发送数据
gen.send("Hello") # 输入: Received: Hello
gen.send("Python") # 输入: Received: Python
# 敞开生成器
gen.close()
在这个例子中,coroutine_generator
是一个协程生成器。咱们能够应用 send()
函数向它发送数据,生成器在收到数据后将其打印进去。
结语
生成器是 Python 中一种十分弱小的工具,它让咱们可能以更高效和简洁的形式解决简单的问题。熟练掌握生成器的应用,将使你在 Python 编程中具备更高的自由度和更强的实力。
One More Thing…
在 Python 的规范库 itertools
中,有一个函数itertools.islice
,它能够用来对生成器进行切片操作,就像咱们对列表进行切片那样。这在解决大规模数据流时十分有用。
import itertools
# 有限序列生成器
def infinite_sequence():
num = 0
while True:
yield num
num += 1
# 创立生成器
seq = infinite_sequence()
# 对生成器进行切片操作
sliced_seq = itertools.islice(seq, 5, 10)
# 输入切片后的元素
for num in sliced_seq:
print(num)
# 输入:
# 5
# 6
#
7
# 8
# 9
在这个例子中,咱们应用 itertools.islice
函数对有限序列生成器 seq
进行了切片操作,获取了序列的第 5 个到第 10 个元素(从 0 开始计数)。这让咱们可能在不耗费大量内存的状况下,灵便地解决大规模的数据流。
心愿这篇深度解析 Python 生成器的文章对你有所帮忙,如果你对生成器有任何疑难或想要理解更多对于 Python 的常识,欢送在下方留言探讨。
如有帮忙,请多关注
集体微信公众号:【Python 全视角】
TeahLead_KrisChang,10+ 年的互联网和人工智能从业教训,10 年 + 技术和业务团队治理教训,同济软件工程本科,复旦工程治理硕士,阿里云认证云服务资深架构师,上亿营收 AI 产品业务负责人。