知行编程网知行编程网  2022-11-28 09:00 知行编程网 隐藏边栏  2 
文章评分 0 次,平均分 0.0
导语: 本文主要介绍了关于一篇文章教你如何使用Python生成器的相关知识,希望可以帮到处于编程学习途中的小伙伴

一篇教你如何使用Python生成器的文章

自从 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 的方式创建迭代器。迭代器允许惰性求值,迭代器对象只会在被请求时生成下一个元素。这对于非常大的数据集很有用。迭代器和生成器都只能迭代一次。生成器函数优于迭代器。生成器表达式优于迭代器(仅在简单情况下)。

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

知行编程网
知行编程网 关注:1    粉丝:1
这个人很懒,什么都没写
扫一扫二维码分享