3-21 生成器

列表生成式

现在有个需求,看列表[0,1,2,3,4,5,6,7,8,9],要求你把列表里的每个值加1,怎么实现?

a = [i+1 for i in range(10)]

这样的写法就叫做列表生成式

生成器


通过列表生成式,我们可以直接创建一个列表。但是,收到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间就白白浪费了。

所以,如果列表元素可以按某种算法推算出来,那我们是否可以在循环的过程不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在python中,这种一边循环一边计算的机制,称为生成器:generator:

要创建一个generator,有很多种方法,第一种方法很简单,只要把一个列表生成式的[]改成()就创建了一个genarator

a = (x if x<5 else x*x for x in range(10))
print(a)

print(next(a))
print(next(a))
print(next(a))

<generator object <genexpr> at 0x01304870>
0
1
2

>>> a3 =(i for i in range(5))
>>> a3
<generator object <genexpr> at 0x003C48F0>
>>> next(a3)
0
>>> next(a3)
1
>>> next(a3)
2
>>> next(a3)
3
>>> next(a3)
4
>>> next(a3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

generator保存的是算法,每次调用next(a)就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

当然,上面这种不断调用next()的方法太麻烦了,正确的方法是使用for循环,因为generator也是可迭代对象:

a = (i for i in range(10))

for i in a:
    print(i)

0
1
2
3
4
5
6
7
8
9

所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代他,并且不需要关心StopIteration的错误。

generator非常强大.如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数。

斐波那契:

斐波那契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

def fib(max):
    n,a,b = 0,0,1
    while n<max:
        yield b #把函数的执行过程冻结到这一步,并且把b的值返回给外部
        a,b = b,a+b
        n= n+1
  return('done')

print(fib(5))

for i in fib(5):
    print(i)

yield vs return

return 返回并终止function

yield返回数据,并冻结当前的执行过程

next 唤醒冻结的函数执行过程,继续执行,直到遇到下一个yield 

函数有了yield之后:

1.函数名加()就得到了一个生成器

2.return在生成器里代表函数的终止,并会报错

生成器的send方法

def range2(n):
    count = 0
    while count < n:
        print('count',count)
        count += 1
        sign =yield count
        print('---sign',sign)
        if sign == 'stop':
            break
    return 3333

new_range = range2(6)
n1 = next(new_range)
n2 = next(new_range)
n3 = next(new_range)
n4 = next(new_range)
new_range.send('stop')

#send的作用,1唤醒并继续执行
#2.发送一个信息到生成器

猜你喜欢

转载自www.cnblogs.com/echo-kid-coding/p/11327976.html