Gin*_*ger 2 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 ]
Run Code Online (Sandbox Code Playgroud)
在一行中执行此操作不会使它更像Pythonic; 它会降低可读性.如果你真的想要,你总是可以通过这样的替换直接翻译它:
data = [x for x in [parse_row(tr) for tr in tr_els] if x is not None]
Run Code Online (Sandbox Code Playgroud)
......显然可以像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]
Run Code Online (Sandbox Code Playgroud)
我认为一个优秀的开发人员让它落后并且在有人意识到这个问题之前有6个人支持它的事实,然后我错过了第二个问题,并且在有人抓住它之前又有7个人投票,这是非常可靠的证明,这不是更多pythonic或者更具可读性,就像Doorknob说的那样.:)
在一般情况下,当面对任何一个嵌套补偿或倍数的补偿for条款,如果不是立即明显它做什么,你应该把它翻译成嵌套for并if与最里面的语句append表达式语句,如图教程.但是如果你需要用你正在尝试写的理解来做到这一点,这是一个很好的迹象,你不应该写它...
但是,是一种方法,使这个更Python,同时也更高效:更改第一个列表中理解到发电机的表情,就像这样:
parsed_rows = (parse_row(tr) for tr in tr_els)
data = [x for x in parsed_rows if x is not None]
Run Code Online (Sandbox Code Playgroud)
我所做的只是将方括号更改为括号,这足以懒惰地计算第一个,根据需要调用parse_row每个tr,而不是在所有行上调用它,并在内存中构建一个实际上不实际的列表需要,在你开始真正的工作之前.
事实上,如果您需要的唯一原因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]
Run Code Online (Sandbox Code Playgroud)
现在它实际上是可读的sub in:
data = [x for x in map(parse_row, tr_els) if x is not None]
Run Code Online (Sandbox Code Playgroud)
您可以类似地将第二种理解转变为filter呼叫.然而,正如同样map,如果谓词不仅仅是"调用此函数并查看它是否返回真正的东西",它通常最终会降低可读性.在这种情况下:
data = filter(lambda x: x is not None, map(parse_row, tr_els))
Run Code Online (Sandbox Code Playgroud)
但请注意,您确实不需要首先检查is not None.None你拥有的唯一非值是3元组,它总是真实的.所以,你可以替换if x is not Nonewith if x,这可以简化你的理解:
data = [x for x in map(parse_row, tr_else) if x]
Run Code Online (Sandbox Code Playgroud)
......可以用两种不同的方式编写filter:
data = filter(bool, map(parse_row, tr_els))
data = filter(None, map(parse_row, tr_els))
Run Code Online (Sandbox Code Playgroud)
问这两个中哪一个更好会在任何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]
Run Code Online (Sandbox Code Playgroud)
(此外,@ Volatility指出,如果parse_row(tr)是None,这将产生错误,可以这样解决:
data = [x for tr in tr_els for x in (parse_row(tr),) if x is not None]
Run Code Online (Sandbox Code Playgroud)
)
但是,在我看来,这个可读性要低得多.更短并不总是更好.