【什么是生成器】

【什么是生成器】什么是生成器 一 生成式 一种调函数的方式二 元组推导式 延迟演算三 yield 语句 交替执行四 yield 表达式五 计算斐波那契数列 生成无限的数据一 生成式 一种调函数的方式 如果忽略开水 价钱 买方便

大家好,欢迎来到IT知识分享网。

一、生成式 —— 一种调函数的方式

  如果忽略开水、价钱,买方便面和泡方便面有何差别?买方便面可能一次买一箱,不是吃多少卖多少,但泡方便面则不会一次泡一箱,时,肯定是吃多少泡多少。

  生成式给了我们另一种选择,即两个函数的交替执行。它像是泡方便面,调一次函数拿到一项数据,不用想办法存储所有的数据,体现了延迟演算的思想,而代码却不用有多少变化。

  生成式有三种形式:元组式、yield 语句、yield表达式。

二、元组推导式 —— 延迟演算

  列表式很常见,它根据一组数据计算出一组新的数据,是对赋值语句的一种改进。下列代码将得到列表 [1,3,2,5] 中各元素的平方构成的新列表。

a = [k2 for k in [1,3,2,5]] print(a) 

运行结果

[1, 9, 4, 25] 

  又一个例子,它能显示计算过程,注意这里没有执行 print,但依旧有结果被打印出来,说明系统立即计算了新列表的所有元素。

a = [(i,print(i))[0] for i in [1,3,2,5]] 

运行结果

1 3 2 5 

  元组也能根据一组数据计算出一组新的数据,但有着不同的中间过程。代码做了修改,将方括号改为圆括号,结果有所不同。

a = ((i,print(i))[0] for i in [1,3,2,5]) 

运行结果是空的,咦,…

 

  这表明,元组式并没有生成它自己的元素,一个都没有,这就是延迟演算。

a = ((i,print(i))[0] for i in [1,3,2,5]) i = 0 for _ in a: if i > 1: break i += 1 

运行结果如下。上面的代码有一个循环,for 执行了 3 遍后结束循环,相应地从 a 中取了 3 个元素,导致 print 被调用 3 次,所以将打印三项数据。

1 3 2 

这就是生成式的第一种形式,上面的例子体现了列表式的立即演算和生成式的延迟演算特性。

三、yield 语句 —— 交替执行

def g(): for i in range(3): print(f'\tin g({ 
     i})') def f(): g() for i in range(3): print(f'in f({ 
     i})') f() 

运行结果如下。当 g 在工作时,f 在等待;当 f 继续工作时,g 已经结束了,呈现出顺序结构的工作模式。

 in g(0) in g(1) in g(2) in f(0) in f(1) in f(2) 

  g 在函数中执行 yield,可做到暂时离开执行中的 g 回到 f,待 f 执行 next 时又回到 g 中,实现 f 与 g交替执行。

def g(): for i in range(3): print(f'\t\t\tg(),i={ 
     i}') yield i def f(): a = g() print(f'f()') for j in range(3): b = next(a) print(f'f(),j={ 
     j},b={ 
     b}') f() 

运行结果如下。代码中,f 首先执行 a = g() 创建一个生成器,执行到 next(a) 语句时暂停,g 开始执行直到 yield 语句,并将 yield 后的表达式的值传递给 b = next(a) 中等号左边的 b,g 暂停,f 继续执行直到下一个 next(a) 或者结束。

f() g(),i=0 f(),j=0,b=0 g(),i=1 f(),j=1,b=1 g(),i=2 f(),j=2,b=2 

四、yield 表达式 —— 双向传递数据

  表达式可以出现在等号右边。使用 yield 表达式可实现 f 与 g 双向数据传送。f 执行 b = a.send©,g 执行 y = yield x。f 执行 b = a.send© 将 c 传给 y = yield x 中的 y 后等待 b,并将控制传递给 g,g 执行 y = yield x 将 x 传递给 f 的 b 后等待 y,并将控制交还给 f。

def g(x): for i in range(10): y = yield x print('\t', y) x = y def f(): a = g(11) b = a.send(None) print (b) b = a.send(b+1) print (b) b = a.send(b+1) print (b) f() 

运行结果

11 12 12 13 13 

五、计算斐波那契数列 —— 生成无限的数据

  生成器有什么用呢?看看下面的例子。

def fib(): a = 0 b = 1 yield a while True: yield b a, b = b, a+b a = fib() for i in range(10): print(next(a)) for i in range(200): print(next(a)) 

运行结果如下。与标准函数相比,这时 fib 才真正有了有数列的感觉。你一直调用它,它会源源不断地返回更多的后继,像是射击,开一枪,响一声,再开一枪,再响一声。

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025     

  请设想,用类能够实现类似的功能吗?生成器是不是最简的选择?

【下一个坑:str 与 repr 有何差别?】

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/140453.html

(0)
上一篇 2025-05-26 18:33
下一篇 2025-05-26 18:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信