是否有更 pythonic 的方法来执行以下代码?我想在一行中完成
parsed_rows 是一个可以返回大小为 3 或 None 的元组的函数。
parsed_rows = [ parse_row(tr) for tr in tr_els ]
data = [ x for x in parsed_rows if x is not None ]
最佳答案
在一行中执行此操作不会使它更像 Pythonic;它会使它的可读性降低。如果你真的想要,你总是可以通过这样的替换直接翻译它:
data = [x for x in [parse_row(tr) for tr in tr_els] if x is not None]
…这显然可以像《雪之门 Handlebars 》中显示的那样被压扁,但仍然难以理解。然而,他没有完全理解:子句从左到右嵌套,你希望 x
是每个 parse_row
结果,而不是每个 的每个元素parse_row
结果(如 Volatility 指出的那样),因此扁平化版本将是:
data = [x for tr in tr_els for x in (parse_row(tr),) if x is not None]
我认为,一个优秀的开发人员在任何人意识到问题之前将其倒退并有 6 人投票支持,然后我错过了第二个问题并且在任何人发现它之前又有 7 人投票支持,这是非常可靠的证据不像 Doorknob 所说的那样更加 pythonic 或更具可读性。 :)
一般来说,当面对一个嵌套的 comp 或一个带有多个 for
子句的 comp 时,如果它的作用不是很明显,你应该将它翻译成嵌套的 for
> 和 if
语句与最内层的 append
表达式语句,如 the tutorial 所示.但是,如果您需要通过您正在尝试编写的理解来做到这一点,那么这是一个很好的迹象,您不应该尝试编写它......
但是, 有一种方法可以使它更像 Pythonic,也更高效:将第一个列表理解更改为生成器表达式,如下所示:
parsed_rows = (parse_row(tr) for tr in tr_els)
data = [x for x in parsed_rows if x is not None]
我所做的只是将方括号更改为圆括号,这足以延迟计算第一个,在每个 tr
上调用 parse_row
根据需要,而不是在所有行上调用它,并在您开始实际工作之前在内存中构建一个您实际上不需要的列表。
事实上,如果您需要 data
的唯一原因是对其进行一次迭代(或将其转换为其他形式,如 CSV 文件或 NumPy 数组),您可以这样做还有一个生成器表达式。
或者,更好的是,将列表理解替换为 map
称呼。当您的表达式只是“在每个元素上调用此函数”时,map
通常更具可读性(而当您必须编写一个新函数,尤其是使用 lambda
时,只是为了包装一些更复杂的表达式,通常不是)。所以:
parsed_rows = map(parse_row, tr_els)
data = [x for x in parsed_rows if x is not None]
现在它实际上是可读的:
data = [x for x in map(parse_row, tr_els) if x is not None]
您可以类似地将第二个理解转换为 filter
称呼。然而,就像 map
一样,如果谓词不仅仅是“调用这个函数并查看它是否返回真实的东西”,它通常最终会变得可读性降低。在这种情况下:
data = filter(lambda x: x is not None, map(parse_row, tr_els))
但是请注意,您真的不需要首先检查 is not None
。您拥有的唯一非 None
值是 3 元组,它们始终为真。因此,您可以将 if x is not None
替换为 if x
,这可以简化您的理解:
data = [x for x in map(parse_row, tr_else) if x]
... 并且可以使用 filter
以两种不同的方式编写:
data = filter(bool, map(parse_row, tr_els))
data = filter(None, map(parse_row, tr_els))
询问这两者中哪一个更好将在任何 Python 列表上引发一场宗教 war ,所以我只展示它们并让您决定。
请注意,如果您使用的是 Python 2.x,map
不是惰性的;它将生成整个中间列表。所以,如果您想两全其美,又不能使用 Python 3,请使用 itertools.imap
而不是 map
。同样,在 3.x 中,filter
是惰性的,所以如果你想要一个列表,请使用 list(filter(…))
.
关于列表理解中函数的 Pythonic 改进?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20692637/