Python里面有個很棒的語法糖(syntactic sugar),它就是 list comprehension ,有人把它翻譯成“列表推導式”,也有人翻譯成“列表解析式”。名字聽上去很難理解,但是看它的語法就很清晰了。雖然名字叫做 list comprehension,但是這個語法同樣適用於dict、set等這一系列可迭代(iterable)數據結構。

語法規范:
out_list = [out_express for out_express in input_list if out_express_condition]
其中的 if 條件判斷根據需要可有可無。
下面看一個具體的例子,生成一個包含10以內的偶數的list:
In [1]: evens = [i for i in range(10) if i % 2 == 0] In [2]: evens Out[2]: [0, 2, 4, 6, 8]
由for循環升級到列表推導式:
在沒有了解list comprehension之前,上面那個生成偶數list的通常做法是用for循環:
evens = [] for i in range(10): if i % 2 == 0: evens.append(i)
很明顯,for循環占用了4行代碼,而 list comprehension 只用了1行代碼。
文章開始說到推導式的語法規范時,我們講了if表達式是可有可無的,這也符合我們編程遇到的實際情況。比如,要生成一個10以內的整數的平方的列表:
squares = [i**2 for i in range(10)]
復雜的嵌套循環
我們先來看一個例子,把一個矩陣(以列表為元素的列表)展平為一個列表。首先,我們用for循環來實現一下:
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] flattened = [] for row in matrix: for i in row: flattened.append(i)
接着我們用列表推導式實現該功能:
flattened = [i for row in matrix for i in row]
還是一行代碼就搞定,但一行里面有兩個for,看起來很亂,兩個for,哪個在前哪個在后呢?只要記住他們的順序和不用推導式的原始for循環是一致的即可。
推導式的可讀性
一行代碼搞定幾行代碼的事情,看上去很簡潔,但是讀起來很費勁,尤其是當條件語句很長的時候,把這一行代碼變得很長,超過了代碼規范規定的長度(一般是80個字符),也使得理解代碼變得困難。
面對一行長長的代碼該如何下口讀,如何理解呢?別着急,好在Python允許在中括號、花括號之間斷行:
列表推導式的斷行:
斷行前:
evens = [i for i in range(10) if i % 2 == 0]
斷行后:
evens = [ i for i in range(10) if i % 2 == 0 ]
帶嵌套循環的推導式的斷行:
斷行前:
flattened = [i for row in matrix for i in row]
斷行后:
flattened = [ i for row in matrix for i in row ]
字典(dict)和集合(set)的推導式:
前面我們也提到過,推導式不僅僅適用於列表,它同樣使用於字典dict和集合set。
把一個字典的key和value互換:
changed = {value: key for key, value in input_dict.items()}
用一個列表的所有單詞的首字母生成一個集合:
chars = {w[0] for w in words_list}
通過以上講解就可以輕松掌握Python的列表推導式(list comprehension)了,簡而言之,就是把普通的多行for循環壓縮成一行代碼,這種壓縮語法適用於列表、字典、集合等可迭代數據結構(iterables)。
文章首發於我的技術博客猿人學Python基礎教程
