3

I'm representing trees with tuples. Say

t1=(t2,t3) and t4=(t5,t6)  

Is it true that when comparing two such trees with ==, it first tests if references t2 and t5 are equal then if references t3 and t6 are equal, if they are not equal then it tries to compare the actual contents of t2 and t5, then the contents of t3 and t6 ?
LE: The following code doesn't call __eq__ it seems that my assumption is right, and that it doesn't evaluate the tuples recursively as I understand from the documentation.

class C:
  def __init__(self,a):
    self.a=a
  def __eq__(self,oth):
    print self.a,oth.a
    return oth.a==self.a

p=(C(1),C(2))
l=(p,p)
f=(p,p)
print l==f 

On the other hand this code does call __eq__

   q=(C(1),C(2))
   p=(C(1),C(2))
   l=(q,q)
   f=(p,p)
   print l==f 
titus
  • 5,512
  • 7
  • 25
  • 39

3 Answers3

4

Yes, tuples attempt to short-circuit the comparison process so two tuples are equal if they are the same tuple or if their elements are either identical or equal.

In particular:

>>> nan = float('NaN')
>>> left = (nan, nan)
>>> right = (nan, nan)
>>> left==right
True
>>> left[0]==right[0]
False

which seems pretty broken.

Duncan
  • 92,073
  • 11
  • 122
  • 156
  • 1
    @titus: Python always assumes that objects compare equal to themselves. Objects failing to have this property will behave strange in all standard containers (see for example [NaNs as key in dictionaries](http://stackoverflow.com/questions/6441857/nans-as-key-in-dictionaries)). The IEEE standard prescribes that NaN must not compare equal to itself, so Python had to accept some weirdness here -- see the [discussion on this issue](http://bugs.python.org/issue4296) in Python's bug tracker. – Sven Marnach Jun 27 '11 at 15:12
3

From the documentation:

Sequence types also support comparisons. In particular, tuples and lists are compared lexicographically by comparing corresponding elements. This means that to compare equal, every element must compare equal and the two sequences must be of the same type and have the same length.

Details about comparisons of the elements are also documented.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • The example wrote in the LE isn't covered by the documentation, I think it proves my assumption – titus Jun 27 '11 at 14:25
  • @titus: That is because `l` and `f` are bound to the same tuple. Python does not need to call `__eq__` to know they are equal, because they are the same object. If you do `l=((C(1),C(2)), (C(1),C(2)))` (and the same for `r`), then `__eq__` will be called. – Björn Pollex Jun 27 '11 at 14:37
  • It wasn't obvious for me that it wouldn't recurse all the way. Now I know better, thanks! – titus Jun 27 '11 at 14:44
1

I've done a little snippet of code to test your assumptions :

class Foo(object):
    def __init__(self, value):
        self.value=value
    def __eq__(self, other):
        print "eq %s with %s"%(self, other)
        return other.value == self.value
    def __cmp__(self, other):
        print "cmp with %s"%other
        return cmp(other.value, self.value)
    def __str__(self):
        return "%s(%s)"%(self.__class__.__name__, self.value)


t1 = (Foo(1), Foo(2))
t2 = (Foo(1), Foo(3))

print t1 == t2

that outputs :

eq Foo(1) with Foo(1)    # equality testing of first item of tuple t1/t2
eq Foo(2) with Foo(3)    # equality testing of second item of tuple t1/t2
False
Cédric Julien
  • 78,516
  • 15
  • 127
  • 132
  • thanks for the suggestion, I extended it in the LE to prove my point. I think my assumption is right – titus Jun 27 '11 at 14:29