Python的高級特性2:列表推導式,生成器與迭代器


一.列表推導式

  1.列表推導式是頗具python風格的一種寫法。這種寫法除了高效,也更簡短。

In [23]: {i:el for i,el in enumerate(["one","two","three"])}
Out[23]: {0: 'one', 1: 'two', 2: 'three'}
enumerate是內建函數,可以讓列表獲得“下標”的屬性。
而如果不用列表推導式,上例需要這么寫
In [24]: lst = ["one","two","three"]

In [25]: i = 0

In [26]: for e in lst:
   ....:     lst[i] = '%d: %s' % (i,lst[i])
   ....:     i +=1
   ....:   

In [27]: lst
Out[27]: ['0: one', '1: two', '2: three']

 

 二.迭代器

迭代器屬於一個臨時區,安排一些元素在里面,但只用用的時候才會創建一些臨時區,一旦遍歷結束則臨時區清空,再遍歷就失效了。所以說迭代器能夠減少內存的開銷。

下面用代碼來說明這句話的意思。

In [29]: import sys

In [30]: i = iter(range(10000))

In [32]: id(i.__next__())
Out[32]: 4388723488

In [33]: sys.getsizeof(i)
Out[33]: 48

In [34]: sys.getsizeof(i.__next__())
Out[34]: 28

In [35]: e = range(10000)

In [37]: sys.getsizeof(e)
Out[37]: 48

In [38]: sys.getsizeof(list(e))
Out[38]: 90112

可以看到,如果一次性把list全部加載進來,需要90112byte內存空間,如果使用迭代器迭代,僅僅需要28byte內存空間。 

 

ps:可以被next()函數調用並不斷返回下一個值的對象稱為迭代器。生成器都是Iterator對象,但listdictstr雖然是Iterable,卻不是Iterator,list,tuple,dict,str是有可迭代屬性(惰性循環),但如果需要轉化成可迭代對象,可以用iter()來轉換,驗證方式就是看對象是否有__next__方法。

 

三.生成器(generator)

 生成器是一種特殊的迭代器。

1.什么時候需要用生成器

其實一般情況下是不需要生成器的,只有當因為性能限制下才需要用到,比如你需要用python來read一個10g的txt文件,如果一次性把10g的文件加載到內存再處理(.read()方法),內存肯定溢出了。這里如果使用生成器,就可以把讀和處理交叉進行,比如使用(.readline和.readlines)就可以在循環讀取的同時不斷處理,這樣可以節省大量內存空間。此外,還可以使用生成器生成線程池。

(ps:如果當自己寫一個讀寫函數封裝給別人使用時,那么要考慮到文件容量問題,此時應該考慮使用生成器。)

 

2.生成生成器的兩種方法

2.1 第一種比較簡單,將列表推導式的[]改稱()就可以了

In [40]: g = (x*x for x in range(10))  

 2.2 第二種辦法就是在函數里加入yield關鍵字。yield和return有點類似,都可以用來返回值,不同的是yield遇到next()就返回,再次執行時從上次返回的yield語句處繼續執行。

 

3.如何判斷一個函數是否是生成器     

判斷生成器的辦法就是查看其屬性

In [41]: dir(g)
Out[41]: ['__class__', ... '__next__', ... '__repr__', '__setattr__', ]

 在這里可以看到g有一個__next__的魔術方法,而這是生成器所特有的屬性,下面兩種方式調用都可以

In [42]: g.__next__()
Out[42]: 0 In [43]: g.__next__() Out[43]: 1 In [44]: next(g) Out[44]: 4

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM