8

在某些情况下,我想要 python 语法用于短路列表理解或生成器表达式。

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

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 中的等效 for 循环:

[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 - 不像while理解那样可读
  • 它可能不如 CPython 理解那么高效或快速
  • 它需要一个额外的步骤来转换输出,而这可以直接放入理解中,例如[x.lower() for x in mylist]
  • 原作者都不太喜欢

我的问题是,对于为什么将语法扩展到这个用例不是一个好主意,是否存在任何理论上的问题,或者它只是不可能,因为 python 开发人员认为它很少有用?这似乎是对语言的简单补充,也是一个有用的功能,但我可能忽略了一些隐藏的微妙之处或复杂性。

相关: 这个这个

4

1 回答 1

7

事实证明,正如@Paul McGuire 所指出的,它已在PEP 3142中提出并被Guido拒绝:

我不知道有一个PEP。我特此拒绝。没有必要在上面浪费更多时间。

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

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

我认为与通常的列表理解的一个基本区别是它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

于 2013-06-05T04:21:47.680 回答