列表理解
一個列表解析建立通過將表達成的每個元素的新 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 in
range(3)for x in
foo(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'
]