列表理解

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