oship-dev team mailing list archive
-
oship-dev team
-
Mailing list archive
-
Message #00939
RES: Hash method
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=lampada.uerj.br@xxxxxxxxxxxxxxxxxxx] 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