列表理解list通过将表达式应用于可迭代的每个元素来创建新的列表。最基本的形式是:
[ <expression> for <element> in <iterable> ]
还有一个可选的“如果”条件:
[ <expression> for <element> in <iterable> if <condition> ]
每个<element>在<iterable>已插入到<expression>如果(可选的)<condition>评估为true。所有结果将立即返回到新列表中。生成器表达式的计算是延迟的,但是列表推导会立即评估整个迭代器-消耗的内存与迭代器的长度成正比。
要创建list平方整数:
squares = [x * x for x in (1, 2, 3, 4)] # 正方形:[1、4、9、16]
的for表达式设置x,以依次从每个值(1, 2, 3, 4)。表达式的结果x * x被附加到一个internal list。完成后,将内部list变量分配给变量squares。
除了提高速度(如此处所述)外,列表理解还大致等同于以下for循环:
squares = [] for x in (1, 2, 3, 4): squares.append(x * x) # 正方形:[1、4、9、16]
应用于每个元素的表达式可以根据需要复杂:
# 从字符串获取大写字符列表 [s.upper() for s in "Hello World"] # ['你好,世界'] # 从列表中的字符串末尾去除所有逗号 [w.strip(',') for w in ['these,', 'words,,', 'mostly', 'have,commas,']] # [“这些”,“单词”,“大部分”,“有逗号”] # 以字母顺序更合理地组织单词中的字母 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循环之前使用,而不要在循环之后使用:
# 在苹果中创建字符列表,用“ *”代替非元音 # Ex - 'apple' --> ['a', '*', '*', '*' ,'e'] [x for x in 'apple' if x in 'aeiou' else '*'] #SyntaxError:语法无效 # 当同时使用if / else时,请在循环前使用它们 [x if x in 'aeiou' else '*' for x in 'apple'] #['a','*','*','*','e']
请注意,这使用了一种不同的语言构造,即条件表达式,它本身不是理解语法的一部分。而ifafterfor…in 是列表理解的一部分,用于从可迭代的源中筛选元素。
两次迭代的顺序[... 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)]
在使用列表推导之前,请了解通常会返回的函数(其副作用为mutating或就地函数)None与返回有趣值的函数之间的区别。
许多函数(尤其是纯函数)仅获取一个对象并返回某个对象。一个就地函数修改现有的对象,其被称为副作用。其他示例包括输入和输出操作,例如打印。
list.sort()就地对列表进行排序(意味着它会修改原始列表)并返回value None。因此,它在列表理解中将无法正常工作:
[x.sort() for x in [[2, 1], [4, 3], [0, 1]]] # [无,无,无]
而是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,1,5,2,4,3,5]
更复杂的列表理解可能会达到不希望的长度,或者变得难以理解。尽管在示例中不太常见,但可以将列表理解分为多行,如下所示:
[ x for x in 'foo' if x not in 'bar' ]