你所不知道的你所不知道的python生成器生成器
协程(协同程序)与子例程协程(协同程序)与子例程
一个程序一般都是从函数的第一行代码开始执行的,结束于return语句、异常或者函数的结束。一旦函数将控制权交给调
用者,就意味着全部结束。函数中做的所有工作以及保存在局部变量中的数据将丢失。对于在计算机编程中所讨论的函数,这
是很标准的流程。这样的函数只能返回一个值,不过,有时可以创建能产生一个序列的函数还是有帮助的。要做到这一点,这
种函数需要能够“保存自己的工作”。能够“产生一个序列”是因为我们的函数并没有像通常意义那样返回。return 隐含的意思是
函数正将执行代码的控制权返回给函数被调用的地方。而 yield 的隐含意思是控制权的转移是临时和自愿的,我们的函数将来
还会收回控制权。在 Python 中,拥有这种能力的“函数”被称为生成器,它非常的有用。生成器(以及 yield 语句)最初的引入
是为了让程序员可以更简单的编写用来产生值的序列的代码。 以前,要实现类似随机数生成器的东西,需要实现一个类或者
一个模块,在生成数据的同时保持对每次调用之间状态的跟踪。引入生成器之后,这变得非常简单。
为了更好地理解,这里给出一个例子:
假设你的老板让你写一个函数,输入参数是一个 int 的 list,返回一个可以迭代的包含素数 1 的结果。
这里直接上实现代码以及测试结果:
import math
def get_primes(input_list):
result_list = list()
for element in input_list:
if is_prime(element):
result_list.append(element)
return result_list
# 下面是 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
input_list=[1,2,3,4,5,6] result=get_primes(input_list)
for each in result:
print(each)
但是我们注意到,这里的列表是有限个数,如果这个list非常大,又是一种什么样的情况呢,仅仅是创建这个 list 就会用完
系统的所有内存,为此在get_primes 函数时带上一个 start 参数,返回所有大于这个参数的素数。
我们来看看这个新需求,很明显只是简单的修改 get_primes 是不可能的。 自然,我们不可能返回包含从 start 到无穷的
所有的素数的列表(虽然有很多有用的应用程序可以用来操作无限序列)。看上去用普通函数处理这个问题的可能性比较渺
茫。
在我们放弃之前,让我们确定一下最核心的障碍,是什么阻止我们编写满足老板新需求的函数。通过思考,我们得到这样
的结论:函数只有一次返回结果的机会,因而必须一次返回所有的结果。得出这样的结论似乎毫无意义;“函数不就是这样工
作的么”,通常我们都这么认为的。可是,不学不成,不问不知,“如果它们并非如此呢?”
想象一下,如果 get_primes 可以只是简单返回下一个值,而不是一次返回全部的值,我们能做什么?我们就不再需要创
建列表。没有列表,就没有内存的问题。由于老板告诉我们的是,她只需要遍历结果,她不会知道我们实现上的区别。不幸的
是,这样做看上去似乎不太可能。即使是我们有神奇的函数,可以让我们从 n 遍历到无限大,我们也会在返回第一个值之后
卡住:
def get_primes(start):
for element in magical_infinite_range(start):
if is_prime(element):
return element
def solve_number_10():
total = 2
for next_prime in get_primes(3):
if next_prime < 2000000:
total += next_prime
else:
print(total)
return
评论0
最新资源