一、概述
我们在使用一组数据时,通常会定义一个列表,然后循环里面的元素,但是如果你只需要使用列表中的其中几个元素,其他的元素用不到,这样就会造成内存资源的浪费,所以,生成器登上历史舞台。
生成器的作用:列表的元素按某种算法推算出来,我们在后续的循环中不断推算出后续的元素,在python中,这种一边循环一边计算的机制,称之为生成器(generator)。
二、列表生成器
如何给列表ff中的每个元素加1
a=[0,1,2,3,4,5,6,7,8,9]for index,i in enumerate(a): a[index]+=1print (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))>>> bat 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 "", line 1, in StopIteration
小结:①generator保存的是算法,每次调用next方法时,就会计算下一个元素的值,直到计算到最后一个元素,如果没有更多元素,则会抛出StopIteration的错误。
②generator只记住当前位置,它访问不到当前位置元素之前和之后的元素,只能往后访问元素,不能访问元素之前的元素。
2、用for循环去访问generator中的元素
用next方法去一个一个访问元素实际coding场景不适用,因为generator也是可迭代对象,实际coding使用for循环去访问,不用关心StopIteration错误
>>> c=(i+2 for i in range(10))>>> cat 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)
结果:
11235
这种逻辑推算非常类似一个生成器(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)
结果:
如果一个函数中包含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__()) #没有多余的元素
结果:
112----------------35Traceback (most recent call last): File "/Users/bianbian/PycharmProjects/test/test12.py", line 15, inprint(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)#结果11235
可以用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: 1f: 1f: 2f: 3f: 5Generator return value: ----done---
捕获这个
当try中的程序执行错误了,就会执行except下面的代码StopIteration这个异常,
五、生成器执行原理
1、执行原理