重构过滤器并映射到列表推导

filtermap 函数通常应该由列表推导替换。Guido Van Rossum 在 2005 年的一封公开信中描述了这一点 :

filter(P, S) 几乎总是像 [x for x in S if P(x)] 一样更加清晰,这有一个巨大的优势,即最常见的用法涉及比较的谓词,例如 x==42,并且定义一个 lambda,这对读者来说需要更多的努力(加上 lambda 比列表理解)。对于 map(F, S) 来说更是如此。当然,在许多情况下,你可以使用生成器表达式。

以下代码行被认为是“ 非 pythonic ”,并且会在许多 python linters 中引发错误。

filter(lambda x: x % 2 == 0, range(10)) # even numbers < 10
map(lambda x: 2*x, range(10)) # multiply each number by two
reduce(lambda x,y: x+y, range(10)) # sum of all elements in list

根据我们从前面的引文中学到的东西,我们可以将这些 filtermap 表达式分解为它们的等效列表推导 ; 还从每个函数中删除 lambda 函数 - 使代码在此过程中更具可读性。

# Filter:
# P(x) = x % 2 == 0
# S = range(10)
[x for x in range(10) if x % 2 == 0]

# Map
# F(x) = 2*x
# S = range(10)
[2*x for x in range(10)]

在处理链接函数时,可读性变得更加明显。由于可读性,一个映射或过滤函数的结果应该作为结果传递给下一个; 在简单的情况下,这些可以用单个列表理解来代替。此外,我们可以很容易地从列表中了解我们的过程的结果是什么,在推断链式 Map 和 Filter 过程时有更多的认知负荷。

# Map & Filter
filtered = filter(lambda x: x % 2 == 0, range(10))
results = map(lambda x: 2*x, filtered)

# List comprehension
results = [2*x for x in range(10) if x % 2 == 0]

重构 - 快速参考

  • 地图

    map(F, S) == [F(x) for x in S]
    
  • 过滤

    filter(P, S) == [x for x in S if P(x)]
    

其中 FP 是分别转换输入值并返回 bool 的函数