Python中是否有`and`和`or`的内置函数版本?

14

这个问题只是为了好玩,我并不指望得到有用的答案。

当我看到人们在Python中使用reduce()时,他们通常会利用Python内置函数,通常来自operator模块。

这样做是有效的:

result = reduce(lambda a, b: a + b, range(5))

但通常你会看到这样:

from operator import add
result = reduce(add, range(5))

对我来说奇怪的是,operator 模块似乎没有逻辑 and 的函数。它确实有位运算和,但没有逻辑 and

因此,假设你正在做这个:

result = reduce(lambda a, b: a and b, range(1, 6))

这里是否有一个内置函数可供使用?

我还想知道是否有一个内置函数可以替换or

如果首先将参数映射为布尔值,您可以使用来自operator的按位与,或者直接使用bool.__and__,像这样:

from operator import and_
result = reduce(and_, map(bool, range(1, 6)))
result = reduce(bool.__and__, map(bool, range(1, 6)))

同样也可以使用operator.or_()bool.__or__进行or操作。但我正在寻找一种不需要将值映射为布尔值的函数。

如果你确定你的值都是整数,你可以使用operator.mul进行and操作,使用operator.add进行or操作。但这只是个粗略的hack方法,我不想要这个答案……特别是当遇到许多数字且它们都不是零时,乘法会变得非常耗费资源!

注意:我知道all()any(),它们是对reduce()更好的替代品。如我在前面所说,我只是出于兴趣而问这个问题。

注意:一个有副作用的函数,可以强制所有值转换为bool,这也是一个可接受的答案。内置的and关键字并不具备这个功能:

x = 3 and 5  # sets x to 5, not to True

但是对于这个问题,我只关心一个能够与reduce()一起使用来执行逻辑andor操作的函数。


1
你可以使用any((a, b))来代替a or b,用all((a, b))来代替a and b。当然,这样你得要创建元组,并且没有短路功能... - kindall
1
x = 3 and 5x 设为 5,但你也可以将其转换为布尔值,那么为什么不这样做呢?重点是无论你尝试在哪个逻辑表达式中评估 x,它都会被解释为布尔值。 - whatyouhide
1
@steveha 很好的问题。我希望你能得到答案,但看起来你已经在你的回答中尝试了每一个可能的替代方案。 - jamylak
2
@jamylak 或许有人应该提议将 botheither 添加到 operator 模块中,作为按位 and_or_ 的逻辑对应物。 - Mark Ransom
1
@NeilG,有没有一个函数工厂可以包装一个函数和两个参数来生成一个函数和一个元组?如果有的话,那将成为问题的答案。我喜欢你提出的让anyall接受多个参数的建议,它们完全可以像minmax一样工作。 - Mark Ransom
显示剩余6条评论
3个回答

6
我猜测operator模块中没有andor的实际原因是不可能以短路方式评估函数参数,这正是布尔运算符的整个重点。所以你的问题的答案是否定的,没有内置函数可以模拟and/or,也不能编写一个。应用于生成器的all/any也是短路执行的。
def gen():
    yield 1
    yield this_wont_be_evaluated

print any(gen())

但是我不知道如何使用运行时参数使其正常工作


2
我认为短路是逻辑运算符的一个有用属性,而不是“整个重点”。 - Mark Ransom
3
这正是问题所问的答案:在运算符模块中没有andor函数,因为你不能定义这些函数。拥有接近但不同的函数只会产生误导。 - Jochen Ritzel
1
我同意在短路模式下无法评估函数参数。但是,如果您想要短路行为,应该使用all()any()而不是reduce()。我仍然希望在operator中看到一个逻辑与函数,尽管我承认lambda很容易编写。 - steveha
1
短路是如何“and”和“or”的“要点”,更不用说“整个要点”了? 要点是评估布尔表达式。 短路是一项额外的功能,可以节省不必要的函数评估,这也可以使用常规运算符实现(考虑def __and(x,y):if x == False:return False [..])。 我根本看不出不将它们作为常规运算符的任何意义。 @JochenRitzel你是什么意思? 当然可以定义这些函数。 OP这样做了,我在我的答案中也这样做了。 它们完全相同,只能用作函数参数。 - Stjepan Bakrac
@StjepanBakrac:请注意,您的示例不是短路计算:它会评估xy - georg
显示剩余2条评论

1
我知道没有内置函数可以完成此操作。但是,您可以定义简单的函数,围绕运算符进行包装:
>>> def newand(a,b):
...  return a and b
...
>>> def newor(a,b):
...  return a or b
...
>>> reduce(newand, map(bool, range(5))) # Will return False, because bool(0) == False
False
>>> reduce(newand, map(bool, range(1,5))) # Now 0 is excluded
True

这与lambda相同,它不是一个内置函数,正如所要求的那样。 - jamylak
1
这个问题已经得到解答,不仅在我的回答中,还有其他人的回答中都有提到,即这些符号并不存在。这也让我感到有点困扰,因为我觉得它们应该是其中的一部分。不幸的是,Python 并不完美,这就是我们能做的全部了,因为 andornot 是特殊条件结构,更接近于 if 而不是常规运算符(这也是为什么你不能重载它们的原因,另一个悲伤的事实)。 - Stjepan Bakrac
@StjepanBakrac:为什么你想要重载and或者or,而且还与__bool__不一致呢? - Neil G
1
因为有时候你会使用到没有唯一的“True”或“False”表示的数据结构,但仍然可以与其他数据进行逻辑比较。我最近在处理数据库查询时遇到了这个问题。最终我选择重载了“&”和“|”,但这并不相同,因为它们的优先级是不同的。你不能这样写:“a == b & c == d”,因为它会被解释成“a == (b & c) == d”,而不是像“a == b and c == d”那样,它将被解释成“(a == b) and (c == d)” 。这意味着你最终会多出一个括号嵌套层级。 - Stjepan Bakrac

0
注意:一个具有副作用的函数,将所有值强制转换为布尔值是可以接受的答案。内置和关键字不会这样做,但内置的 not 关键字会。
In : not 255
Out: False

In : not 0
Out: True

当然,你需要把逻辑反过来:

In : not (not 5 and not 0) # mimics: 5 or 0
Out: True

所以,使用这个方法,你可以通过reducemapoperator.*模拟all()函数:
In : not reduce(operator.or_,map(operator.not_,[1,2,3,4,5])) # mimics all(1,2,3,4,5)
Out: True

In : not reduce(operator.or_,map(operator.not_,[1,2,3,0,5])) # mimics all(1,2,3,0,5)
Out: False

这(有点)是你想要实现的吗?恐怕我们无法再接近了。


很抱歉,我不知道如何在reduce()语句中使用上述任何内容。我需要一个可调用对象,如果需要编写一个lambda来封装一些代码,我会直接编写一个lambda,并在其参数上调用andor - steveha
你建议使用 not 将值映射到布尔值,但你指出这样我们就需要反转逻辑。我建议使用 bool() 将值映射到布尔值,因为这样我们就不需要反转逻辑了。请参考原始问题中的示例,从文本“如果您首先将参数映射到布尔值”开始。 - steveha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接