← Back to team overview

oship-dev team mailing list archive

Re: Hash method

 

Hello Diego and Sergio, thanks for your replies.

Sergio, you gave us a very good example. I understood the problem and the
only doubt now is how to recalculate the hash if some attribute value
changes after we put it in a dictionary (if this is going to be necessary).
We don't have a "rehash" function in python dictionary. Just to show my
doubt, it's something like this:

class SpringDetector:
    def detectSpring(self):
        map = {}
        g0 = Groundhog(0);
        g1 = Groundhog(1);
        map[g0] = Prediction();
        map[g1] = Prediction();
        print map
        g1.number = 6  # changing the value...
        print 'Looking up prediction for ' + str(g1)
        if (g1 in map):
            print map[g1]
        else:
            print 'key not found'

I searched the web and the only way I saw to solve this problem is to create
a new dictionary... something like this:

def rehash(d):
  return dict(d.iteritems())

class SpringDetector:
    def detectSpring(self):
        map = {}
        g0 = Groundhog(0);
        g1 = Groundhog(1);
        map[g0] = Prediction();
        map[g1] = Prediction();
        print map
        g1.number = 6  # changing the value...
        map = rehash(map)
        print 'Looking up prediction for ' + str(g1)
        if (g1 in map):
            print map[g1]
        else:
            print 'key not found'


I suggested to implement the __ne__ method because usually when we are
programming we expect that != is the negation of == (at least I expect). But
if we don't implement __ne__ it won't be true.


Thanks again,


Wagner F. Mezaroba.

2010/3/8 Sergio Miranda Freire <sergio@xxxxxxxxxxxxxxx>

>  Hi Wagner,
>
>
>
> I think all classes in Oship are mutable. Consider the following use case:
>
> A person has a set of names. Each name is modeled as a class Name with two
> attributes: firstName and lastName. Then you create a instance of Person p1,
> and two instances of the Name class (Mary Smith and Mary Hopkins) and add
> them to the set of names of p1. Suppose you consider that two names are
> equal if their firstName and lastName are both equals.  The set of names of
> a person then should not contain two equal names (by the definition of set).
>
>
>
> If you don´t redefine __eq__ in your Name class, the program will consider
> two names as equals if they are the same object. Two different instances of
> Name with the same firstName and lastName would be different according to
> the default implementation of __eq__. Therefore in this case we should
> redefine __eq__. But we should also redefine __hash__, otherwise it would
> not be based on the attributes used to establish equality between two
> objects, and you would have problems, for example in using the object as a
> key to a dictionary.
>
>
>
> I followed the link to the documentation and I don´t agree with the
> statement that if “you redefine __eq__ for a mutable class, then you should
> not redefine __hash__”.
>
> In the health applications I  think that we will base our sets and
> dictionaries keys on object attributes’ values, not on objects’ ids.
> Therefore we need to redefine both __eq__ and __hash__.
>
> Below is a simple program that illustrates what I said. In the first
> program, we use the default __eq__ and __hash__ implementations. See that
> the key is not found and two Groundhogs (marmota in Portuguese) with the
> same number is added to the set. In the second program, the __eq__ and
> __hash__ are redefined as a function of the number attribute. See that the
> key is found and there are no identifical groundhogs in the set. In fact if
> I redefine __eq__ but do not redefine __hash__ the program doesn´t run. Try
> it.
>
>
>
> There are proposals to calculate the hash function in the literature. If
> you change some attribute value, then the hash value will have to be
> recalculated.
>
> I do not see the need to implement __ne__. Why should we?
>
>
>
> Regards,
>
>
>
> Sergio
>
>
>
> ________________________
>
> Using default __eq__ and __hash__
>
>
>
> import random
>
>
>
> class Groundhog:
>
>
>
>     def __init__(self, value):
>
>         self.number = value
>
>
>
>     def __repr__(self):
>
>         return 'Groundhog #' + str(self.number);
>
>
>
> class Prediction:
>
>
>
>     def __init__(self):
>
>         rand = random.randint(1,10)
>
>         self.shadow = (rand > 5)
>
>
>
>     def __repr__(self):
>
>                 if (self.shadow is False):
>
>             return 'Early Spring'
>
>         else:
>
>             return 'Six more weeks of Winter!'
>
>
>
> class SpringDetector:
>
>
>
>     def detectSpring(self):
>
>         map = {}
>
>         for i in range (0,9):
>
>             map[Groundhog(i)] = Prediction();
>
>         print map
>
>         gh = Groundhog(3)
>
>         print 'Looking up prediction for ' + str(gh)
>
>         if (gh in map):
>
>             print map[gh]
>
>         else:
>
>             print 'key not found'
>
>
>
> if __name__ == "__main__":
>
>     sd = SpringDetector()
>
>     sd.detectSpring()
>
>
>
> Output:
>
>
>
> {Groundhog #1: Early Spring, Groundhog #3: Six more weeks of Winter!,
> Groundhog #4: Early Spring, Groundhog #5: Early Spring, Groundhog #6: Early
> Spring, Groundhog #7: Six more weeks of Winter!, Groundhog #8: Early Spring,
> Groundhog #2: Early Spring}
>
> Looking up prediction for Groundhog #3
>
> key not found
>
> set([Groundhog #0, Groundhog #3, Groundhog #8, Groundhog #1, Groundhog #5,
> Groundhog #3, Groundhog #6, Groundhog #7, Groundhog #2, Groundhog #4])
>
>
>
> _________________________________________________
>
> “””Program redefining __eq__ and __hash__”””
>
>
>
> import random
>
>
>
> class Groundhog:
>
>
>
>     def __init__(self, value):
>
>         self.number = value
>
>
>
>     def __repr__(self):
>
>         return 'Groundhog #' + str(self.number);
>
>
>
>     def __hash__(self):
>
>         return self.number
>
>
>
>     def __eq__(self, o):
>
>         if  isinstance(o, Groundhog):
>
>             return self.number == o.number
>
>         else:
>
>             return false
>
>
>
> class Prediction:
>
>
>
>     def __init__(self):
>
>         rand = random.randint(1,10)
>
>         self.shadow = (rand > 5)
>
>
>
>     def __repr__(self):
>
>                 if (self.shadow is False):
>
>             return 'Early Spring'
>
>         else:
>
>             return 'Six more weeks of Winter!'
>
>
>
> class SpringDetector:
>
>
>
>     def detectSpring(self):
>
>         map = {}
>
>         for i in range (0,9):
>
>             map[Groundhog(i)] = Prediction();
>
>         print map
>
>         gh = Groundhog(3)
>
>         print 'Looking up prediction for ' + str(gh)
>
>         if (gh in map):
>
>             print map[gh]
>
>         else:
>
>             print 'key not found'
>
>
>
> if __name__ == "__main__":
>
>     sd = SpringDetector()
>
>     sd.detectSpring()
>
>
>
>
>
> Output:
>
>
>
> {Groundhog #1: Six more weeks of Winter!, Groundhog #2: Early Spring,
> Groundhog #3: Six more weeks of Winter!, Groundhog #4: Six more weeks of
> Winter!, Groundhog #5: Early Spring, Groundhog #6: Early Spring, Groundhog
> #7: Six more weeks of Winter!, Groundhog #8: Six more weeks of Winter!}
>
> Looking up prediction for Groundhog #3
>
> Six more weeks of Winter!
>
> set([Groundhog #0, Groundhog #1, Groundhog #2, Groundhog #3, Groundhog #4,
> Groundhog #5, Groundhog #6, Groundhog #7, Groundhog #8])
>
>
>
> *De:* oship-dev-bounces+sergio=lampada.uerj.br@xxxxxxxxxxxxxxxxxxx[mailto:
> oship-dev-bounces+sergio <oship-dev-bounces%2Bsergio>=lampada.uerj.br@
> lists.launchpad.net] *Em nome de *Wagner Francisco
> *Enviada em:* sábado, 6 de março de 2010 01:26
> *Para:* OSHIP-Dev
> *Assunto:* [Oship-dev] Hash method
>
>
>
> Hello,
>
> As we talked this week, we need to correct some parts of some Information
> Models we are implementing. Sergio suggested that we implemented the
> __hash__ method in some classes. I was studying about this method (
> http://docs.python.org/reference/datamodel.html#object.__hash__), and I
> saw that if we are writing a mutable class, we shouldn't override __hash__
> method. Apparently, classes like EhrAccess and EhrStatus are mutable
> classes, right? We can change their properties, so it would be hard to
> calculate their hashcode. What do you think about it?
>
> Changing the subject, in python the operator != isn't the negation of ==.
> So if we are going to implement the __eq__ method it would be interesting to
> implement the __ne__ method too.
>
> Cheers,
>
> Wagner F. Mezaroba.
>

Follow ups

References