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 只被计算一次”到底是什么意思呢?
2 个回答
8
在这里,y被用来表示一个可能会产生副作用的任意表达式。简单来说,y可以是任何代码,它在运行时可能会改变一些东西或者产生一些影响。举个例子:
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
45
这个'表达式' y
只会被计算一次。也就是说,在下面这个表达式中,函数只会执行一次。
>>> def five():
... print 'returning 5'
... return 5
...
>>> 1 < five() <= 5
returning 5
True
和下面这个相比:
>>> 1 < five() and five() <= 5
returning 5
returning 5
True