[Python]B11─产⽣器表示式(generator)

Hi! 大家好,我是Eric,这次教大家Python的产生器表示式(generator)!
http://img2.58codes.com/2024/emoticon07.gif

■ 产生器表示式(generator)

■ 产⽣器表示式

列表推导使用方括号,而产生器表示式使用圆括号
[n ** 2 for n in range(12)]  #典型的列表推导(n ** 2 for n in range(12))  #典型的产生器表示式
注意:直接输出产生器表达式并不会列印出内容。要列印出产生器表达式产生的全部内容
的⼀个方法是通过向 list 产生器传递参数
list[(n ** 2 for n in range(12))]
列表是值的集合,而产生器是产生值的方法
当你建立⼀个列表的时候,你实际上在产生⼀个数值的集合,并且需要花费⼀定的记忆体开销。
当你建立⼀个产生器的时候,你并没有建立⼀个数值的集合,而是建立了⼀个产生这些数值的方法。
这两者都具有相同的迭代器介面:
L = [n ** 2 for n in range(12)]      #列表推导for val in L:      print(val, end=' ')          G = (n ** 2 for n in range(12))     #产生器表示式for val in G:      print(val, end=' ')      # 区别是:产生器表达式并不会在数值被需要之前计算出它们。这并不仅仅可以提高记忆体效率,  也能提高计算效率!这也意味着⼀个列表的大小受到可用记忆体的限制,而产生器表达式的大小是无限的!
我们可以透过itertools中定义的count迭代器建立一个无限的产生器表示式
itertools import countcount()      for i in count():      print(i, end=' ')      if i >= 10: break
另一个例子
factors = [2, 3, 5, 7]G = (i for i in count() if all(i % n > 0 for n in factors))for val in G:      print(val, end=' ')       if val > 40: break
列表可以被迭代多次,产生器表示式是一次性的
我们可以直接对⼀个列表进行如下操作
L = [n ** 2 for n in range(12)]for val in L:     print(val, end=' ')print()      for val in L:     print(val, end=' ')     #另⼀方面,产⽣器表示式在⼀次迭代后就被用尽G = (n ** 2 for n in range(12))list(G)list(G)#这个特性可以变得非常实用,因为这意味着迭代可以被停止和继续G = (n**2 for n in range(12))for n in G:      print(n, end=' ')      if n > 30: break          print("\ndoing something in between")      for n in G:       print(n, end=' ')       #这个特性在对硬碟上的资料档案集合进行处理时非常实用,意味着我们可以非常轻鬆地批量处理资料, 让产生器负责追蹤那些你尚未处理的区块。

■ 产⽣器函式:关键字yield

在之前的章节中我们看到了列表推导是建立相对简单的列表的最佳途径,而常规的 for 循环在更加複杂的情况下更为 合适。对于产生器表达式来说这也是成立的,我们可以通过产生器函式yield 语句来建立更加複杂的产生器。
我们有两种方式组成同一个列表:
L1 = [n ** 2 for n in range(12)]    L2 = []for n in range(12):    L2.append(n ** 2)        print(L1)print(L2)#同样地,我们也有两种方式组等价的产生器:G1 = (n ** 2 for n in range(12))def gen():    for n in range(12):        yield n ** 2            G2 = gen()print(*G1)print(*G2)
⼀个产生器函式是这样的:它不使用 return 回传⼀个值(仅回传⼀次),而是使用 yield 来产生⼀个包含(可能 是无穷多的)数值的序列。
和产生器表达式中⼀样,在部分迭代(两次迭代的中间,此时产生器并没有被从头到尾执行完,故称部分迭代)的间隔 中产生器的状态得到保留。
但是如果我们需要产生器的⼀个全新的副本,我们只需要简单地重新呼叫那个函式即可。

■ case:质数产生器

产生⼀个包含候选数值的列表
L = [n for n in range(2, 40)]print(L)
对于候选数值序列的第⼀个值,移除它的倍数
L = [n for n in L if n == L[0] or n % L[0] > 0]print(L)
对于候选数值序列的第二个值,移除它的倍数
L = [n for n in L if n == L[1] or n % L[1] > 0]print(L)
对于候选数值序列的第三个值,移除它的倍数
L = [n for n in L if n == L[2] or n % L[2] > 0]print(L)
如果我们不断在⼀个足够大的列表上重複这个过程足够多次,我们就能产生足够多我们需要的质数。
让我们把计算的逻辑封装成为⼀个产生器表示式:
def gen_primes(N):     """Generate primes up to N"""     primes = set()     for n in range(2, N):         if all(n % p > 0 for p in primes):            primes.add(n)            yield nprint(*gen_primes(100))

■ Refer to《Python 旋风之旅,[正体中文]Will保哥》的第13章


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章