python生成器的使用
by Radu Raicea
由Radu Raicea
应该如何以及为什么使用Python生成器 (How — and why — you should use Python Generators)
Generators have been an important part of Python ever since they were introduced with PEP 255.
自从PEP 255被引入以来, 生成器就一直是Python的重要组成部分。
Generator functions allow you to declare a function that behaves like an iterator.
生成器函数使您可以声明行为类似于迭代器的函数。
They allow programmers to make an iterator in a fast, easy, and clean way.
它们允许程序员以快速,轻松和干净的方式制作迭代器。
What’s an iterator, you may ask?
您可能会问,什么是迭代器?
An iterator is an object that can be iterated (looped) upon. It is used to abstract a container of data to make it behave like an iterable object. You probably already use a few iterable objects every day: strings, lists, and dictionaries to name a few.
迭代器是可以对其进行迭代(循环)的对象。 它用于抽象数据容器,使其表现得像可迭代对象。 您可能已经每天使用一些可迭代的对象:字符串,列表和字典等。
An iterator is defined by a class that implements the Iterator Protocol. This protocol looks for two methods within the class: __iter__
and __next__
.
迭代器由实现迭代器协议的类定义。 该协议在类中寻找两种方法: __iter__
和__next__
。
Whoa, step back. Why would you even want to make iterators?
哇,退后一步。 您为什么还要创建迭代器?
节省内存空间 (Saving memory space)
Iterators don’t compute the value of each item when instantiated. They only compute it when you ask for it. This is known as lazy evaluation.
迭代器在实例化时不会计算每个项目的值。 他们仅在您需要时才进行计算。 这就是所谓的惰性评估 。
Lazy evaluation is useful when you have a very large data set to compute. It allows you to start using the data immediately, while the whole data set is being computed.
当您要计算非常大的数据集时,惰性评估非常有用。 它允许您在计算整个数据集时立即开始使用数据。
Let’s say we want to get all the prime numbers that are smaller than a maximum number.
假设我们要获取所有小于最大值的质数。
We first define the function that checks if a number is prime:
我们首先定义检查数字是否为质数的函数:
def check_prime(number): for divisor in range(2, int(number ** 0.5) + 1): if number % divisor == 0: return False return True
Then, we define the iterator class that will include the __iter__
and __next__
methods:
然后,我们定义迭代器类,该类将包括__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
is instantiated with a maximum value. If the next prime is greater or equal than the max
, the iterator will raise a StopIteration
exception, which ends the iterator.
Primes
以最大值实例化。 如果下一个质数大于或等于max
,则迭代器将引发StopIteration
异常,从而终止迭代器。
When we request the next element in the iterator, it will increment number
by 1 and check if it’s a prime number. If it’s not, it will call __next__
again until number
is prime. Once it is, the iterator returns the number.
当我们请求迭代器中的下一个元素时,它将使number
递增1并检查其是否为质数。 如果不是,它将再次调用__next__
直到number
为素数。 一旦完成,迭代器将返回数字。
By using an iterator, we’re not creating a list of prime numbers in our memory. Instead, we’re generating the next prime number every time we request for it.
通过使用迭代器,我们不会在内存中创建素数列表。 取而代之的是,每次请求时,我们都会生成下一个质数。
Let’s try it out:
让我们尝试一下:
primes = Primes(100000000000)
print(primes)
for x in primes: print(x)
---------
<__main__.Primes object at 0x1021834a8>235711...
Every iteration of the Primes
object calls __next__
to generate the next prime number.
Primes
对象的每次迭代都会调用__next__
来生成下一个素数。
Iterators can only be iterated over once. If you try to iterate over primes
again, no value will be returned. It will behave like an empty list.
迭代器只能迭代一次。 如果尝试再次遍历primes
,则不会返回任何值。 它的行为就像一个空列表。
Now that we know what iterators are and how to make one, we’ll move on to generators.
现在我们知道了什么是迭代器以及如何创建迭代器,接下来我们将继续介绍生成器。
发电机 (Generators)
Recall that generator functions allow us to create iterators in a more simple fashion.
回想一下,生成器函数使我们能够以更简单的方式创建迭代器。
Generators introduce the yield
statement to Python. It works a bit like return
because it returns a value.
生成器将yield
语句引入Python。 它的工作原理类似于return
因为它返回一个值。
The difference is that it saves the state of the function. The next time the function is called, execution continues from where it left off, with the same variable values it had before yielding.
区别在于它保存了功能的状态 。 下次调用该函数时,将从其中断处继续执行,并使用与屈服前相同的变量值 。
If we transform our Primes
iterator into a generator, it’ll look like this:
如果我们将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>235711...
Now that’s pretty pythonic! Can we do better?
现在,这很pythonic! 我们可以做得更好吗?
Yes! We can use Generator Expressions, introduced with PEP 289.
是! 我们可以使用PEP 289引入的Generator Expressions 。
This is the list comprehension equivalent of generators. It works exactly in the same way as a list comprehension, but the expression is surrounded with ()
as opposed to []
.
这是生成器的列表理解等效项。 它的工作原理与列表理解完全相同,但是表达式用()
而不是[]
包围。
The following expression can replace our generator function above:
以下表达式可以代替上面的生成器函数:
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>235711...
This is the beauty of generators in Python.
这就是Python中生成器的美。
综上所述… (In summary…)
- Generators allow you to create iterators in a very pythonic manner. 生成器允许您以非常Python化的方式创建迭代器。
- Iterators allow lazy evaluation, only generating the next element of an iterable object when requested. This is useful for very large data sets. 迭代器允许进行惰性求值,仅在请求时才生成可迭代对象的下一个元素。 这对于非常大的数据集很有用。
- Iterators and generators can only be iterated over once. 迭代器和生成器只能迭代一次。
- Generator Functions are better than Iterators. 生成器功能优于迭代器。
- Generator Expressions are better than Iterators (for simple cases only). 生成器表达式优于迭代器(仅适用于简单情况)。
You can also check out my explanation of how I used Python to find interesting people to follow on Medium.
您也可以查看我对我如何使用Python查找在Medium上关注的有趣人物的解释 。
For more updates, follow me on Twitter.
有关更多更新,请在Twitter上关注我。
翻译自: https://www.freecodecamp.org/news/how-and-why-you-should-use-python-generators-f6fb56650888/
python生成器的使用