列表理解

一個列表解析建立通過將表達成的每個元素的新 list 可迭代 。最基本的形式是:

[ <expression> for <element> in <iterable> ]

還有一個可選的’if’條件:

[ <expression> for <element> in <iterable> if <condition> ]

如果(可選)<condition> 評估為真,<iterable> 中的每個 <element> 都插入到 <expression> 中。所有結果將在新列表中立即返回。生成器表示式是懶惰地計算的,但是列表推導會立即評估整個迭代器 - 消耗與迭代器長度成比例的記憶體。

要建立一個平方整數:

squares = [x * x for x in (1, 2, 3, 4)]
# squares: [1, 4, 9, 16]

for 表示式從 (1, 2, 3, 4) 依次將 x 設定為每個值。表示式 x * x 的結果附加到內部 list。內部 list 在完成時分配給變數 squares

除了一個速度增加 (如解釋在這裡 ),列表理解大致相當於下面的 for 迴圈:

squares = []
for x in (1, 2, 3, 4):
    squares.append(x * x)
# squares: [1, 4, 9, 16]

應用於每個元素的表示式可以根據需要複雜化:

# Get a list of uppercase characters from a string
[s.upper() for s in "Hello World"]
# ['H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D']

# Strip off any commas from the end of strings in a list
[w.strip(',') for w in ['these,', 'words,,', 'mostly', 'have,commas,']]
# ['these', 'words', 'mostly', 'have,commas']

# Organize letters in words more reasonably - in an alphabetical order
sentence = "Beautiful is better than ugly"
["".join(sorted(word, key = lambda x: x.lower())) for word in sentence.split()]
# ['aBefiltuu', 'is', 'beertt', 'ahnt', 'gluy']

其他

else 可以在 List 理解構造中使用,但要注意語法。if / else 子句應該在 for 迴圈之前使用,而不是在:

# create a list of characters in apple, replacing non vowels with '*'
# Ex - 'apple' --> ['a', '*', '*', '*' ,'e']

[x for x in 'apple' if x in 'aeiou' else '*']
#SyntaxError: invalid syntax

# When using if/else together use them before the loop
[x if x in 'aeiou' else '*' for x in 'apple']
#['a', '*', '*', '*', 'e']

請注意,這使用不同的語言構造,條件表示式 ,它本身不是理解語法的一部分。而 for…in 之後的 if 列表推導的一部分,用於從源迭代中過濾元素。

雙迭代

雙重迭代的順序 [... for x in ... for y in ...] 要麼是自然的,要麼是反直覺的。經驗法則是遵循一個等效的 for 迴圈:

def foo(i):
    return i, i + 0.5

for i in range(3):
    for x in foo(i):
        yield str(x)

這變為:

[str(x)
    for i in range(3)
        for x in foo(i)
]

這可以壓縮為一行,如 [str(x)for i inrange(3)for x infoo(i)]

就地突變和其他副作用

在使用列表推導之前,要了解通常返回 None 的副作用( 變異就地 函式)呼叫的函式與返回有趣值的函式之間的區別。

許多函式(尤其是 函式)只是獲取一個物件並返回一些物件。一個就地函式修改現有的物件,其被稱為副作用。其他示例包括輸入和輸出操作,例如列印。

list.sort() 對列表進行排序 (意味著它修改了原始列表)並返回值 None。因此,它在列表理解中不會按預期工作:

[x.sort() for x in [[2, 1], [4, 3], [0, 1]]]
# [None, None, None]

相反, sorted() 返回一個已排序的 list 而不是就地排序:

[sorted(x) for x in [[2, 1], [4, 3], [0, 1]]]
# [[1, 2], [3, 4], [0, 1]]

可以使用對副作用的理解,例如 I / O 或就地功能。然而 for 迴圈通常更具可讀性。雖然這適用於 Python 3:

[print(x) for x in (1, 2, 3)]

而是使用:

for x in (1, 2, 3):
    print(x)

在某些情況下,副作用功能適合列表理解。 random.randrange() 具有改變隨機數生成器狀態的副作用,但它也返回一個有趣的值。另外,可以在迭代器上呼叫 next()

以下隨機值生成器不是純粹的,但有意義,因為每次計算表示式時都會重置隨機生成器:

from random import randrange
[randrange(1, 7) for _ in range(10)]
# [2, 3, 2, 1, 1, 5, 2, 4, 3, 5]

列表理解中的空白

更復雜的列表推導可能達到不期望的長度,或者變得不那麼可讀。雖然在示例中不太常見,但可以將列表理解分成多行,如下所示:

[
    x for x
    in 'foo'
    if x not in 'bar'
]