上次说到生成器的调用next(),这样很不方便,需要手动调,我们一般是循环着调,while ,for都可以
a = (i for i in range(5)) for i in a: print(i) 0 1 2 3 4 # 执行结果 #和手动调的区别是没了的话就会自动终止循环。就跳出来了 #换成while a = (i for i in range(5)) while True: next(a) 0 1 2 3 4 Traceback (most recent call last): File "<stdin>", line 2, in <module> StopIteration # 执行结果,会报错 #所以一般会用for循环,相当于错误内部就给消化了 补充:其实range(10)底层就是用生成器实现的,也就是每循环一次加一,再python3.x里,range(10)的执行结果是range(0,10),而在python2.7里,结果是直接生成了一个列表[0,1,2,3,4,5,6,7,8,9],这是因为python3中他不是一个普通的range(),是一个公式,就根本没有创建,只有循环到了才创建这个值,但是再python2 里有和python3里range()方法相同的是xrange()。 前面所讲的加1是最简单的,生成器是可以做复杂的算法的。再列表生成式里最复杂的最多写三元运算,而要是做更复杂的,就需要用函数来做这个生成器。 比如,数学上著名的斐波那契数列,(除了第一个和第二个数之外,任意两个数都可由前两个数相加得到)1,1,2,3,5,8,13,21,34......(没什么用,就是一个规律) 如果把前15个数相加,斐波那契数列用列表生成式写不出来,但是可以用函数把他轻松的打印出来 def fib(max): n, a, b = 0, 0, 1 while n< max: print(b) a, b = b, a+b n = n+1 return 'done' 注意赋值语句:a, b = b, a+b 试一下: fib(15) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 'done' # 执行结果 把他变成生成器只需要一步 def fib(max): n, a, b = 0, 0, 1 while n< max: yield b a, b = b, a+b n = n+1 return 'done' print(fib(15)) <generator object fib at 0x0000019878D244C0> #执行结果 #接下来调用 def fib(max): n, a, b = 0, 0, 1 while n< max: yield b #只要函数中出现了yield,就变成了一个生成器,它的作用就是把函数的执行过程冻结在这一步,并且把 b 的值返回给next a, b = b, a+b n = n+1 return 'done' f = fib(15) print(next(f)) print(next(f)) print(next(f)) print(next(f)) 1 1 2 3 # 执行结果 # 换成循环的方式调用 def fib(max): n, a, b = 0, 0, 1 while n< max: yield b a, b = b, a+b n = n+1 return 'done' f = fib(15) for i in f: print(i) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 # 执行结果 #分析 def fib(max): n, a, b = 0, 0, 1 while n< max: print('yemao') yield b #函数到这儿并没有返回就结束了,而是冻结了,接下来怎么继续往下走呢 print(b) a, b = b, a+b n = n+1 return 'done' f = fib(15) print(f) 并不会有执行结果,不会调用,只是生成了一个生成器 next(f)# 调用next才会被执行
#yield比之前的函数好的地方其实是,函数一执行,就会再函数里面打印等结果,不能往外返回, #而用yield就可以在执行的过程中把想要的值返回出来, #yield以后, 函数外面加()根本不会调用,而是生成了一个生成器
#如果要中途终止这个生成器
def range2(n): count = 0 while count < n: print('count', count) count += 1 sign = yield count #return if sign == 'stop': print('---sign', sign) break return 3333 new_range = range2(3) n1 = next(new_range) new_range.send('stop') #next只能是唤醒生成器并执行 #send可以是唤醒并执行,还可以发送给一个信息到生成器内部 count 0 Traceback (most recent call last): ---sign stop File "E:/pycharm/pyCharm/考核/lianxi.py", line 16, in <module> new_range.send('stop') StopIteration: 3333 # 执行结果