在 Python 中,生成新列表時使用列表推導表示法很簡單。(List comprehensions
)
- 5. Data Structures — List Comprehensions — Python 3.10.0 Documentation
- 6. Expressions — Displays for lists, sets and dictionaries — Python 3.10.0 Documentation
在本文中,我們將首先討論以下內容
- 列表理解符號的基本類型
- 用 if 條件分支列出理解符號
- 與三元運算符的組合(if else-like處理)
zip()
,enumerate()
與這些結合- 嵌套列表包含符號
接下來,我們將通過示例代碼解釋列表理解符號集。
- 設置包含符號(
Set comprehensions
) - 字典包含符號(
Dict comprehensions
) - 發電機類型(
Generator expressions
)
列表理解符號的基本類型
列表理解符號寫成如下。
[Expression for Any Variable Name in Iterable Object]
它通過任意變量名稱獲取可迭代對象(例如列表、元組或範圍)的每個元素,並使用表達式對其進行評估。返回以評估結果為元素的新列表。
給出了一個示例以及等效的 for 語句。
squares = [i**2 for i in range(5)]
print(squares)
# [0, 1, 4, 9, 16]
squares = []
for i in range(5):
squares.append(i**2)
print(squares)
# [0, 1, 4, 9, 16]
可以使用 map() 完成相同的過程,但首選列表理解表示法,因為它簡單明了。
用 if 條件分支列出理解符號
也可以使用 if 進行條件分支。在後綴中寫 if 如下。
[Expression for Any Variable Name in Iterable Object if Conditional Expression]
表達式只對條件表達式為真的可迭代對象的元素進行評估,並返回一個元素為結果的新列表。
您可以在條件表達式中使用任何變量名稱。
給出了一個示例以及等效的 for 語句。
odds = [i for i in range(10) if i % 2 == 1]
print(odds)
# [1, 3, 5, 7, 9]
odds = []
for i in range(10):
if i % 2 == 1:
odds.append(i)
print(odds)
# [1, 3, 5, 7, 9]
可以使用 filter() 完成相同的過程,但首選列表理解表示法,因為它簡單明了。
與三元運算符的組合(if else-like處理)
在上面的例子中,只處理那些符合條件的元素,不符合條件的元素被排除在新列表之外。
如果要根據條件切換流程,或者要以不同方式處理不滿足條件的元素(如 if else),請使用三元運算符。
在 Python 中,三元運算符可以寫成如下
Value When True if Conditional Expression else Value When False
這用於列表理解符號的表達式部分,如下所示。
[Value When True if Conditional Expression else Value When False for Any Variable Name in Iterable Object]
給出了一個示例以及等效的 for 語句。
odd_even = ['odd' if i % 2 == 1 else 'even' for i in range(10)]
print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
odd_even = []
for i in range(10):
if i % 2 == 1:
odd_even.append('odd')
else:
odd_even.append('even')
print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
也可以使用任意變量名稱為真值和假值編寫表達式。
如果滿足條件,則進行一些處理,否則原始可迭代對象的值保持不變。
odd10 = [i * 10 if i % 2 == 1 else i for i in range(10)]
print(odd10)
# [0, 10, 2, 30, 4, 50, 6, 70, 8, 90]
結合 zip() 和 enumerate()
for 語句中經常使用的有用函數包括 zip(),它組合了多個可迭代對象,以及 enumerate(),它返回一個值及其索引。
當然,可以將 zip() 和 enumerate() 與列表理解符號一起使用。它不是一種特殊的語法,如果考慮與 for 語句的對應關係,也不難。
zip() 示例。
l_str1 = ['a', 'b', 'c']
l_str2 = ['x', 'y', 'z']
l_zip = [(s1, s2) for s1, s2 in zip(l_str1, l_str2)]
print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]
l_zip = []
for s1, s2 in zip(l_str1, l_str2):
l_zip.append((s1, s2))
print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]
enumerate() 的例子。
l_enu = [(i, s) for i, s in enumerate(l_str1)]
print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]
l_enu = []
for i, s in enumerate(l_str1):
l_enu.append((i, s))
print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]
使用 if 時的想法與之前相同。
l_zip_if = [(s1, s2) for s1, s2 in zip(l_str1, l_str2) if s1 != 'b']
print(l_zip_if)
# [('a', 'x'), ('c', 'z')]
每個元素也可以用來計算一個新元素。
l_int1 = [1, 2, 3]
l_int2 = [10, 20, 30]
l_sub = [i2 - i1 for i1, i2 in zip(l_int1, l_int2)]
print(l_sub)
# [9, 18, 27]
嵌套列表包含符號
與嵌套 for 循環一樣,列表理解符號也可以嵌套。
[Expression for Variable Name 1 in Iterable Object 1
for Variable Name 2 in Iterable Object 2
for Variable Name 3 in Iterable Object 3 ... ]
為方便起見,添加了換行和縮進,但不是語法所必需的;它們可以在一行上繼續。
給出了一個示例以及等效的 for 語句。
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [x for row in matrix for x in row]
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
flat = []
for row in matrix:
for x in row:
flat.append(x)
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
也可以使用多個變量。
cells = [(row, col) for row in range(3) for col in range(2)]
print(cells)
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
您還可以進行條件分支。
cells = [(row, col) for row in range(3)
for col in range(2) if col == row]
print(cells)
# [(0, 0), (1, 1)]
也可以為每個可迭代對像有條件地分支。
cells = [(row, col) for row in range(3) if row % 2 == 0
for col in range(2) if col % 2 == 0]
print(cells)
# [(0, 0), (2, 0)]
設置包含符號(Set comprehensions)
將列表推導式表示法中的方括號 [] 更改為大括號 {} 創建一個集合(集合類型對象)。
{Expression for Any Variable Name in Iterable Object}
s = {i**2 for i in range(5)}
print(s)
# {0, 1, 4, 9, 16}
字典包含符號(Dict comprehensions)
字典(字典類型對象)也可以用理解符號生成。
{},並將表達式部分中的鍵和值指定為 key: value。
{Key: Value for Any Variable Name in Iterable Object}
可以為鍵和值指定任何表達式。
l = ['Alice', 'Bob', 'Charlie']
d = {s: len(s) for s in l}
print(d)
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}
要從鍵和值列表創建新字典,請使用 zip() 函數。
keys = ['k1', 'k2', 'k3']
values = [1, 2, 3]
d = {k: v for k, v in zip(keys, values)}
print(d)
# {'k1': 1, 'k2': 2, 'k3': 3}
發電機類型(Generator expressions)
如果列表推導式表示法中的方括號 [] 用作圓括號 (),則返回生成器而不是元組。這稱為生成器表達式。
列表理解符號的示例。
l = [i**2 for i in range(5)]
print(l)
# [0, 1, 4, 9, 16]
print(type(l))
# <class 'list'>
生成器表達式的示例。如果按原樣打印() 生成器,它不會打印出其內容,但如果使用 for 語句運行它,則可以獲得內容。
g = (i**2 for i in range(5))
print(g)
# <generator object <genexpr> at 0x10af944f8>
print(type(g))
# <class 'generator'>
for i in g:
print(i)
# 0
# 1
# 4
# 9
# 16
生成器表達式還允許使用 if 和列表理解符號進行條件分支和嵌套。
g_cells = ((row, col) for row in range(0, 3)
for col in range(0, 2) if col == row)
print(type(g_cells))
# <class 'generator'>
for i in g_cells:
print(i)
# (0, 0)
# (1, 1)
例如,如果使用列表理解表示法生成具有大量元素的列表,然後使用 for 語句循環,則如果使用列表理解表示法,將在開頭生成包含所有元素的列表。另一方面,如果使用生成器表達式,每次重複循環時,元素都會一個一個地生成,從而減少使用的內存量。
如果生成器表達式是函數的唯一參數,則可以省略圓括號 ()。
print(sum([i**2 for i in range(5)]))
# 30
print(sum((i**2 for i in range(5))))
# 30
print(sum(i**2 for i in range(5)))
# 30
至於處理速度,當處理所有元素時,列表理解符號通常比生成器符號快。
但是,例如,在使用 all() 或 any() 進行判斷時,會在存在 false 或 true 時確定結果,因此使用生成器表達式可能比使用列表推導式表示法更快。
沒有元組推導表示法,但是如果您使用生成器表達式作為 tuple() 的參數,則可以使用推導表示法生成一個元組。
t = tuple(i**2 for i in range(5))
print(t)
# (0, 1, 4, 9, 16)
print(type(t))
# <class 'tuple'>