上次说到生成器的调用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 "", line 2, in
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))
#执行结果
#接下来调用
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
new_range.send('stop')
StopIteration: 3333 # 执行结果