49

andor返回他们评估的最后一个元素,但为什么 Python 的内置函数不any呢?

我的意思是这样实现自己很容易,但我仍然想知道为什么。

def any(l):
    for x in l:
        if x:
            return x
    return x

编辑:

要添加到下面的答案,这里是来自同一个邮件列表的实际引用 ye 强大的皇帝在这个问题上:

是否始终返回 True 和 False 或第一个失败/传递元素?我在写博客之前也玩过这个,并意识到最终情况(如果序列为空或所有元素都未通过测试)永远无法令人满意地工作:如果参数是布尔值的可迭代,则选择 None 感觉很奇怪,并且如果参数是非布尔对象的可迭代对象,则选择 False 感觉很奇怪。

Guido van Rossum(主页: http: //www.python.org/~guido/

4

7 回答 7

48

这个问题在 2005 年出现在 Python 开发人员的邮件列表中,当时 Guido Van Rossum 提议将any和添加all到 Python 2.5。

Bill Janssen要求将它们实施为

def any(S):
    for x in S:
        if x:
            return x
    return S[-1]

def all(S):
    for x in S:
        if not x:
            return x
    return S[-1]

any实施andall的Raymond Hettinger专门回应了为什么anyall不表现得像andand or

随着时间的推移,我收到了关于这些和其他 itertools 食谱的反馈。没有人反对这些食谱或 Guido 版本中的 True/False 返回值。

Guido 的版本符合任何/所有作为谓词的正常期望。此外,它避免了人们目前在使用 Python 的“and”和“or”的独特实现时遇到的那种错误/困惑。

返回最后一个元素并不邪恶;这很奇怪,出乎意料,而且不明显。克制住把这个变得棘手的冲动。

邮件列表在很大程度上同意了,留下了你今天看到的实现。

于 2012-04-16T19:56:51.577 回答
22

and并且or可以合理地定义为它们总是返回它们的一个操作数。但是,any不能all明智地将其定义为始终从其输入序列中返回一个值:特别是当列表为空时,它们不能这样做。在这种情况下,两者anyall当前都有一个明确定义的结果:any返回 False 并all返回 True。您有时会被迫返回一个布尔值,有时会从序列中返回一个项目,这会产生令人不快且令人惊讶的界面。简单和一致要好得多。

于 2012-04-16T19:41:07.227 回答
11

开始Python 3.8,并引入赋值表达式(PEP 572):=运算符),我们可以交替地显式捕获表达式的见证any或表达式的all


引用PEP 描述中的几个例子:

if any(len(long_line := line) >= 100 for line in lines):
  print("Extremely long line:", long_line)
if all((nonblank := line).strip() == '' for line in lines):
  print("All lines are blank")
else:
  print("First non-blank line:", nonblank)
于 2019-04-28T10:18:22.853 回答
5

我在 python-ideas 上问了同样的问题,并被告知原因是any()andall()需要在序列为空时返回一个值,并且这些值必须是Falseand True。对我来说,这似乎是一个软弱的论据。

这些函数现在不能改变,但我认为如果它们返回他们遇到的第一个真值或假值,它们会更有用,更好地模拟它们概括的and和运算符。or

于 2012-04-16T19:37:48.790 回答
3

的行为andor存在的历史原因。

在 Python 有三元运算/条件表达式之前,and如果or你想在条件上使用值,你就使用过。任何这样的表达式都可以用条件表达式语法重写:

true_val if condition else false_val

本质上,它们重载了两个函数,出于兼容性原因,它们没有被更改。

不是重载其他操作的理由。any似乎它应该告诉您任何 item 的条件是否为真,它是一个布尔值,所以它应该返回一个bool.

于 2012-04-16T19:40:07.700 回答
0

Any返回一个布尔值,因为它在考虑其中任何一个是否为真之前有效地将其参数视为布尔列表。它正在返回它评估的元素,但这恰好是一个布尔值。

你想什么时候使用你的版本any?如果它在布尔列表中,那么您已经有了正确的答案。否则,您只是在防备None,可能会表示为:

filter(lambda x: x != None, l)[0]

或者:

[x for x in l if x != None][0]

这是一个更清晰的意图陈述。

于 2012-04-16T19:31:17.437 回答
0

any' 的值可能是 False 或输入中的值之一并不是很明显。此外,大多数用途看起来像

tmp = any(iterable)
if tmp:
   tmp.doSomething()
else:
   raise ValueError('Did not find anything')

那是在你跳跃之前先看一下,因此是不合情理的。相比于:

next(i for i in iterable if i).doSomething()
# raises StopIteration if no value is true

and和的行为or在历史上作为当时不可用的条件表达式的插入项很有用。

于 2012-04-16T19:34:36.617 回答