O que “avaliado apenas uma vez” significa para comparações encadeadas em Python?
Um amigo me chamou a atenção, e depois que apontei uma esquisitice, estamos ambos confusos.
Os documentários do Python, digamos, e disseram desde pelo menos 2.5.1 (não verificamos mais adiante:
As comparações podem ser encadeadas arbitrariamente, por exemplo, x <y <= z é equivalente a x <y e y <= z, exceto que y é avaliado apenas uma vez (mas em ambos os casos z não é avaliado quando x <y é encontrado ser falso).
Nossa confusão está no significado de "y é avaliado apenas uma vez".
Dada uma classe simples, mas inventada:
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
Nós podemos produzir este resultado:
>>> 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.
>>>
Isso certamenteparece como "y" é, em um sentido tradicional "avaliado" duas vezes - uma vez quandox.__lt__(y)
é chamado e realiza uma comparação sobre ele, e uma vez quandoy.__le__(z)
é chamado.
Então, com isso em mente, o que exatamente os documentos do Python significam quando dizem "y é avaliado apenas uma vez"?