首页 > Python基础教程 >
-
深入解释yield和Generators(生成器)
生成器和yield关键字可能是Python里面最强大的最难理解的概念之一(或许没有之一), 但是并不妨碍yield成为Python里面最强大的关键字,对于初学者来讲确实非常难于理解,来看一篇关于yield的国外大牛写的文章,让你快速理解yield。 文章有点长,请耐心读完, 过程中有些例子, 循序渐进,让你不觉得枯燥。
生成器
生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭代器不一定是生成器)。
如果一个函数包含yield关键字,这个函数就会变为一个生成器。
生成器并不会一次返回所有结果,而是每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。
由于生成器也是一个迭代器,那么它就应该支持next方法来获取下一个值。(也可以使用.__next__()属性, 在python2 中是.next())
协程与子例程
我们调用一个普通的Python函数时,一般是从函数的第一行代码开始执行,结束于return语句、异常或者函数结束(可以看作隐式的返回None)。一旦函数将控制权交还给调用者,就意味着全部结束。函数中做的所有工作以及保存在局部变量中的数据都将丢失。再次调用这个函数时,一切都将从头创建。
对于在计算机编程中所讨论的函数,这是很标准的流程。这样的函数只能返回一个值,不过,有时可以创建能产生一个序列的函数还是有帮助的。要做到这一点,这种函数需要能够“保存自己的工作”。
我说过,能够“产生一个序列”是因为我们的函数并没有像通常意义那样返回。return隐含的意思是函数正将执行代码的控制权返回给函数被调用的地方。而"yield"的隐含意思是控制权的转移是临时和自愿的,我们的函数将来还会收回控制权。
在Python中,拥有这种能力的“函数”被称为生成器,它非常的有用。生成器(以及yield语句)最初的引入是为了让程序员可以更简单的编写用来产生值的序列的代码。 以前,要实现类似随机数生成器的东西,需要实现一个类或者一个模块,在生成数据的同时保持对每次调用之间状态的跟踪。引入生成器之后,这变得非常简单。
为了更好的理解生成器所解决的问题,让我们来看一个例子。在了解这个例子的过程中,请始终记住我们需要解决的问题:生成值的序列。
注意:在Python之外,最简单的生成器应该是被称为协程(coroutines)的东西。在本文中,我将使用这个术语。请记住,在Python的概念中,这里提到的协程就是生成器。Python正式的术语是生成器;协程只是便于讨论,在语言层面并没有正式定义。
例子:有趣的素数
假设你的老板让你写一个函数,输入参数是一个int的list,返回一个可以迭代的包含素数1 的结果。
记住,迭代器(Iterable) 只是对象每次返回特定成员的一种能力。
你肯定认为"这很简单",然后很快写出下面的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
def get_primes(input_list): result_list = list () for element in input_list: if is_prime(element): result_list.append() return result_list # 或者更好一些的... def get_primes(input_list): return (element for element in input_list if is_prime(element)) # 下面是 is_prime 的一种实现... def is_prime(number): if number > 1 : if number = = 2 : return True if number % 2 = = 0 : return False for current in range ( 3 , int (math.sqrt(number) + 1 ), 2 ): if number % current = = 0 : return False return True return False |