“仅评估一次”对于Python中的链式比较意味着什么?


问题内容

一个朋友引起了我的注意,当我指出一个奇怪的地方后,我们俩都感到困惑。

Python的文档说,并且至少从2.5.1起就说过(还没有进一步检查:

比较可以任意链接,例如,x <y <= z等同于x <y和y <= z,除了y仅被评估一次(但是在两种情况下,当x
<y被发现时,z都不被评估。是假的)。

我们的困惑在于“ y仅被评估一次”的含义。

给定一个简单但人为的类:

class Magic(object):
    def __init__(self, name, val):
        self.name = name
        self.val = val
    def __lt__(self, other):
        print("Magic: Called lt on {0}".format(self.name))
        if self.val < other.val:
            return True
        else:
            return False
    def __le__(self, other):
        print("Magic: Called le on {0}".format(self.name))
        if self.val <= other.val:
            return True
        else:
            return False

我们可以产生以下结果:

>>> x = Magic("x", 0)
>>> y = Magic("y", 5)
>>> z = Magic("z", 10)
>>> 
>>> if x < y <= z:
...     print ("More magic.")
... 
Magic: Called lt on x
Magic: Called le on y
More magic.
>>>

在传统意义上,这肯定 看起来 像是“ y”,两次x.__lt__(y)被“评估”-一次被调用并对其进行比较,一次y.__le__(z)被调用。

因此,考虑到这一点,当Python文档说“ y仅被评估一次”时,究竟意味着什么?


问题答案:

“表达式”y被评估一次。即,在以下表达式中,该函数仅执行一次。

>>> def five():
...    print 'returning 5'
...    return 5
... 
>>> 1 < five() <= 5
returning 5
True

相对于:

>>> 1 < five() and five() <= 5
returning 5
returning 5
True