繁体   English   中英

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

[英]Pythonic Improvement Of Function In 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 ] 

在一行中执行此操作不会使它更像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结果(如波动率所指出的),所以扁平版本将是:

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

我认为一个优秀的开发人员让它落后并且在有人意识到这个问题之前有6个人支持它的事实,然后我错过了第二个问题,并且在有人抓住它之前又有7个人投票,这是非常可靠的证明,这不是更多pythonic或者更具可读性,就像Doorknob说的那样。 :)

通常,当面对嵌套的comp或带有多个for子句的comp时,如果它不能立即明白它的作用,则应将其转换为嵌套的forif语句,并使用最内层的append表达式语句,如教程中所示。 但是如果你需要用你正在尝试写的理解来做到这一点,这是一个很好的迹象,你不应该写它...


然而,有一种方法可以让这个更Python,同时也更高效:更改第一个列表中理解到发电机的表情,就像这样:

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]

现在它实际上可读的sub in:

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 Noneif 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列表上发起一场宗教战争,所以我只是提出它们并让你决定。


请注意,如果您使用的是Python 2.x,则map不是懒惰的; 它将生成整个中间列表。 因此,如果您想要充分利用这两个世界,并且不能使用Python 3,请使用itertools.imap而不是map 同样,在3.x中, filter 惰性的,所以如果你想要一个列表,请使用list(filter(…))

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

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]

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM