生成器

一、概述

我们在使用一组数据时,通常会定义一个列表,然后循环里面的元素,但是如果你只需要使用列表中的其中几个元素,其他的元素用不到,这样就会造成内存资源的浪费,所以,生成器登上历史舞台。

生成器的作用:列表的元素按某种算法推算出来,我们在后续的循环中不断推算出后续的元素,在python中,这种一边循环一边计算的机制,称之为生成器(generator)。

二、列表生成器

如何给列表ff中的每个元素加1

a=[0,1,2,3,4,5,6,7,8,9]
for index,i in enumerate(a):
    a[index]+=1
print (a)
#结果
[1,2, 3, 4, 5, 6, 7, 8, 9, 10]

 方法2:

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

  以上这种就叫列表生成

三、生成器

1、创建生成器

生成一个list

>>> a=[i+1 for i in range(10)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

生成一个generator

>>> b=(i+1 for i in range(10))
>>> b
<generator object <genexpr> at 0x103ca42a0>

python3是通过__next__()去获得generator的下一个返回值,没有元素时,则会抛出抛出StopIteration的错误 

>>> b.__next__()
1
>>> b.__next__()
2
>>> b.__next__()
3
>>> b.__next__()
4
>>> b.__next__()
5
>>> b.__next__()
6
>>> b.__next__()
7
>>> b.__next__()
8
>>> b.__next__()
9
>>> b.__next__()
10
>>> b.__next__()  #没有元素时,则会抛出抛出StopIteration的错误
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

 小结:①generator保存的是算法,每次调用next方法时,就会计算下一个元素的值,直到计算到最后一个元素,如果没有更多元素,则会抛出StopIteration的错误。

    ②generator只记住当前位置,它访问不到当前位置元素之前和之后的元素,只能往后访问元素,不能访问元素之前的元素。

2、用for循环去访问generator中的元素

用next方法去一个一个访问元素实际coding场景不适用,因为generator也是可迭代对象,实际coding使用for循环去访问,不用关心StopIteration错误

>>> c=(i+2 for i in range(10))
>>> c
<generator object <genexpr> at 0x103ca4318>
>>> for i in c:    #迭代生成器中的元素
    print(i)  

四、函数实现生成器

推算的算法比较复杂,用类似列表生成式的for循环无法实现时,可以使用函数来实现

1、斐波那契数列

实现原理:除第一个和第二个数外,任意一个数都可由前两个数相加得到:1, 1, 2, 3, 5, 8, 13, 21, 34, ...,很明显斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易。

def fibna(max):
    n,a,b=0,0,1
    while n < max:
        print(b)
        a,b=b,a+b
        n=n+1
    return "----done---"
fibna(5)

  结果:

1
1
2
3
5

 这种逻辑推算非常类似一个生成器(generator),如何把一个函数转换成一个生成器?

2、用yield函数转换为生成器(generator)

def fibna(max):
    n,a,b=0,0,1
    while n < max:
        yield b  # 用yield替换print,把fib函数转化成一个生成器
        a,b=b,a+b
        n=n+1
    return "----done---"
f=fibna(5)
print(f)

  结果:

<generator object fibna at 0x10ec8b750>

 如果一个函数中包含yield关键字,那么这个函数就不是一个普通的函数,而是一个生成器(generator)。

注:

①函数是顺序执行的,遇到return语句或者最后一行函数语句就返回

②变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

def fibna(max):
    n,a,b=0,0,1
    while n < max:
        yield b  # 用yield替换print,把fib函数转化成一个生成器
        a,b=b,a+b
        n=n+1
    return "----done---"
f=fibna(5)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print("--------------")
print(f.__next__())
print(f.__next__())#访问的是最后一个元素
print(f.__next__()) #没有多余的元素

 结果:

1
1
2
----------------
3
5
Traceback (most recent call last):
  File "/Users/bianbian/PycharmProjects/test/test12.py", line 15, in <module>
    print(f.__next__()) #没有多余的元素
StopIteration: ----done---  

访问生成器中的元素,不用是连续的,可以中间去执行其他程序。

return在这里的作用:当发生异常时,打印ruturn后面的值。

def fibna(max):
    n,a,b=0,0,1
    while n < max:
        yield b  # 用yield替换print,把fib函数转化成一个生成器
        a,b=b,a+b
        n=n+1
    return "----done---"
f=fibna(5)
for i in f:
    print(i)
#结果
1
1
2
3
5

 可以用for循环访问 

3、异常捕获

def fibna(max):
    n,a,b=0,0,1
    while n < max:
        yield b  # 用yield替换print,把fib函数转化成一个生成器
        a,b=b,a+b
        n=n+1
    return "----done---"
f=fibna(5)
while True:
    try:
        x = f.__next__()
        print("f:",x)
    except StopIteration as e:  #当try中的程序执行错误了,才会执行except下面的代码
        print("Generator return value:",e.value)
        break

  结果

f: 1
f: 1
f: 2
f: 3
f: 5
Generator return value: ----done---

  捕获这个StopIteration这个异常,当try中的程序执行错误了,就会执行except下面的代码

五、生成器执行原理

1、执行原理

原文地址:https://www.cnblogs.com/bianfengjie/p/10844899.html