第9条:用生成器表达式来改写数据量较大的列表推导式

核心知识点:

(1)当输入的数据量较大时,列表推导可能会因为占用太多内存而出问题。

(2)由生成器表达式所返回的迭代器,可以逐次产生输出值,从而避免内存用量问题

(3)把某个生成器表达式所返回的迭代器,放在另一个生成器表达式的for子表达式中,即可将二者结合起来。

(4)串在一起的生成器表达式执行速度很快。

列表推导式的缺点是:在推导过程中,对于输入序列中的每个值来说,可能都要创建仅含一项元素的全新列表。

当输入的数据比较少时,不会出任何问题,但如果输入的数据非常多,那么可能会消耗大量内存,并导致程序崩溃。

所有的for循环都是将文件的内容依次读入到内存中。

例如,要读取一份文件并返回每行的字符数。若是采用列表推导来做,则需要把文件每一行的长度都保存在内存中。

如果这个文件特别大,或是通过无休止的network socket(网络套接字)来读取,那么这种列表推导就会出问题。

下面的这段列表推导代码,只适合处理少量的输入值。

[[email protected] tmp]# cat /tmp/my_file.txt
systemd-bus-proxy:x:999:997:systemd Bus Proxy:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:998:996:User for polkitd:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
chrony:x:997:995::/var/lib/chrony:/sbin/nologin
cx:x:1000:1000:cx:/home/cx:/bin/bash
mysql:x:1001:1001::/home/mysql:/sbin/nologin

原文件比较小还好

>>> value = [len(x) for x in open(‘/tmp/my_file.txt‘)]
>>> print(value)
[62, 69, 48, 51, 100, 50, 67, 48, 37, 45]

为了解决此问题,python提供了生成器表达式,它是对列表推导和生成器的一种泛化。

生成器表达式在运行的时候,并不会把整个输出序列都呈现出来,而是会估值为迭代器,这个迭代器每次可以根据生成器表达式产生一项数据。

把实现列表推导所用的那种写法放在一对圆括号中,就构成了生成器表达式。

下面给出的生成器表达式与刚才的代码等效,二者的区别在于,生成器表达式求值的时候,它会立刻返回一个迭代器,而不会深入处理文件中的内容。

>>> it = (len(x) for x in open(‘/tmp/my_file.txt‘))
>>> print(it)
<generator object <genexpr> at 0x7f53a13fee60>

以刚才返回的那个迭代器为参数,逐次调用内置的next函数,即可使其按照生成器表达式来输出下一个值。

可以根据自己的需要,多次命令迭代器根据生成器表达式来生成新的值,而不用担心内存用量激增。

>>> print(next(it))
62
>>> print(next(it))
69

使用生成器表达式还有个好处,就是可以互相结合。

下面这行代码会把刚才那个生成器表达式所返回的迭代器用作另外一个生成器表达式的输入值。

>>> roots = ((x,x**0.5) for x in it)

外围的迭代器每次前进时,都会推动内部那个迭代器,这就产生了连锁效应,使得执行循环、评估条件表达式、对接输入和输出等逻辑都组合在了一起。

>>> print(next(roots))
(48, 6.928203230275509)

上面这种连锁生成器表达式,可以迅速在python中执行。

如果要把多种手法组合起来,以操作大批量的输入数据,那最好是用生成器表达式来实现。

只是要注意:由生成器表达式所返回的那个迭代器是有状态的,用过一轮之后,就不要反复使用了。

文章摘抄于Brett Slatkin的《编写高质量Python代码的59个有效方法》,仅作为个人学习使用,如有侵权请告知,将及时删除,如果觉得有益,请购买原版书籍,知识需要传递和支持,谢谢。

时间: 2024-10-04 11:17:15

第9条:用生成器表达式来改写数据量较大的列表推导式的相关文章

(一)Python入门-4控制语句:10推导式创建序列-列表推导式-字典推导式-集合推导式-生成器推导式

推导式创建序列: 推导式是从一个或者多个迭代器快速创建序列的一种方法.它可以将循环和条件判断结合, 从而避免冗长的代码.推导式是典型的Python 风格,会使用它代表你已经超过Python初 学者的水平. 一:列表推导式 列表推导式生成列表对象,语法如下: [表达式 for item in 可迭代对象 ] 或者:{表达式 for item in 可迭代对象 if 条件判断} 1 #列表推导式 2 x = [x for x in range(1,5)] 3 print(x) 4 5 x = [x*

三元表达式、列表推导式、生成器表达式、递归、匿名函数、内置函数

一 三元表达式.列表推导式.生成器表达式 1.三元表达式 name=input('姓名>>: ') res='SB' if name == 'alex' else 'NB' print(res) 2.列表推导式 #1.示例 egg_list=[] for i in range(10): egg_list.append('鸡蛋%s' %i) egg_list=['鸡蛋%s' %i for i in range(10)] #2.语法 [expression for item1 in iterabl

列表推导式和生成器表达式

# 列表推导式 lis = [i for i in range(10)] print(lis) # 生成器表达式 crt = (i for i in range(10)) print(crt) print(crt.__next__()) print(crt.__next__()) print(crt.__next__()) #打印: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] <generator object <genexpr> at 0x00000188F0FED9

生成器表达式,列表推导式

两者的区别在于一个用的是(),另外一个用B[] 生成器表达式: G = (x**2 for x in range(5)) 列表推导式: L = [x**2 for x in range(5)]

生成器表达式 和 列表推导式

列表推导式   [i** 2 for i in [1,2,3]] print(li) li2=[int(i/2) for i in range(0,7,2)] print(li2) 生成器表达式 # 生成器 表达式 简化代码 g=(i for i in range(5)) # 没有元组推导式 for i in g: print(i) 例子  0 list=[{'name':'alex','age':80},{'name':'egon','age':40},{'name':'neza','age'

六 三元表达式、列表推导式、生成器表达式

一 三元表达式 二 列表推导式 三 生成器表达式 一 三元表达式 1 name=input('姓名>>: ') 2 res='abc' if name == 'lucy' else 'jack' 3 print(res) 二 列表推导式 #1.示例 egg_list=[] for i in range(10): egg_list.append('鸡蛋%s' %i) egg_list=['鸡蛋%s' %i for i in range(10)] #2.语法 [expression for ite

列表推导式----生成器表达式

列表推导式: 基本形式: [表达式  for  参数  in  可迭代对象]   或者 [表达式  for  参数  in  可迭代对象  if   条件] 实例: 1 l = [] 2 for i in range(100): 3 l.append('egg%s' %i) 4 print i 5 6 #不带if条件 7 l = ['agg%s' %i for i in range(100) ] 8 9 #带if条件 10 l = ['agg%s' %i for i in range(100)

day14,列表推导式,生成器表达式,内置函数

一.列表推导式.生成器表达式: # li = []# for i in range(1,101):# li.append(i)# print(li) #l1 = [python1期,python2期,python3期.....]# l1 = []# for i in range(1,12):# l1.append('python%s期' % i)# print(l1)#一行搞定,列表推导式:用列表推导式能够构建的任何列表,用别的都可以构建.#一行,简单,感觉高端.但是,不易排错.# li = [

(列表推导式,生成器表达式,内置函数)

一,列表生成式 示例一: 生成1~100的列表 生成1-100的列表 1 2 3 4 5 li = [] for i in range(1,101):     li.append(i) print(li) 执行输出: [1,2,3...] 生成python1期~11期li = []for i in range(1,12): li.append('python{}期'.format(i))print(li) 执行输出: ['python1期', 'python2期', 'python3期'...]