7

I have defined a list as below:

list = [1,3,2,[4,5,6]]

then defined a comparator method as below:

def reverseCom(x,y):
   if(x>y):
        return -1
   elif(x<y):
        return 1
   else:
        return 0

Now I have sorted the list using reverseCom:

list.sort(reverseCom)
print list

Result : [[4, 5, 6], 3, 2, 1]

Though the element [4, 5, 6] is not comparable with other elements of the list. How its not throwing any error ?

Do you can help me to understand that how sort works with the user defined comparator in python ?

1
  • You don't get errors, because the objects are comparable. That is list instances can be compared to int instances. Try [4,5,6] > 3. Any list is always greater than any int as far as I remember. That is how comparison methods are defined in list. Commented Dec 26, 2015 at 19:38

2 Answers 2

10

This is a Python 2 quirk. In Python 2, numeric and non numeric values are comparable, and numeric values are always considered to be less than the value of container objects:

>>> 1 < [1]
True
>>> 1 < [2]
True
>>> 1558 < [1]
True
>>> 1 < {}
True

when comparing two containers values of different types, on the other hand, it is the name of their type that is taken into consideration:

>>> () < []
False
>>> 'tuple' < 'list'
False

>>> {} < []
True
>>> 'dict' < 'list'
True

This feature, however, has been dropped in Python 3, which made numeric and non-numeric values no longer comparable:

>>> 1 < [1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < list()

EDIT: this next explanation is fully experimentation-based, and I couldn't find sound documentation to back it up. If any one does find it, I'd be glad to read through it.

It appears Python 2 has even more rules when it comes to comparison of user-defined objects/non-container objects.

In this case it appears that numeric values are always greater than non-numeric non-container values.

>>> class A: pass
...
>>> a = A()
>>> 1 > a
True
>>> 2.7 > a
True

Now, when comparing two objects of different, non-numeric, non-container types, it seems that it is their address that is taken into account:

>>> class A: pass
...
>>> class B: pass
...
>>> a = A()
>>> a
<__main__.A instance at 0x0000000002265348>
>>> b = B()
>>> b
<__main__.B instance at 0x0000000002265048>
>>> a < b
False
>>> b < a
True

Which is really bananas, if you ask me.

Of course, all that can be changed around if you care to override the __lt__() and __gt__() methods inside your class definition, which determine the standard behavior of the < and > operators.

Further documentation on how these methods operate can be found here.

Bottomline: avoid comparison between different types as much as you can. The result is really unpredictable, unintuitive and not all that well documented. Also, use Python 3 whenever possible.

Sign up to request clarification or add additional context in comments.

Comments

1

Your comparator actually works, i.e., does not throw any error:

In [9]: reverseCom([4,5,6],1)
Out[9]: -1

In [10]: reverseCom([4,5,6],2)
Out[10]: -1

In [11]: reverseCom([4,5,6],3)
Out[11]: -1

The reason why it works is, list instances always bigger than int instances:

In [12]: [1,2,3] > 5
Out[12]: True

In [13]: ['hello'] > 5
Out[13]: True

In [14]: [] > -1
Out[14]: True

2 Comments

@Eli thanks for your reply ,I am very new to python .Can you please help me to understand how comparison works among instances. ` class A: pass . a = A() print a>10 --> false . print A>10 --> true and print " " >10000000000000000000 --> true.
@Oori I updated my answer with more examples and information on how those crazy Python 2 comparisons work. Please take a look at it, it might solve some of your problems.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.