列表理解
一个列表解析创建通过将表达成的每个元素的新 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'
]