469,282 Members | 2,359 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,282 developers. It's quick & easy.

Possibly dumb question about dicts and __hash__()

Hi!

There's one thing about dictionaries and __hash__() methods that puzzle me. I
have a class with several data members, one of which is 'name' (a str). I would
like to store several of these objects in a dict for quick access
({name:object} style). Now, I was thinking that given a list of objects I might
do something like

d = {}
for o in objects:
d[o] = o

and still be able to retrieve the data like so:

d[name]

if I just defined a __hash__ method like so:

def __hash__(self):
return self.name.__hash__()

but this fails miserably. Feel free to laugh if you feel like it. I cooked up a
little example with sample output below if you care to take the time.

Code:
---------------------------------------------------------------
class NamedThing(object):
def __init__(self, name):
self.name = name
def __hash__(self):
return self.name.__hash__()
def __repr__(self):
return '<foo>'
name = 'moo'
o = NamedThing(name)
print "This output puzzles me:"
d = {}
d[o] = o
d[name] = o
print d
print
print "If I wrap all keys in hash() calls I'm fine:"
d = {}
d[hash(o)] = o
d[hash(name)] = o
print d
print
print "But how come the first method didn't work?"
---------------------------------------------------------------

Output:
---------------------------------------------------------------
This output puzzles me:
{'moo': <foo>, <foo>: <foo>}

If I wrap all keys in hash() calls I'm fine:
{2038943316: <foo>}

But how come the first method didn't work?
---------------------------------------------------------------

I'd be grateful if anyone can shed a litte light on this, or point me to some
docs I might have missed.

Also:
Am I in fact abusing the __hash__() method? If so - what's the intended use of
the __hash__() method?

Is there a better way of implementing this?

I realise I could just write

d[o.name] = o

but this problem seems to pop up every now and then and I'm curious if there's
some neat syntactic trick that I could legally apply here.

Thanks for your time!
/Joel Hedlund
May 3 '06 #1
7 1013
Use __repr__. Behold:
class NamedThing(object): def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
a = NamedThing("Delaware")
b = NamedThing("Hawaii")
d = {}
d[a] = 1
d[b] = 50
print d {Delaware: 1, Hawaii: 50} d[a] 1 d[b]
50

Although this is a bit illegal, because repr is not supposed to be used
this way.

Joel Hedlund wrote: Hi!

There's one thing about dictionaries and __hash__() methods that puzzle me. I
have a class with several data members, one of which is 'name' (a str). I would
like to store several of these objects in a dict for quick access
({name:object} style). Now, I was thinking that given a list of objects I might
do something like

d = {}
for o in objects:
d[o] = o

and still be able to retrieve the data like so:

d[name]

if I just defined a __hash__ method like so:

def __hash__(self):
return self.name.__hash__()

but this fails miserably. Feel free to laugh if you feel like it. I cooked up a
little example with sample output below if you care to take the time.

Code:
---------------------------------------------------------------
class NamedThing(object):
def __init__(self, name):
self.name = name
def __hash__(self):
return self.name.__hash__()
def __repr__(self):
return '<foo>'
name = 'moo'
o = NamedThing(name)
print "This output puzzles me:"
d = {}
d[o] = o
d[name] = o
print d
print
print "If I wrap all keys in hash() calls I'm fine:"
d = {}
d[hash(o)] = o
d[hash(name)] = o
print d
print
print "But how come the first method didn't work?"
---------------------------------------------------------------

Output:
---------------------------------------------------------------
This output puzzles me:
{'moo': <foo>, <foo>: <foo>}

If I wrap all keys in hash() calls I'm fine:
{2038943316: <foo>}

But how come the first method didn't work?
---------------------------------------------------------------

I'd be grateful if anyone can shed a litte light on this, or point me to some
docs I might have missed.

Also:
Am I in fact abusing the __hash__() method? If so - what's the intended use of
the __hash__() method?

