Python Forum

Full Version: Hash function in Python
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I've done some research and was able to implement the rich comparisons in my Person class. I have two questions,

1. Given the equals method how do I construct a good __hash__ function? I've read the documentation on the official website, but it was discussed on SO as having problems

def __init__(self, iden, firstname, lastname):
        self._firstname = firstname
        self._lastname = lastname
        self._iden = iden

    @property
    def identification_number(self):
        return self._iden

    @property
    def first_name(self):
        return self._firstname

    @property
    def last_name(self):
        return self._lastname

    def __eq__(self, other):
        return (self._iden, self._lastname.lower(), self._firstname.lower()) == (other.identification_number, other.last_name.lower(), other.first_name.lower())
2. When creating the other rich comparisons, is it good practice to check if the operand is an instance of the class? For example, take the following __lt__ function:
    def __lt__(self, other):
        if isinstance(other, Person):
            return (self._lastname.lower(), self._firstname.lower()) < (other.last_name.lower(), other.first_name.lower())
        return NotImplemented
If it's considered bad practice, how then would I return NotImplemented error? The documentation clearly specifies that rich comparisons should return this error if the methods used for comparison haven't been implemented.
I don't see a problem there. Remember that if the two objects are equal, they must return the same hash. The problem SO seems to be talking about is two objects with the same hash that aren't equal. That's the reverse, and shouldn't really cause a problem, at least for standard Python use of the hash in dictionaries and sets. I would just construct the hash based on the tuple of the three attributes you are using for equality.

For the less than, that looks fine for handling the NotImplemented. That's how I always do it: if/elif to match different classes, and if no appropriate class then return NotImplemented. I am wondering why self and other have different attribute names, though.
(Sep-29-2017, 02:21 PM)ichabod801 Wrote: [ -> ]I don't see a problem there. Remember that if the two objects are equal, they must return the same hash. The problem SO seems to be talking about is two objects with the same hash that aren't equal. That's the reverse, and shouldn't really cause a problem, at least for standard Python use of the hash in dictionaries and sets. I would just construct the hash based on the tuple of the three attributes you are using for equality.

For the less than, that looks fine for handling the NotImplemented. That's how I always do it: if/elif to match different classes, and if no appropriate class then return NotImplemented. I am wondering why self and other have different attribute names, though.

Thanks for you answer!

They have different property names because the other attributes are being called with the getters. For consistency, I should choose the getters approach and stick with it. PyCharm complains I'm attempting to access private variables when I call them directly.
Oh, duh. I saw the @properties but didn't read them closely.