¿Qué significa "evaluado solo una vez" para las comparaciones encadenadas en Python?
Un amigo me llamó la atención, y después de señalar una rareza, los dos estamos confundidos.
Los documentos de Python, digamos, y han dicho desde al menos 2.5.1 (no he comprobado más atrás:
Las comparaciones se pueden encadenar arbitrariamente, por ejemplo, x <y <= z es equivalente a x <y y y <= z, excepto que y se evalúa solo una vez (pero en ambos casos no se evalúa en absoluto cuando se encuentra x <y ser falso).
Nuestra confusión radica en el significado de "y se evalúa solo una vez".
Dada una clase simple pero artificial:
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
Podemos producir 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.
>>>
Esto ciertamentemiradas como 'y' es, en un sentido tradicional "evaluado" dos veces, una vez cuandox.__lt__(y)
se llama y realiza una comparación en él, y una vez quey.__le__(z)
se llama.
Entonces, con esto en mente, ¿qué significan exactamente los documentos de Python cuando dicen "y se evalúa solo una vez"?