Welcome, guest | Sign In | My Account | Store | Cart

This describes possible ways of using userdefined class instances as dictionary keys.

Python, 58 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class Base:
        def __init__(self,v):
                self.v=v

class StaticHash(Base):
        def __hash__(self):
                if not hasattr(self,"hashvalue"):
                        self.hashvalue=hash(self.v)
                return self.hashvalue

class ImmutableHash(Base):
        def __init__(self,v):
                self.__dict__["protect"]=[]
                Base.__init__(self,v)

        def __hash__(self):
                self.protect.append("v")
                return hash(self.v)
        def __setattr__(self,k,v):
                if k in self.protect:
                        raise NameError,"%s is protected." % k
                else:
                        self.__dict__[k]=v

class ValueIdentity(ImmutableHash):
        def __cmp__(self,x):
                if self.v==x.v:
                        return 0
                if self.v<x.v:
                        return -1
                return 1

if __name__=="__main__":
        ## SHASH:
        s1=StaticHash(1)
        s2=StaticHash(2)
        r={s1:1,s2:2}
        s2.v=3
        print r[s2]
        ## IHASH
        i1=ImmutableHash(1)
        i2=ImmutableHash(2)
        r={i1:1,i2:2}
        try:
                i1.v=100
        except NameError,v:
                print "NameError,",v
        ## VALUEID
        v1=ValueIdentity(1)
        v2=ValueIdentity(2)
        if v1==v2:
                print "ID1"
        v2.v=1
        if v1==v2:
                print "ID2"
        ## VALUEHASH
        r={v1:1}
        print r[v2]

Sometimes one wants to use instances of userdefined classes as dictionary keys.

For this to be possible, the user supplied class must provide a __hash__ method.

But there some other issues for this to work reliably: 1.) Identity of objects. If you go by the default object equality relation, one can only retrieve data from the dictionary by using exactly the same instance. If you go for value equality one can recreate a different instance with the same logical value, and use it to retrieve tghe stored data. 2.) Keeping the __hash__ value constant. This is important, as this value is used by the dictionary to find the stored data. Two possible solutions are remembering the hash value that was returned the first time, or disallowing changing the "value" of the object.

StaticHash implements a class that uses object identity and remembering the hash value as a solution.

ImmutableHash does disallow changing the "hash generating" attributes after the first time the hash method is used.

ValueIdentity additionally defines a value equality.

Created by Andreas Kostyrka on Fri, 26 Oct 2001 (PSF)
Python recipes (4591)
Andreas Kostyrka's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks