How does a comparator work for objects that are not comparable in python?

I defined a list as shown below:

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

then defined a comparator method as shown below:

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

Now I sorted the list using reverseCom:

 list.sort(reverseCom) print list 

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

Although the element [4, 5, 6] is not comparable with other elements of the list. How not to throw any errors?

Can you help me understand how sorting works with a user-defined comparator in python?

+7
python
source share
2 answers

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

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

when comparing two values ​​of containers of different types, on the other hand, is the name of their type, which is taken into account:

 >>> () < [] False >>> 'tuple' < 'list' False >>> {} < [] True >>> 'dict' < 'list' True 

This function, however, was removed 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 following explanation is entirely experimentally based, and I could not find the audio documentation to back it up. If anyone finds it, I would be happy to read it.

Python 2 seems to have even more rules when it comes to comparing user objects / non-container objects.

In this case, it turns out that numerical values ​​are always greater than non-numerical values ​​other than the container.

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

Now, comparing two objects of different, non-numeric, non-container types, it seems that their address 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 

What really are bananas if you ask me.

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

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

Bottomline: Avoid comparing between different types as much as possible. The result is truly unpredictable, unintuitive and not so well documented. Also, use Python 3 whenever possible.

+10
source share

Actually your comparator works, i.e. does not cause any errors:

 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 it works is that list instances are always larger 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 
+1
source share

All Articles