在Python中编写双不等式时,运算符优先级是什么(在代码中明确说明,以及如何在数组中覆盖它?)

问题描述 投票:0回答:4

当我要求类似的内容时,按顺序执行的具体代码是什么

>>> 1 <= 3 >= 2
True

如果两者具有相同的优先级并且这只是它们评估的顺序,为什么第二个不等式的功能为

(3 >= 2)
而不是
(True >= 2)

例如考虑这些之间的区别

>>> (1 < 3) < 2
True

>>> 1 < 3 < 2
False

这只是硬编码到 Python 中的纯语法快捷方式,以将第二个语句展开为两个语句的

and
吗?

我可以改变一个类的这种行为,以便

a <= b <= c
扩展到不同的东西吗?看起来是这样的

a (logical operator) b (logical operator) c 
    --> (a logical operator b) and (b logical operator c)

但真正的问题是如何在代码中实现这一点。

我很好奇,所以我可以在我自己的一些课程中复制这种

__lt__
__gt__
行为,但我对如何在保持中间参数不变的情况下完成这一点感到困惑。

这是一个具体的例子:

>>> import numpy as np

>>> tst = np.asarray([1,2,3,4,5,6])

>>> 3 <= tst
array([False, False,  True,  True,  True,  True], dtype=bool)

>>> 3 <= tst <= 5
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/home/ely/<ipython-input-135-ac909818f2b1> in <module>()
----> 1 3 <= tst <= 5

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

最好重写它,以便它也“适用于”数组,如下所示:

>>> np.logical_and(3 <= tst, tst <= 5)
array([False, False,  True,  True,  True,  False], dtype=bool)

添加澄清

评论中表明我在解释问题方面做得很差。以下是一些澄清说明:

1)我不是正在寻找一个简单的解释,解释器在两个连锁不等式之间弹出一个

and
。我已经知道了,上面也这么说了。

2)为了与我想做的事情进行类比,请考虑

with
语句(link)。以下:

with MyClass(some_obj) as foo:
    do_stuff()

解压成

foo = MyClass(some_obj)
foo.__enter__()
try:
    do_stuff()
finally:
    foo.__exit__()

因此,通过适当地编写

MyClass
,我可以在
with
语句中做许多特殊的事情。

我问是否有类似的链式不等式解包代码,通过它我可以拦截它正在做的事情并将其重定向为使用数组式逻辑运算符仅适用于我关心的类

我觉得我的问题非常清楚,尤其是这个例子,但希望这能让它更清楚。

python operator-overloading inequalities
4个回答
13
投票

我不完全确定你在寻找什么,但快速反汇编表明

a < b < c
没有编译为与
a < b and b < c

相同的字节码
>>> import dis
>>>
>>> def f(a, b, c):
...     return a < b < c
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 DUP_TOP
              7 ROT_THREE
              8 COMPARE_OP               0 (<)
             11 JUMP_IF_FALSE_OR_POP    21
             14 LOAD_FAST                2 (c)
             17 COMPARE_OP               0 (<)
             20 RETURN_VALUE
        >>   21 ROT_TWO
             22 POP_TOP
             23 RETURN_VALUE
>>>
>>> def f(a, b, c):
...     return a < b and b < c
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 COMPARE_OP               0 (<)
              9 JUMP_IF_FALSE_OR_POP    21
             12 LOAD_FAST                1 (b)
             15 LOAD_FAST                2 (c)
             18 COMPARE_OP               0 (<)
        >>   21 RETURN_VALUE

编辑1:进一步挖掘,我认为这对于 numpy 来说是奇怪或错误的。考虑这个示例代码,我认为它的工作原理符合您的预期。

class Object(object):
    def __init__(self, values):
        self.values = values
    def __lt__(self, other):
        return [x < other for x in self.values]
    def __gt__(self, other):
        return [x > other for x in self.values]

x = Object([1, 2, 3])
print x < 5 # [True, True, True]
print x > 5 # [False, False, False]
print 0 < x < 5 # [True, True, True]

编辑2:实际上这并不能“正常”工作......

print 1 < x # [False, True, True]
print x < 3 # [True, True, False]
print 1 < x < 3 # [True, True, False]

我认为它是在

1 < x < 3
的第二次比较中将布尔值与数字进行比较。

编辑3:我不喜欢从gt、lt、gte、lte特殊方法返回非布尔值的想法,但根据Python文档实际上并没有限制。

http://docs.python.org/reference/datamodel.html#object.lt

按照惯例,成功时返回 False 和 True 比较。然而,这些方法可以返回任何值...


7
投票

两者具有相同的优先级,但根据文档从左到右进行评估。

a <= b <= c
形式的表达式扩展为
a <= b and b <= c


1
投票

但真正的问题是如何在代码中实现这一点。

你的意思是解释器如何转换它,还是什么?你已经说了

a (logical operator) b (logical operator) c 
    --> (a logical operator b) and (b logical operator c)

所以我不确定你在这里问什么 好吧,我想通了:不,你不能覆盖从

a < b < c
(a < b) and (b < c)
IIUC 的扩展。


我很好奇,所以我可以在我自己的一些课程中复制这种

__lt__
__gt__
行为,但我对如何在保持中间参数不变的情况下完成这一点感到困惑。

这取决于表达式

a
中的
b
c
a < b < c
中的哪一个是您自己的类的实例。实现您的
__lt__
__gt__
和方法取得了一些进展,但 documentation 指出:

这些方法没有交换参数版本(当左侧参数不支持该操作但右侧参数支持该操作时使用)

所以,如果你想要

Int < MyClass < Int
,那你就不走运了。您至少需要
MyClass < MyClass < Something
(因此您的类的实例位于扩展表达式中每个比较的左侧)。


0
投票

我想回应最初的例子--

为什么:

(1 < 3) < 2 == True

同时:

1 < 3 < 2 == False

所以,让我们来解决这个问题,第二个(明显的)首先:

(1 < 3) and (3 < 2)
简化为
(True) and (False)
False

接下来,不太明显的一个:

(1 < 3) < 2
简化为
(True) < 2
简化为
1 < 2
,即
True

这是另一个答案,解释这是因为布尔值是整数的子类型:https://stackoverflow.com/a/47644907/22348177

© www.soinside.com 2019 - 2024. All rights reserved.