What does “evaluated only once” mean for chained comparisons in Python?
一个朋友把这件事引起了我的注意,在我指出一个奇怪的地方之后,我们都很困惑。
比如说,python的文档,从至少2.5.1开始就已经说过了(还没有进一步检查过:
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).
我们的困惑在于"Y只评估一次"。
给出了一个简单但做作的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
我们可以得出这样的结果:
1 2 3 4 5 6 7 8 9 10 11 | >>> 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"被"评估"了两次——一次是在调用
因此,考虑到这一点,当python文档说"y只计算一次"时,它们究竟意味着什么?
"表达式"
1 2 3 4 5 6 7 | >>> def five(): ... print 'returning 5' ... return 5 ... >>> 1 < five() <= 5 returning 5 True |
与之相反:
1 2 3 4 | >>> 1 < five() and five() <= 5 returning 5 returning 5 True |
在被评估的y的上下文中,y是指可能产生副作用的任意表达式。例如:
1 2 3 4 5 6 7 8 9 | class Foo(object): @property def complain(self): print("Evaluated!") return 2 f = Foo() print(1 < f.complain < 3) # Prints evaluated once print(1 < f.complain and f.complain < 3) # Prints evaluated twice |