Is there a better way of implementing this?

I realise I could just write

d[o.name] = o

but this problem seems to pop up every now and then and I'm curious if there's
some neat syntactic trick that I could legally apply here.

Thanks for your time!
/Joel Hedlund


May 3 '06 #2
Hi!

Thanks for the quick response!
Although this is a bit illegal, because repr is not supposed to be used
this way.
How illegal is it? If I document it and put it in an opensource project, will
people throw tomatoes?

/Joel

jo********@gmail.com wrote: Use __repr__. Behold:

class NamedThing(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return self.name

a = NamedThing("Delaware")
b = NamedThing("Hawaii")
d = {}
d[a] = 1
d[b] = 50
print d
{Delaware: 1, Hawaii: 50}
d[a]
1
d[b]


50

Although this is a bit illegal, because repr is not supposed to be used
this way.

Joel Hedlund wrote:
Hi!

There's one thing about dictionaries and __hash__() methods that puzzle me. I
have a class with several data members, one of which is 'name' (a str). I would
like to store several of these objects in a dict for quick access
({name:object} style). Now, I was thinking that given a list of objects I might
do something like

d = {}
for o in objects:
d[o] = o

and still be able to retrieve the data like so:

d[name]

if I just defined a __hash__ method like so:

def __hash__(self):
return self.name.__hash__()

but this fails miserably. Feel free to laugh if you feel like it. I cooked up a
little example with sample output below if you care to take the time.

Code:
---------------------------------------------------------------
class NamedThing(object):
def __init__(self, name):
self.name = name
def __hash__(self):
return self.name.__hash__()
def __repr__(self):
return '<foo>'
name = 'moo'
o = NamedThing(name)
print "This output puzzles me:"
d = {}
d[o] = o
d[name] = o
print d
print
print "If I wrap all keys in hash() calls I'm fine:"
d = {}
d[hash(o)] = o
d[hash(name)] = o
print d
print
print "But how come the first method didn't work?"
---------------------------------------------------------------

Output:
---------------------------------------------------------------
This output puzzles me:
{'moo': <foo>, <foo>: <foo>}

If I wrap all keys in hash() calls I'm fine:
{2038943316: <foo>}

But how come the first method didn't work?
---------------------------------------------------------------

I'd be grateful if anyone can shed a litte light on this, or point me to some
docs I might have missed.

Also:
Am I in fact abusing the __hash__() method? If so - what's the intended use of
the __hash__() method?

Is there a better way of implementing this?

I realise I could just write

d[o.name] = o

but this problem seems to pop up every now and then and I'm curious if there's
some neat syntactic trick that I could legally apply here.

Thanks for your time!
/Joel Hedlund


May 3 '06 #3
Joel Hedlund a crit :
(snip)
How illegal is it? If I document it and put it in an opensource project,
will people throw tomatoes?


Don't know, but they'll sure do if you insist on top-posting !-)
May 3 '06 #4
Actually, come to think of it, __str__ works just as well.
class NamedThing(object): def __init__(self, name):
self.name = name
def __str__(self):
return self.name d = {}
d[a] = 1
d[b] = 50
d {<__main__.NamedThing object at 0x00C528D0>: 1, <__main__.NamedThing
object at 0x00C529B0>: 50} d[a] 1 d[b]
50

This is what you should use, instead of my first answer. From the docs
for __repr__: "If at all possible, this should look like a valid Python
expression that could be used to recreate an object with the same value
(given an appropriate environment). If this is not possible, a string
of the form "<...some useful description...>" should be returned. ...
This is typically used for debugging, so it is important that the
representation is information-rich and unambiguous."

jo********@gmail.com wrote:
Use __repr__. Behold:
class NamedThing(object): def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
a = NamedThing("Delaware")
b = NamedThing("Hawaii")
d = {}
d[a] = 1
d[b] = 50
print d {Delaware: 1, Hawaii: 50} d[a] 1 d[b]

