在列表表达式中避免使用超过两个的表达式


多层循环

排除基础的用法(详见第7项:使用列表表达式而不是map或者filter),列表表达式也支持多层循环。例如:你想简化一个矩阵(也就是一个列表内是一些其他的列表)到一个大列表中。这里,作者通过内嵌两个表达式成功实现。表达式运行的顺序是由左至右。

matrix = [[1, 2, 3],[4, 5, 6],[7, 8, 9]]
flat = [x for row in matrix for x in row]
print(flat)

[ 1, 2, 3, 4, 5, 6, 7, 8, 9]

上面的例子简单,可读而且是条理清晰的多层循环。另一个关于多层循环的合理使用是对于如此两层输入列表的复制。例如你想计算一个两维矩阵的每一个位置上数的平方,虽然这个表达式看起来会因为空列表([])的存在略显杂乱,但是代码的可读性却得到了提高。

squared = [[ x**2 for x in row] for row in matrix]
print(squared)
>>>
[[1, 4, 9],[16, 25, 36],[49, 64, 81]]

如果这个表达式包含另外的一个循环体,此列表表达式将变得特别的长以至于你不得不将其分割成多行,来保持代码的可读性。

my_lists = [
    [[1, 2, 3],[4, 5, 6]],
    # ...
]
flat = [ x for sublist in my_lists
          for sublist2 in sublist
          for x in sublist2]

print(flat)

从这点来看,多行的列表表达式并不比替代方案少多少代码。这里,作者更加的建议使用正常的循环体语句。因为其比列表表达式更简洁好看一点,也更加易读,易懂。

flat = []
for sublist in my_lists:
    for sublist2 in sublist:
        flat.append(sublist2)

列表表达式同样支持if条件语句。多个条件语句出现在相同的循环水平中也是一个隐式&的表达,即同时成立才成立。例如:你只想获得列表中大于4且是偶数的值。那么下面的两个列表表达式是等价的。

a = [1,2,3,4,5,6,7,8,9,10]
b = [x for x in a if x> 4 if x%2 ==0]
c = [x for x in a if x > 4 and if x%2 ==0]

条件语句可以被很明确的添加在每一层循环的for表达式的后面,起到过滤的作用。例如:你想过滤出每行总和大于10且能被3正处的元素。虽然用列表表达式表示出这段代码很短,但是其可读性确实很糟糕。

matrix = [[ 1, 2, 3],[ 4, 5, 6],[ 7, 8, 9]]
filtered = [[x for x in row if x%3==0]
            for row in matrix if sum(row) >= 10 ]
print(filtered)
>>>
[[6],[9]]

可能你会感觉上面的例子有些费解,不过在实践中你将能看到更多列表表达式完美工作的情形。我强烈的建议你在遇到以下情形的时候避免使用列表表达式。那就是代码对别人来说难于理解;通过使用列表表达式来减少的代码行数不足以胜过其即将带来的麻烦时,请不要使用列表表达式。

拇指规则是指在一个列表表达式中避免使用超过两个的表达式。这些表达式可以是条件语句,循环语句,或者一个判断一个循环。只要事情变得比这种情况还要复杂,就不应该使用列表表达式了。 而是应该使用常规的语句来实现相同的业务逻辑。(详见第16项:考虑生成式而不是返回列表)


备忘录

  • 列表表达式支持多层的循环和条件语句,以及每层循环内部的条件语句。
  • 当列表表达式内部多余两个表达式的时候就会变得难于阅读,这种写法应该避免使用。

results matching ""

    No results matching ""