and
和or
返回他们评估的最后一个元素,但为什么不是Python的内置函数any
?
我的意思是这样实现自己很容易,但我仍然想知道为什么。
def any(l):
for x in l:
if x:
return x
return x
编辑:
要添加到下面的答案,这里是你们强大的皇帝在同一个邮件列表中的实际引用:
是否总是返回True和False或第一个faling / passing元素?在博客之前我也玩过它,并且意识到最终的情况(如果序列是空的或者所有元素都没有通过测试)永远不能令人满意:如果参数是可迭代的bool,则选择None感觉很奇怪,并且如果参数是非bool对象的可迭代,那么选择False会感觉很奇怪。
Guido van Rossum(主页:http://www.python.org/~guido/)
这个问题出现在2005年Python开发人员的邮件列表中,当时Guido Van Rossum建议将any
和all
添加到Python 2.5中。
Bill Janssen requested认为他们被实施为
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]
Raymond Hettinger,他实施了any
和all
,responded专门解释了为什么any
和all
不像and
和or
那样:
随着时间的推移,我得到了关于这些和其他itertools食谱的反馈。没有人反对这些食谱或Guido版本中的真/假返回值。
Guido的版本符合任何/所有谓词的正常期望。此外,它避免了人们目前使用Python的“和”和“或”的独特实现所遇到的错误/混淆。
归还最后一个元素并不邪恶;它只是奇怪的,意外的,非显而易见的。抵制这个变得棘手的冲动。
邮件列表在很大程度上是同意的,只留下今天看到的实现。
and
和or
可以通过他们总是返回其中一个操作数的方式明智地定义。但是,any
和all
无法明确地定义为从输入序列返回一个值:具体来说,当列表为空时,它们不能这样做。在这种情况下,any
和all
目前都有明确定义的结果:any
返回False,all
返回True。您将被迫有时返回一个布尔值,有时会从序列返回一个项目,这会产生令人不快和令人惊讶的界面。简单而一致的好多了。
我问同样的问题on python-ideas,并被告知原因是any()
和all()
需要在序列为空时返回一个值,这些值必须是False
和True
。这对我来说似乎是一个微弱的争论。
这些函数现在不能改变,但我认为它们会更有用,并且如果它们返回了他们遇到的第一个真正的或者虚假的值,那么它们推广的and
和or
运算符的更好的类比。
由于历史原因,and
和or
的行为存在。
在Python有三元运算/条件表达式之前,如果要在条件上使用值,则使用and
和or
。可以使用条件表达式语法重写任何此类表达式:
true_val if condition else false_val
从本质上讲,它们有两个功能,并且由于兼容性原因,它们没有被更改。
这不是使其他操作超负荷的原因。 any
似乎应该告诉你条件对于任何项是否为真,这是一个布尔值,所以它应该返回一个bool
。
启动Python 3.8
,并引入assignment expressions (PEP 572)(:=
算子),我们可以明确地捕获any
表达式的证人或all
表达式的反例:
引用PEP description的几个例子:
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)
显而易见,any
的值可能是False或输入中的一个值。此外,大多数用途看起来像
tmp = any(iterable)
if tmp:
tmp.doSomething()
else:
raise ValueError('Did not find anything')
这是Look Before You Leap因此unpythonic。相比于:
next(i for i in iterable if i).doSomething()
# raises StopIteration if no value is true
and
和or
的行为在历史上可用作当时不可用的条件表达式的插入。
Any
返回一个布尔值,因为它有效地将其参数视为bool列表,然后再考虑它们是否为真。它返回它评估的元素,但这恰好是一个bool。
您想什么时候使用您的any
版本?如果它在bool列表中,那么你已经有了正确的答案。否则你只是在防范None
,可能表达为:
filter(lambda x: x != None, l)[0]
要么:
[x for x in l if x != None][0]
这是一个更明确的意图陈述。