繁体   English   中英

Python list-comprehensions中的lisp风格的`let`语法

[英]lisp-style style `let` syntax in Python list-comprehensions

请考虑以下代码:

>>> colprint([
        (name, versions[name][0].summary or '')
        for name in sorted(versions.keys())
    ])

此代码的作用是keys升序打印字典versions的元素,但由于该value是另一个排序列表,因此仅打印其第一个元素的摘要(“max”)。

由于我所熟悉的let从口齿不清,我重写了上面:

>>> colprint([
        (name, package.summary or '')
        for name in sorted(versions.keys())
        for package in [versions[name][0]]
    )]

你认为这违反了Pythonic吗? 可以改进吗?

注意:对于好奇, colprint 在这里定义。

为什么不利用元组?

colprint([(name, version[0].summary or '')
      for (name, version) in sorted(versions.iteritems())])

甚至

colprint(sorted([(name, version[0].summary or '')
             for (name, version) in versions.iteritems()]))

此外,您可以考虑(在我的第一个示例中)删除[] s,因为这样您获得生成器而不是列表(可能有用也可能没用,因为我猜这将打印整个数组,所以你不会保存任何评估)。

在大多数情况下,我不会使用“棘手的条款”(或“let-equivalent”),但如果这是避免重复的自然方式,尤其是代价高昂的重复,我会这样做。 例如

xs = [(y, y*1.2, y-3.4) for z in zs for y in [somefun(z)] ]

对我来说看起来好多于三次调用somefun ! - )所以,值得记住,即使可能不值得使用它不会消除重复。

所以你使用“for y in [y]”代替“let xy”。

尝试用另一种语言模拟语言的语法绝不是一个好主意。 我认为原始版本更清晰。

正如Tordek所说,在这种情况下你可以使用items()iteritems()来避免这个问题:

colprint(sorted((name, packages[0].summary or '')
                for (name, packages) in versions.items()))

将分拣移到外面是个不错的选择。

[注意, items()的使用稍微改变了排序顺序 - 它曾经是名称,并且按原始顺序解决了绑定(Python排序是稳定的),现在它的名称是通过摘要解析的绑定。 由于dict的原始顺序是随机的,新行为可能更好。]

但是对于其他用途(例如Alex Martelli的例子),“let”-alike可能仍然有用。 我也曾经for var in [value]技巧中发现了for var in [value] ,但我现在发现它很难看。 更清晰的替代方案可能是理解/生成器的“管道”,使用“装饰/未装饰”技巧来传递元组中的附加值:

# You could write this with keys() or items() - 
# I'm just trying to examplify the pipeline technique.
names_packages = ((name, versions[name][0]) 
                  for name in versions.keys())

names_summaries = ((name, package.summary or '')
                   for (name, package) in names_packages)

colprint(sorted(names_summaries))

或者应用于Alex的例子:

ys = (somefun(z) for z in zs)
xs = [(y, y*1.2, y-3.4) for y in ys]

(您甚至不需要原始z值,因此中间值不必是元组。)

有关“管道”技术的更多强大示例,请访问http://www.dabeaz.com/generators/

您可以将排序移动到最后以避免某些中间列表。

这看起来好一点我想:

colprint(sorted(
        (name, version[0].summary or '')
        for (name,version) in versions.iteritems())
    ))

Python3可以做得更好:

colprint(sorted(
        (name, first_version.summary or '')
        for (name,(first_version,*_)) in versions.items())
    ))

暂无
暂无

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

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