oship-dev team mailing list archive
-
oship-dev team
-
Mailing list archive
-
Message #00940
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