列表解析和生成器表达式
列表解析(List comprehensions,或者縮略為list comps)來(lái)自函數(shù)式編程語(yǔ)言Haskell,可以用來(lái)動(dòng)態(tài)創(chuàng)建列表。
[expr for iter_var in iterable]? ? ? ?這個(gè)語(yǔ)法的核心是for 循環(huán),他迭代iterable對(duì)象的所有條目,表達(dá)式expr應(yīng)用于序列的每個(gè)成員,最后的結(jié)果值是該表達(dá)式產(chǎn)生的列表。
print map(lambda x:x ** 2,range(6)) print [x ** 2 for x in range(6)] #使用列表解析列表解析中,只有一次函數(shù)調(diào)用(調(diào)用range()函數(shù)),而第一條語(yǔ)句中有三次函數(shù)調(diào)用(range(),map(),lambda),也可以將x**2括起來(lái),這樣更便于閱讀[(x**2) for x in range(6)],列表解析可以取代內(nèi)建的map()和lambda函數(shù),而且效率更高。結(jié)合if語(yǔ)句,列表解析還提供了一個(gè)擴(kuò)展的語(yǔ)法形式。
[expr for iter_var in iterable if cond_expr ] seq = [11,10,9,9,10,10,9,8,23,9,7,18,12,11,12] print filter(lambda x:x%2,seq) print [x for x in seq if x % 2]還比如迭代一個(gè)矩陣
print [(x+1,y+1) for x in range(3) for y in range(5)]? ? ? ?生成器表達(dá)式是列表解析的一個(gè)擴(kuò)展,列表解析的一個(gè)重要不足之處在于要生成所有的數(shù)據(jù),用于創(chuàng)建整個(gè)列表,這可能對(duì)于有大量數(shù)據(jù)的迭代器有負(fù)面效應(yīng),而生成器是特定的函數(shù),允許返回一個(gè)值,然后“暫停”代碼的執(zhí)行,稍后回復(fù)。生成器表達(dá)式通過(guò)結(jié)合列表解析和生成器解決了整個(gè)問(wèn)題。其語(yǔ)法和列表解析非常相似,而且他們的基本語(yǔ)法基本相同,不過(guò)生成器表達(dá)式并不真正的創(chuàng)建數(shù)字列表,而是返回一個(gè)生成器,整個(gè)生成器在每次計(jì)算出一個(gè)條目后,把這個(gè)條目“產(chǎn)生”出來(lái),生成器表達(dá)式使用了“延遲計(jì)算”,所以在使用內(nèi)存上更高效。
(expr for iter_var in iterable if cond_expr )生成器并不會(huì)讓列表解析廢棄,它只是一個(gè)內(nèi)存使用更友好的結(jié)構(gòu),基于此,很多使用生成器的地方
例如計(jì)算文件中的非空字符總和。
f = open('test.txt','r') print len([word for line in f for word in line.split()]) print sum(len(word) for line in f for word in line.split())為了避免創(chuàng)建龐大的列表,可以使用生成器表達(dá)式來(lái)完成對(duì)非空格字符的求解
這里尋找一個(gè)文件最長(zhǎng)的行的例子來(lái)看看如何改進(jìn)代碼
f = open('/etc/motd','r') longest = 0 while true:linelength = len(f.readline().strip()) #strip()函數(shù)是移除字符串首尾的空字符if not linelength:breakif linelength > longest:longest = linelengthf.close() return longest在上面的例子中,從讀取文件開(kāi)始一直查找到最長(zhǎng)的行,一直占用著文件資源,那如果這是一個(gè)很多進(jìn)程都需要訪問(wèn)的日志文件,這樣理所當(dāng)然的就不能一直占用文件的句柄不釋放,因此作出如下改動(dòng)。
f = open('/etc/motd','r') longest = 0 allLines = f.readlines() f.close() for line in allLines:linlen = len(line.strip())if linlen > longest:longest = linlen return longest列表解析允許稍微簡(jiǎn)化代碼,而且可以再得到行的集合之前做一定的處理
f = open('/etc/motd','r') longest = 0 allLines = [x.strip() for x in f.readlines()] f.close() for line in allLines:linlen = len(line)if linlen > longest:longest = linlen return longest然而兩個(gè)例子中在處理大文件時(shí)候都有問(wèn)題,因?yàn)閞eadlines()函數(shù)會(huì)讀取文件的所有行,在有了迭代器之后,文件本事就成為自己的迭代器,不需要調(diào)用readlines()函數(shù),這樣
f = open('/etc/motd','r') allLineLen = [len(x.strip()) for x in f] f.close() return max(allLineLen)這里的問(wèn)題就是一行一行迭代f的時(shí)候,列表解析需要文件的所有行讀取到內(nèi)存中,然后生成列表,這里可以進(jìn)一步簡(jiǎn)化代碼:使用生成器表達(dá)式替換列表解析,然后把它移動(dòng)大max()函數(shù)中
f = open('/etc/motd','r') longest = max(len(x.strip()) for x in f) f.close() return longest最后可以去掉文件的打開(kāi)模式(默認(rèn)為讀取),然后讓python去處理打開(kāi)的文件。當(dāng)然文件用于寫(xiě)入的時(shí)候不能這么做。
return max(len(x.strip()) for x in open('etc/moth'))總結(jié)
以上是生活随笔為你收集整理的列表解析和生成器表达式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 拷贝Python对象、浅拷贝、深拷贝
- 下一篇: 错误和异常