Pythonic改进列表理解中的功能?

时间:2013-12-19 22:08:16

标签: python list-comprehension

有更多pythonic方式来执行以下代码吗?我想在一行中做到这一点

parsed_rows是一个可以返回大小为3或无的元组的函数。

parsed_rows = [ parse_row(tr) for tr in tr_els ]        
data        = [ x for x in parsed_rows if x is not None ] 

2 个答案:

答案 0 :(得分:8)

在一行中执行此操作不会使它更像Pythonic;它会降低可读性。如果你真的想要,你总是可以通过这样的替换直接翻译它:

data = [x for x in [parse_row(tr) for tr in tr_els] if x is not None] 

......显然可以像Doorknob of Snow一样扁平化,但它仍然很难理解。但是,他没有说得对:条款从左到右嵌套,你希望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和{{1}具有最内层if表达式语句的语句,如the tutorial中所示。但是如果你需要通过你想要写的理解来做到这一点,这是一个非常好的迹象,你不应该写它...


然而, 是一种使这更像Pythonic的方法,也更有效:将第一个列表理解改为生成器表达式,如下所示:

append

我所做的只是将方括号更改为括号,这足以计算第一个懒惰,在每个parsed_rows = (parse_row(tr) for tr in tr_els) data = [x for x in parsed_rows if x is not None] 根据需要调用parse_row,而不是调用在你开始真正的工作之前,它在所有行上,并在内存中建立一个你实际上并不需要的列表。

事实上,如果你需要tr的唯一原因是迭代一次(或将其转换为其他形式,如CSV文件或NumPy数组),你可以使它成为一个生成器表达式同样。


或者更好的是,用map调用替换列表推导。当你的表达式只是“在每个元素上调用这个函数”时,data通常更具可读性(而当你必须编写一个新函数时,尤其是map时),只需要包含一些更复杂的表达式,通常不是)。所以:

lambda

现在它实际上 对sub in:

可读
parsed_rows = map(parse_row, tr_els)
data = [x for x in parsed_rows if x is not None]

您可以类似地将第二次理解转变为filter来电。但是,就像使用data = [x for x in map(parse_row, tr_els) if x is not None] 一样,如果谓词不仅仅是“调用此函数并查看它是否返回真正的东西”,它通常最终会降低可读性。在这种情况下:

map

但请注意,您确实不需要首先检查data = filter(lambda x: x is not None, map(parse_row, tr_els)) 。您拥有的唯一非is not None值是3元组,它们总是真实的。因此,您可以将None替换为if x is not None,这可以简化您的理解:

if x

...可以使用data = [x for x in map(parse_row, tr_else) if x] 以两种不同的方式编写:

filter

询问这两个中哪一个更好会在任何Python列表上发起一场宗教战争,所以我只是展示它们并让你决定。


请注意,如果您使用的是Python 2.x,data = filter(bool, map(parse_row, tr_els)) data = filter(None, map(parse_row, tr_els)) 并不是懒惰的;它将生成整个中间列表。因此,如果您想要充分利用这两个世界,并且不能使用Python 3,请使用map而不是itertools.imap。以同样的方式,在3.x中,map 是懒惰的,因此如果您需要列表,请使用filter

答案 1 :(得分:5)

你可以将一个嵌套在另一个中:

data = [x for tr in tr_els for x in parse_row(tr) if x is not None]

(另外,@ Volatility指出如果parse_row(tr)None,这会产生错误,可以这样解决:

data = [x for tr in tr_els for x in (parse_row(tr),) if x is not None]

然而,在我看来,这个可读性要低得多。更短并不总是更好。