oship-dev team mailing list archive
-
oship-dev team
-
Mailing list archive
-
Message #00943
Re: Hash method
Thanks again Sergio.
I added the __hash__ method to some classes now. I think it would be good if
we had an specific object to create theses hashes (like the java
implementation has). If we don't have this, the classes with many
significant fields are going to have big (and repetitive) hash methods.
Yes, we have an implementation guide. I've never modified it, but it's
located on oshipenv/oship/oship/src/oship/docs/oship_dev_guide.pdf.
Cheers,
Wagner.
2010/3/9 Sergio Miranda Freire <sergio@xxxxxxxxxxxxxxx>
> Hi Wagner,
>
>
>
> My quick answer to your doubt would be: you are right, you would have to
> create a new dictionary whenever you change its data.
>
> But this is the way the EHR works in openEHR: every composition and every
> demographic object is versioned, meaning that you don´t delete or overwrite
> older elements, you just create a new version of it. I think that you don´t
> even need to define a rehash method.
>
>
>
> As to the __ne__ method, now I tend to agree with you. If everyone agrees,
> then we should add this recommendation to the implementation guide. Do we
> have one?
>
>
>
> Cheers
>
>
>
> Sergio
>
>
>
> *De:* Wagner Francisco [mailto:wagnerfrancisco@xxxxxxxxx]
> *Enviada em:* terça-feira, 9 de março de 2010 00:52
> *Para:* Sergio Miranda Freire
> *Cc:* OSHIP-Dev
> *Assunto:* Re: [Oship-dev] 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.
>
>
>
References