短路列表理解

时间:2013-06-05 03:47:41

标签: python list-comprehension generator-expression

有几次我想要python语法来缩短列表推导或生成器表达式。

这是一个简单的列表推导,以及python中循环的等价物:

my_list = [1, 2, 3, 'potato', 4, 5]
[x for x in my_list if x != 'potato']

result = []
for element in my_list:
    if element != 'potato':
        result.append(element)

在语言中不支持理解短路。提出的语法,以及python中循环的等价物:

[x for x in my_list while x != 'potato']
# --> [1, 2, 3]

result = []
for element in my_list:
    if element != 'potato':
        result.append(element)
    else:
        break

它应该适用于任意迭代,包括无限序列,并且可以扩展到生成器表达式语法。我知道list(itertools.takewhile(lambda x: x != 'potato'), my_list)是一个选项,但是:

  • 它不是特别pythonic - 不像一段时间的理解那样可读
  • 它可能不如CPython理解那样高效或快速
  • 它需要一个额外的步骤来转换输出,而这可以直接理解,例如, [x.lower() for x in mylist]
  • 甚至是original author doesn't seem to like it much

我的问题是,是否有任何理论上的皱纹为什么将语法扩展到这个用例并不是一个好主意,或者它是不可能的因为python dev认为它很少有用?它似乎是对语言的简单补充,也是一个有用的功能,但我可能会忽略一些隐藏的细微之处或并发症。

相关:thisthis

1 个答案:

答案 0 :(得分:6)

正如@Paul McGuire指出的那样,它是由Guido在PEP 3142rejected中提出的:

  

我不知道有一个PEP。我在此拒绝。没有意义   浪费更多时间。

但是,他没有给出解释。在邮件列表中,反对它的一些要点是:

  • “[理解]是在多个嵌套语句和单个表达式之间精心设计的1对1转换。但是这个提议忽略并打破了它。(here)。”也就是说,while关键字与显式循环中的while不对应 - 它只是break
  • “这使得Python更难学习,因为它增加了一些东西需要学习。” (引用here
  • 它增加了生成器表达式和列表理解之间的另一个区别。似乎将此语法添加到列表理解中似乎也是绝对不可能的。

我认为与通常的列表理解的一个基本区别是while本质上是命令性的,而不是声明性的。它取决于并指示执行的顺序,而语言(AFAIK)无法保证。我想这就是它不包含在Haskell的理解中的原因,python从中理解了这个想法。

当然,生成器表达式确实有方向,但它们的元素可能是预先计算的 - 再次,AFAIK。提到的PEP确实建议用于生成器表达式 - 这是有道理的。

当然,Python 无论如何都是一种命令式语言,但它会引发问题。

选择一个无序的集合怎么样?

[x for x in {1,2,3} while x!=2]

你也没有在简单的for循环中使用它,但这是你无法用语言强制执行的东西。 takewhile回答了这个问题,但这是一个随意的答案。


最后一点,请注意,为了保持一致性,您需要支持dropwhile

之类的东西
[x for x in my_list from x != 'potato']

与等效for构造的关系更少,如果my_list只是可迭代的话,这次不可能短路。