Can someone explain me the differences between the two. Are those normally equivalent ? Maybe I\'m completely wrong here, but I thought that each comparison operator was necessa
This is relying on the __cmp__
magic method, which is what the rich-comparison operators were meant to replace:
>>> dict1 = {1:1}
>>> dict2 = {2:2}
>>> dict1.__cmp__
<method-wrapper '__cmp__' of dict object at 0x10f075398>
>>> dict1.__cmp__(dict2)
-1
As to the ordering logic, here is the Python 2.7 documentation:
Mappings (instances of dict) compare equal if and only if they have equal (key, value) pairs. Equality comparison of the keys and values enforces reflexivity.
Outcomes other than equality are resolved consistently, but are not otherwise defined.
With a footnote:
Earlier versions of Python used lexicographic comparison of the sorted (key, value) lists, but this was very expensive for the common case of comparing for equality. An even earlier version of Python compared dictionaries by identity only, but this caused surprises because people expected to be able to test a dictionary for emptiness by comparing it to {}.
And, in Python 3.0, ordering has been simplified. This is from the documentation:
The ordering comparison operators
(<, <=, >=, >)
raise a TypeError exception when the operands don’t have a meaningful natural ordering.
builtin.sorted()
andlist.sort()
no longer accept the cmp argument providing a comparison function. Use the key argument instead.The
cmp()
function should be treated as gone, and the__cmp__()
special method is no longer supported. Use__lt__()
for sorting,__eq__()
with__hash__()
, and other rich comparisons as needed. (If you really need thecmp()
functionality, you could use the expression(a > b) - (a <> b)
as the equivalent forcmp(a, b)
.)
So, to be explicit, in Python 2, since the rich comparison operators are not implemented, dict
objects will fall-back to __cmp__
, from the data-model documentation:
object.__cmp__(self, other)
Called by comparison operations if rich comparison (see above) is not defined. Should return a negative integer if self < other, zero if self == other, a positive integer if self > other.
Note for operator <
versus __lt__
:
import types
class A:
def __lt__(self, other): return True
def new_lt(self, other): return False
a = A()
print(a < a, a.__lt__(a)) # True True
a.__lt__ = types.MethodType(new_lt, a)
print(a < a, a.__lt__(a)) # True False
A.__lt__ = types.MethodType(new_lt, A)
print(a < a, a.__lt__(a)) # False False
<
calls __lt__
defined on class; __lt__
calls __lt__
defined on object.
It's usually the same :) And it is totally delicious to use: A.__lt__ = new_lt