Making a python user-defined class sortable, hashable
Question:
What methods need to be overridden/implemented when making user-defined classes sortable and/or hashable in python?
What are the gotchas to watch out for?
I type dir({})
into my interpreter to get a list of methods on built-in dicts. Of those, I assume I need to some implement some subset of
['__cmp__', '__eq__', '__ge__', '__gt__', '__hash__', '__le__', '__lt__', '__ne__']
Is there a difference in which methods must be implemented for Python3 as opposed to Python2?
Answers:
There are a few ways of marking your object sortable. First – rich comparison, defined by a set of functions:
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
Also it is possible to define only one function:
object.__cmp__(self, other)
And the last should be defined if you want to define custom __hash__
function. See the doc.
There isn’t any difference between Python 2 and 3.
For sortability:
You should define comparision methods. This makes your items sortable. Generally, you shouldn’t prefer __cmp__()
.
I usually use functools.total_ordering decorator.
functools.total_ordering(cls) Given a class defining one or more rich
comparison ordering methods, this class decorator supplies the rest.
This simplifies the effort involved in specifying all of the possible
rich comparison operations:
The class must define one of __lt__()
, __le__()
, __gt__()
, or
__ge__()
. In addition, the class should supply an __eq__()
method.
You should be careful that your comparison methods do not have any side effects. (change any of the values of the object)
For hashing:
You should implement __hash__()
method. I think the best way is returning hash(repr(self))
, so your hash would be unique.
I almost posted this as a comment to the other answers but it’s really an answer in and of itself.
To make your items sortable, they only need to implement __lt__
. That’s the only method used by the built in sort.
The other comparisons or functools.total_ordering
are only needed if you actually want to use the comparison operators with your class.
To make your items hashable, you implement __hash__
as others noted. You should also implement __eq__
in a compatible way — items that are equivalent should hash the same.
Implement __lt__(self,other)
method is the answer to make your class sortable.
It can be used for not only the built-in method sorted(iterable)
, but also priority queue via heapq
module.
In addition, I don’t like python’s design, so many '__ge__', '__gt__', '__le__', '__lt__', '__ne__'
methods are not intuitive at all !
As a contrast, Java’s Interface Comparable<T>
(see java doc) returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object, which is direct and friendly!
What methods need to be overridden/implemented when making user-defined classes sortable and/or hashable in python?
What are the gotchas to watch out for?
I type dir({})
into my interpreter to get a list of methods on built-in dicts. Of those, I assume I need to some implement some subset of
['__cmp__', '__eq__', '__ge__', '__gt__', '__hash__', '__le__', '__lt__', '__ne__']
Is there a difference in which methods must be implemented for Python3 as opposed to Python2?
There are a few ways of marking your object sortable. First – rich comparison, defined by a set of functions:
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
Also it is possible to define only one function:
object.__cmp__(self, other)
And the last should be defined if you want to define custom __hash__
function. See the doc.
There isn’t any difference between Python 2 and 3.
For sortability:
You should define comparision methods. This makes your items sortable. Generally, you shouldn’t prefer __cmp__()
.
I usually use functools.total_ordering decorator.
functools.total_ordering(cls) Given a class defining one or more rich
comparison ordering methods, this class decorator supplies the rest.
This simplifies the effort involved in specifying all of the possible
rich comparison operations:The class must define one of
__lt__()
,__le__()
,__gt__()
, or
__ge__()
. In addition, the class should supply an__eq__()
method.
You should be careful that your comparison methods do not have any side effects. (change any of the values of the object)
For hashing:
You should implement __hash__()
method. I think the best way is returning hash(repr(self))
, so your hash would be unique.
I almost posted this as a comment to the other answers but it’s really an answer in and of itself.
To make your items sortable, they only need to implement __lt__
. That’s the only method used by the built in sort.
The other comparisons or functools.total_ordering
are only needed if you actually want to use the comparison operators with your class.
To make your items hashable, you implement __hash__
as others noted. You should also implement __eq__
in a compatible way — items that are equivalent should hash the same.
Implement __lt__(self,other)
method is the answer to make your class sortable.
It can be used for not only the built-in method sorted(iterable)
, but also priority queue via heapq
module.
In addition, I don’t like python’s design, so many '__ge__', '__gt__', '__le__', '__lt__', '__ne__'
methods are not intuitive at all !
As a contrast, Java’s Interface Comparable<T>
(see java doc) returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object, which is direct and friendly!