15

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

>>> 1 <= 3 >= 2
True

如果两者具有相同的优先级并且这只是它们的评估顺序,为什么第二个不等式起作用(3 >= 2)而不是(True >= 2)

例如考虑这些之间的区别

>>> (1 < 3) < 2
True

>>> 1 < 3 < 2
False

and将第二个扩展为两个语句中的第二个,是否只是硬编码到 Python 中的纯语法快捷方式?

我可以改变一个类的这种行为,从而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语句(链接)。以下:

with MyClass(some_obj) as foo:
    do_stuff()

解压成

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

因此,通过适当地编写MyClass,我可以在with语句中做许多特殊的事情。

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

从我的问题,尤其是示例中,我觉得这很清楚,但希望这可以使其更加清楚。

4

3 回答 3

12

我不完全确定您在寻找什么,但快速反汇编显示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。但是,这些方法可以返回任何值...

于 2012-10-01T14:23:25.910 回答
6

两者具有相同的优先级,但根据文档从左到右进行评估。表单的表达式a <= b <= c扩展为a <= b and b <= c.

于 2012-09-30T02:45:42.183 回答
1

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

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

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

所以我不确定你在这里问什么 好的,我想通了:不,你不能覆盖从 IIUC 的a < b < c扩展(a < b) and (b < c)


我很好奇,所以我可以在我自己的一些类中复制这种__lt__行为__gt__,但我对如何在保持中间参数不变的情况下实现这一点感到困惑。

这取决于表达式中的a,b和是您自己的类的实例。实现你的and和方法有一些方法,但文档指出:ca < b < c__lt____gt__

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

所以,如果你愿意Int < MyClass < Int,你就不走运了。您至少需要MyClass < MyClass < Something(因此您的类的一个实例位于扩展表达式中每个比较的 LHS 上)。

于 2012-10-01T12:08:05.550 回答