关于 Python的生成器畅聊
发布时间:2021-11-12 15:44:50 所属栏目:教程 来源:互联网
导读:生成器可以理解为一种的数据结构,将算法保存,每次计算并返回一个结果,实现了迭代器协议,生成器也是迭代器 生成器有两种表现形式,1)生成器表达式;2)生成器函数 1、生成器表达式 说到生成器表达式,就得先说一下列表推导式 [i for i in range(10)] ,
生成器可以理解为一种的数据结构,将算法保存,每次计算并返回一个结果,实现了迭代器协议,生成器也是迭代器 生成器有两种表现形式,1)生成器表达式;2)生成器函数 1、生成器表达式 说到生成器表达式,就得先说一下列表推导式 [i for i in range(10)] ,生成器表达式,就是将 [ ] 改为 (),区别如下所示 >>> b = [i for i in range(20)] >>> b [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] >>> b = (i for i in range(20000)) >>> b <generator object <genexpr> at 0x00000185EC6104F8> >>> next(b) 0 >>> next(b) 1 >>> next(b) 2 生成器表达式优点:省内存,一次只计算返回一结果。 缺点:不知道有几个元素,只能往后遍历,不能向前遍历,且只能整个生成器只能遍历一次 列表推导式优点:可以通过下标获取元素。 缺点:占用内存大 2、生成器函数 生成器函数:在函数中如果出现了yield关键字,那么该函数就不再是普通函数,而是生成器函数 我们都知道 return 是函数的返回值,yield 也可以将值返回,我们先看一个简单的生成器函数与普通函数之间的差别 >>> def test(): ... print("_______生成器函数") ... yield "返回值1" ... yield "返回值2" ... yield "返回值3" ... >>> test() <generator object test at 0x000001651BEC0570> >>> t1 = test() >>> print(t1.__next__()) _______生成器函数 返回值1 >>> print(t1.__next__()) 返回值2 >>> print(t1.__next__()) 返回值3 >>> print(t1.__next__()) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration 可以看到在第7行调用test()函数的时候,并没有执行函数,而是返回了一个生成器对象。在第10行执行 t1.__next__() 才真正的执行了函数,返回 "返回值1",并保存当前的生成器函数的状态。 每执行一次 next(),生成器函数将执行到下一 yield 并将相应的结果返回,直到产生StopIteration异常。 理解了上述过程,就不难理解生成器表达式的原理,next(t1) 等价于 t1.__next__() def test(): for i in range(10): yield i print(test()) t2 = test() print(next(t2)) print(next(t2)) print(next(t2)) t3 = (i for i in range(10)) print(t3) print(next(t3)) print(next(t3)) print(next(t3)) #输出结果 <generator object test at 0x000001A12D8FF570> 1 <generator object <genexpr> at 0x000001A12D8FF5E8> 1 3、生成器强调,send() 生成器中还有一个重要的方法 send() 方法,send() 方法可以解决将值传递给生成器函数的问题,具体如下: >>> def test(): ... print("____start_____") ... y1 = yield "返回1" ... print("____生成器函数内:%s" % y1) ... y2 = yield "返回2" ... print("____生成器函数内:%s" % y2) ... yield "返回3" ... >>> >>> t1 = test() >>> print(t1.__next__()) ____start_____ 返回1 >>> print(t1.send("a")) ____生成器函数内:a 返回2 >>> print(t1.send("b")) ____生成器函数内:b 返回3 在这里第一次获取值的时候,不能用send(),否者会报错,如果一定要用send,则传值None,如下: >>> t2 = test() >>> t2.send("a") Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't send non-None value to a just-started generator >>> t3 = test() >>> t3.send(None) ____start_____ '返回1' 对于send() 不是很理解的可以尝试往下看,下边是我的一些个人理解,不是很准确,我觉得这样会比较好理解一些 我们可以把函数内 第3行 y1 = yield "返回1" 看成两个过程:1)yield "返回1" 2)y1 = receive_from_send() [并没有这个方法,只是为了理解说明] 这样就可以看到,当执行 send() 时将参数"a" 传递给生成器函数,并在 1)过程停留,传递过去的值没有语句接收,则会出错 所以第一次是不能传值给生成器函数,y1接收到的值为下一次遍历遍历生成器接收的值。 这里也可以也可以在,上上边的代码执行流程可以看出,执行了 14行,y1才会接收到值。 补充一点:每执行一次 1)next(),2)__next(),3)send(),都会在yield语句停留,并保存当前状态,知道直到产生StopIteration异常,结束遍历。 通过生成器,实现斐波那契数列 def fib(n): a, b = 0, 1 while True: yield b a, b = b, a + b if b > n: return f1 = fib(100) #小于 100 的斐波那契数列 for i in f1: print(i,end=" ") #输出结果 1 1 2 3 5 8 13 21 34 55 89 (编辑:常州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |