1. 一個簡單的例子
在Python中,如果我們想修改列表中所有元素的值,可以使用 for
循環語句來實現。
例如,將一個列表中的每個元素都替換為它的平方:
>>> L = [1, 2, 3, 4, 5] >>> for i in range(len(L)): ... L[i] = L[i] ** 2 >>> L [1, 4, 9, 16, 25]
另一種優雅的實現方式就是使用列表推導式(List Comprehensions):
>>> L = [1, 2, 3, 4, 5] >>> L = [x ** 2 for x in L] >>> L [1, 4, 9, 16, 25]
2. 基本語法
我們具體來分析上面給出的例子
>>> L = [x ** 2 for x in L]
我們將列表推導式寫在一個方括號內,因為它最終構建的是一個列表。
列表推導式主要由兩部分構成:
- 循環變量表達式(
x ** 2
) for
循環頭部(for x in L
)
是不是非常簡單!
3. 工作原理
Python在執行列表推導式時,會對可迭代對象 L
進行迭代,將每一次迭代的值賦給循環變量 x
,然后收集變量表達式 x ** 2
的計算結果,最終由這些結果構成了新的列表,也就是列表推導式所返回的值。
只要支持 for
循環進行迭代的對象,都可以對它使用列表推導式。
例如,我們將一個字符串進行移位處理:
>>> S = 'abcde' >>> S = ''.join([chr(ord(c)+1) for c in S]) >>> S 'bcdef'
4. 高級語法
除了像上面介紹的 [x ** 2 for x in L]
這種基本語法之外,列表推導式還有一些高級的擴展。
4.1. 帶有if語句
我們可以在 for
語句后面跟上一個 if
判斷語句,用於過濾掉那些不滿足條件的結果項。
例如,我想去除列表中所有的偶數項,保留奇數項,可以這么寫:
>>> L = [1, 2, 3, 4, 5, 6] >>> L = [x for x in L if x % 2 != 0] >>> L [1, 3, 5]
4.2. 帶有for嵌套
在復雜一點的列表推導式中,可以嵌套有多個 for
語句。按照從左至右的順序,分別是外層循環到內層循環。
例如:
>>> [x + y for x in 'ab' for y in 'jk'] ['aj', 'ak', 'bj', 'bk']
4.3. 既有if語句又有for嵌套
列表推導式可以帶任意數量的嵌套 for
循環,並且每一個 for
循環后面都有可選的 if
語句。
通用語法:
[ expression for x in X [if condition] for y in Y [if condition] ... for n in N [if condition] ]
例如,下面的代碼輸出了0~4之間的偶數和奇數的組合。
>>> [(x, y) for x in range(5) if x % 2 == 0 for y in range(5) if y % 2 == 1] [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
等價於下面的一般 for
循環:
>>> L = [] >>> for x in range(5): ... if x % 2 == 0: ... for y in range(5): ... if y % 2 == 1: ... L.append((x, y)) >>> L [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
4.4. 列表推導式生成矩陣
生成矩陣的方式有多種,例如手動賦值、一般for循環,還有就是列表推導式。如果我們要用列表推導式生成下面的矩陣,可以怎么寫?
>>> M = [[1, 2, 3], ... [4, 5, 6], ... [7, 8, 9]]
一種方法是:
>>> M = [[x, x+1, x+2] for x in [1, 4, 7]] >>> M [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
矩陣的列數少時可以使用這種方法。
如果矩陣的列數較多,我們可以使用另外一種方式:在循環變量的表達式中使用列表推導式。
具體代碼如下:
>>> M = [[y for y in range(x, x+3)] for x in [1, 4, 7]] >>> M [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
與之前帶 for
嵌套的語法不同,這個例子中,實際使用的是最基本的 [expression for x in L]
語法,只有一個 for
語句。
復雜的地方在於前面的變量表達式 expression
不再是簡單的變量運算,而是一個列表推導式,在這個例子中就是 [y for y in range(x, x+3)]
。
內層的列表推導式返回一個行向量,而這些行向量經由外層的列表推導式,最終形成一個二維列表,也就是我們想要的矩陣。
當然,在實際的應用中不能單純追求代碼的簡潔,還要考慮到代碼的可讀性和維護成本。
如果代碼變得過於復雜,不易於理解,我們寧可多寫幾行代碼來增加它的可讀性。
5. 生成器表達式
生成器表達式與列表推導式的語法相同,區別在於生成器表達式的外面使用圓括號,而列表推導式使用方括號。
有關生成器的介紹,請參考這篇文章:《Python高級編程之初識生成器》
6. 集合推導式和字典推導式
注意:集合推導式和字典推導式只有在Python2.7以及之后的版本中才有,Python2.7之前的版本不支持這兩種推導式。
集合推導式的語法與列表推導式相同,只需要把外面的方括號改成花括號即可。
例如,我們可以通過以下方式來生成一個集合:
>>> {x ** 2 for x in [1, 2, 2]} {1, 4}
字典推導式的外面也是使用花括號,不過花括號的內部需要包含鍵值兩部分。
在值不重復的情況下,我們可以通過字典推導式快速交換鍵值對:
>>> D = {'a':1, 'b':2, 'c':3} >>> D = {value: key for key, value in D.items()} >>> D {1: 'a', 2: 'b', 3: 'c'}
總結:在編寫或是閱讀這類推導式的時候,一定要注意先從for..in開始,最后再看前面的循環變量表達式。
作者:Wray Zheng
原文:http://www.codebelief.com/article/2017/02/python-advanced-programming-list-comprehensions/