50

Although this is a bit illegal, because repr is not supposed to be used
this way.

Joel Hedlund wrote:
Hi!

There's one thing about dictionaries and __hash__() methods that puzzle me. I
have a class with several data members, one of which is 'name' (a str). I would
like to store several of these objects in a dict for quick access
({name:object} style). Now, I was thinking that given a list of objects I might
do something like

d = {}
for o in objects:
d[o] = o

and still be able to retrieve the data like so:

d[name]

if I just defined a __hash__ method like so:

def __hash__(self):
return self.name.__hash__()

but this fails miserably. Feel free to laugh if you feel like it. I cooked up a
little example with sample output below if you care to take the time.

Code:
---------------------------------------------------------------
class NamedThing(object):
def __init__(self, name):
self.name = name
def __hash__(self):
return self.name.__hash__()
def __repr__(self):
return '<foo>'
name = 'moo'
o = NamedThing(name)
print "This output puzzles me:"
d = {}
d[o] = o
d[name] = o
print d
print
print "If I wrap all keys in hash() calls I'm fine:"
d = {}
d[hash(o)] = o
d[hash(name)] = o
print d
print
print "But how come the first method didn't work?"
---------------------------------------------------------------

Output:
---------------------------------------------------------------
This output puzzles me:
{'moo': <foo>, <foo>: <foo>}

If I wrap all keys in hash() calls I'm fine:
{2038943316: <foo>}

But how come the first method didn't work?
---------------------------------------------------------------

I'd be grateful if anyone can shed a litte light on this, or point me to some
docs I might have missed.

Also:
Am I in fact abusing the __hash__() method? If so - what's the intended use of
the __hash__() method?

Is there a better way of implementing this?

I realise I could just write

d[o.name] = o

but this problem seems to pop up every now and then and I'm curious if there's
some neat syntactic trick that I could legally apply here.

Thanks for your time!
/Joel Hedlund


May 3 '06 #5
Beautiful!

But how come my attempt didn't work? I've seen docs that explain how __hash__()
methods are used to put objects in dict buckets:

http://docs.python.org/ref/customization.html#l2h-195

But if it's really hash(str(o)) that's used for dict keys, what good are
__hash__() methods? Or am I reading the docs wrong?

/Joel
May 3 '06 #6
Joel Hedlund wrote:
There's one thing about dictionaries and __hash__() methods that puzzle
me. I have a class with several data members, one of which is 'name' (a
str). I would like to store several of these objects in a dict for quick
access ({name:object} style). Now, I was thinking that given a list of
objects I might do something like

d = {}
for o in objects:
d[o]*=*o

and still be able to retrieve the data like so:

d[name]

if I just defined a __hash__ method like so:

def __hash__(self):
return*self.name.__hash__()


Just the hash is not enough. You need to define equality, too:
class Named(object): .... def __init__(self, name):
.... self.name = name
.... def __hash__(self):
.... return hash(self.name)
.... def __eq__(self, other):
.... try:
.... other_name = other.name
.... except AttributeError:
.... return self.name == other
.... return self.name == other_name
.... def __repr__(self):
.... return "Named(name=%r)" % self.name
.... items = [Named(n) for n in "alpha beta gamma".split()]
d = dict(zip(items, items))
d["alpha"]

Named(name='alpha')

Peter

May 4 '06 #7
Hi!
Just the hash is not enough. You need to define equality, too:


Thanks a million for clearing that up.

Cheers!
/Joel
May 4 '06 #8

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by Thomas Guettler | last post: by
39 posts views Thread by Marco Aschwanden | last post: by
3 posts views Thread by fdsl ysnh | last post: by
1 post views Thread by Erik Max Francis | last post: by
65 posts views Thread by Steven Watanabe | last post: by
3 posts views Thread by redefined.horizons | last post: by
12 posts views Thread by Bill Jackson | last post: by
12 posts views Thread by Alan Isaac | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.