Python中的 List Comprehension 以及 Generator
三年前,我在一篇部落格裡不無自豪的記錄了python編寫的小函式,當時感覺python真強大,11行程式碼就寫出了一個配置檔案的解析器。
def loadUserInfo(fileName): userinfo = {} file = open(fileName, "r") while file: line = file.readline() if len(line) == 0: break if line.startswith('#'): continue key, value = line.split("=") userinfo[key.strip()] = value.strip() return userinfo
最近正在跟同事學習python在資料探勘中的應用
,又專門學習了一下python本身,然後用list comprehension
簡化了以下上面的程式碼:
def loadUserInfo(file): return dict([line.strip().split("=") for line in open(file, "r") if len(line) > 0 and not line.startswith("#")])
這個函式和上面的函式的功能一樣,都是讀取一個指定的key=value
格式的檔案,然後構建出來一個對映
(當然,在Python中叫做字典
)物件,該函式還會跳過空行和#
開頭的行。
比如,我想要檢視一下.wgetrc
配置檔案:
if __name__ == "__main__": print(loadUserInfo("/Users/jtqiu/.wgetrc"))
假設我的.wgetrc
檔案配置如下:
http-proxy=10.18.0.254:3128 ftp-proxy=10.18.0.254:3128 #http_proxy=10.1.1.28:3128 use_proxy=yes
則上面的函式會產生這樣的輸出:
{'use_proxy': 'yes', 'ftp-proxy': '10.18.0.254:3128', 'http-proxy': '10.18.0.254:3128'}
list comprehension(列表推導式)
在python中,list comprehension
(或譯為列表推導式)可以很容易的從一個列表生成另外一個列表,從而完成諸如map
, filter
等的動作,比如:
要把一個字串陣列中的每個字串都變成大寫:
names = ["john", "jack", "sean"] result = [] for name in names: result.append(name.upper())
如果用列表推導式,只需要一行:
[name.upper() for name in names]
結果都是一樣:
['JOHN', 'JACK', 'SEAN']
另外一個例子,如果想要過濾出一個數字列表中的所有偶數:
numbers = [1, 2, 3, 4, 5, 6] result = [] for number in numbers: if number % 2 == 0: result.append(number)
如果寫成列表推導式:
[x for x in numbers if x%2 == 0]
結果也是一樣:
[2, 4, 6]
顯然,列表推導更加短小,也更加表意。
迭代器
在瞭解generator
之前,我們先來看一個迭代器
的概念。有時候我們不需要將整個列表都放在記憶體中,特別是當列表的尺寸比較大的時候。
比如我們定義一個函式,它會返回一個連續的整數的列表:
def myrange(n): num, nums = 0, [] while num < n: nums.append(num) num += 1 return nums
當我們計算諸如myrange(50)
或者myrange(100)
時,不會有任何問題,但是當獲取諸如myrange(10000000000)
的時候,由於這個函式的內部會將數字儲存在一個臨時的列表中,因此會有很多的記憶體佔用。
因此在python有了迭代器的概念:
class myrange(object): def __init__(self, n): self.i = 0 self.n = n def __iter__(self): return self # for python 3 def __next__(self): return self.next() def next(self): if self.i < self.n: i = self.i self.i += 1 return i else: raise StopIteration()
這個物件其實實現了兩個特殊的方法:__iter__
(對於python3來說,是__next__
)和next
方法。其中next
每次只返回一個值,如果迭代已經結束,就丟擲一個StopIteration
的異常。實現了這兩個方法的類都可以算作是一個迭代器,他們可以被用於可迭代
的上下文中,比如:
>>> from myrange import myrange >>> x = myrange(10) >>> x.next() 0 >>> x.next() 1 >>> x.next() 2
但是可以看到這個函式中有很多的樣板程式碼,因此我們有了生成器表示式來簡化這個過程:
def myrange(n): num = 0 while num < n: yield num num += 1
注意此處的yield
關鍵字,每次使用next
來呼叫這個函式時都會求值一次num並返回,具體的細節可以參考這裡。
區別
簡單來說,兩者都可以在迭代器上下文中使用,看起來幾乎是一樣的。不同的地方是generator
可以節省記憶體空間,從而提高執行速度。generator
更適合一次性的列表處理,比如只是需要一箇中間列表作為轉換。而列表推導則更適合要將列表
儲存下來,以備後續使用的場景。
這裡也有一些討論,可以一併參看。
參考
相關文章
- python技巧——list comprehension vs mapPython
- python - function list generatorPythonFunction
- python技巧——使用list comprehension生成素數(prime number)Python
- 翻譯:《實用的Python程式設計》02_06_List_comprehensionPython程式設計
- ES6中的迭代器、Generator函式以及Generator函式的非同步操作函式非同步
- Python中list的遍歷Python
- python中的list、tuple和dictionaryPython
- Python中list的切片細節Python
- python中list的各種方法使用Python
- Python中清空list的幾種方法Python
- python中list有哪些方法Python
- python中list切片詳解Python
- Python中元組tuple的作用以及tuple和list的轉換Python
- JS 中的 Iterator, Generator, asyncJS
- PHP中的 Iterator 與 GeneratorPHP
- python中sorted()和list.sort()的用法Python
- python 切片獲取list、tuple中的元素Python
- Python Enhanced Generator - CoroutinePython
- PyThon numpy中array如何轉list?Python
- python中的list,tuple,set和dict(參考python文件)Python
- Python中的List物件(《Python原始碼剖析》筆記四)Python物件原始碼筆記
- Java中基於泛型的交叉型別 - {4Comprehension}Java泛型型別
- Python List 列表list()方法Python
- 【python】list 的用法Python
- Python Yield Generator 詳解Python
- va_list 原理以及用法
- Python中tuple和list的區別?Python基礎學習!Python
- Python List 列表list()方法分享Python
- python listPython
- javascript中generator函式的介紹JavaScript函式
- python generator iterator和iterable objectPythonObject
- Sphinx Introducation: Python Documentation GeneratorPython
- Python “黑魔法” 之 Generator CoroutinesPython
- python中list方法與函式的學習總結Python函式
- Java中List的排序Java排序
- 【譯】什麼是JavaScript generator 以及如何使用它們JavaScript
- python中如何判斷list中是否包含某個元素Python
- python列表(List)Python