自从 PEP 255 引入生成器以来,它就是 Python 中重要的一部分.
生成器允许你定义一个有迭代器行为的函数.
它允许程序员更快、更容易、更干净地创建迭代器。
那么什么是迭代器呢,你或许会问?
迭代器 迭代器是一个可迭代(循环)对象。它可以被抽象为一个容器,它保存数据并且表现得像一个可迭代对象。也许你每天都在使用一些可迭代对象:字符串、列表、字典或其他任何对象。
迭代器是实现迭代器接口 Iterator Protocol 的类。该接口为类提供了两个方法:__iter__ 和 __next__。
嗯~回到上一步。为什么要创建迭代器?
节省内存空间
实例化时,迭代器不会计算它的每一项的值,它们只会等待你访问这些项来执行计算。这也称为懒惰评估。
当你要计算非常大的数据集时,惰性求值很有用。它允许你立即开始处理数据,而整个数据集仍在计算中。
假设我们想要获得小于某个值的所有素数。
让我们首先定义一个检查数字是否为质数的函数:
def check_prime(number):
for divisor in range(2, int(number ** 0.5) + 1):
if number % divisor == 0:
return False
return True
然后,我们定义一个迭代器类,包含__iter__ 和 __next__ 方法。
class Primes:
def __init__(self, max):
self.max = max
self.number = 1
def __iter__(self):
return self
def __next__(self):
self.number += 1
if self.number >= self.max:
raise StopIteration
elif check_prime(self.number):
return self.number
else:
return self.__next__()
Primes 类通过给定一个值来实例化。如果下一个素数大于值 max,迭代器将抛出 StopIteration 异常以停止迭代器。
当我们请求迭代器中的下一个元素时,它将数字递增 1 并检查数字是否为质数。如果不是,它会再次调用 __next__ 直到 number 变成素数。一旦如此,迭代器返回数字。
通过使用迭代器,我们不会在内存中创建一个包含许多素数的列表。相反,我们将在每次请求时生成下一个素数。
让我们来试一试:
primes = Primes(100000000000)
print(primes)
for x in primes:
print(x)
......
<__main__.Primes object at 0x1021834a8>
2
3
5
7
11
...
Primes 对象的每次迭代都会调用 __next__ 来生成下一个素数。
迭代器只能迭代一次。如果你尝试再次遍历素数,它将不会返回任何内容并且表现得像一个空列表。
现在我们知道迭代器是什么以及如何制作迭代器,我们将继续讨论生成器。
生成器
回想一下,生成器函数允许我们以更简单的方式创建迭代器。
生成器将 yield 语句引入 Python。它的工作方式有点像 return,因为它返回一个值。
不同之处在于 yield 保存了函数的状态。下次调用该函数时,将从它停止的地方继续执行,并使用与产生之前相同的变量值。
如果我们把我们的 Primes 迭代器变成一个生成器,它看起来像这样:
def Primes(max):
number = 1
while number < max:
number += 1
if check_prime(number):
yield number
primes = Primes(100000000000)
print(primes)
for x in primes:
print(x)
......
<generator object Primes at 0x10214de08>
2
3
5
7
11
现在真是太 pythonic 了!我们还能再给力点吗?
当然!我们可以使用 PEP 289 中介绍的生成器表达式。
这相当于生成器的列表理解。它的工作原理与列表理解相同,但表达式被包裹在 () 而不是 [] 中。
下面的表达式可以代替我们上面的生成器函数:
primes = (i for i in range(2, 100000000000) if check_prime(i))
print(primes)
for x in primes:
print(x)
......
<generator object <genexpr> at 0x101868e08>
2
3
5
7
11
...
这就是 Python 生成器的美妙之处。
总结
生成器允许你以非常 Pythonic 的方式创建迭代器。迭代器允许惰性求值,迭代器对象只会在被请求时生成下一个元素。这对于非常大的数据集很有用。迭代器和生成器都只能迭代一次。生成器函数优于迭代器。生成器表达式优于迭代器(仅在简单情况下)。
本文为原创文章,版权归知行编程网所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ python中的\ xa0是什么09/29
- ♥ python raise 触发异常的实现01/06
- ♥ 安利十二个常用的IPython魔法命令01/04
- ♥ 如何快速安装python12/26
- ♥ 在python中使用round函数保留两位小数08/29
- ♥ Python Timer timer:控制函数在特定时间执行11/06
内容反馈