13

I want to use a class instance as a dictionary key, like:

classinstance = class()
dictionary[classinstance] = 'hello world'

Python seems to be not able to handle classes as dictionary key, or am I wrong? In addition, I could use a Tuple-list like [(classinstance, helloworld),...] instead of a dictionary, but that looks very unprofessional. Do you have any clue for fixing that issue?

Miles Erickson
  • 2,574
  • 2
  • 17
  • 18
ltsstar
  • 832
  • 1
  • 8
  • 24
  • 1
    No problem with it - it works fine for me. And why you think it doesn't work - do you have any exceptions? What python version you have? – Mikhail Churbanov Sep 26 '11 at 19:26
  • I use Python 2.7 + twisted framework. This message is shown at me: exceptions.KeyError: <__main__.xmpp instance at 0x02B2A530> – ltsstar Sep 26 '11 at 19:28
  • So - I'm confident (or just think so) this exception is raised not when you ADD element to the dict (like in your example) but when you try to GET it - check what you put in it before - it's possible your instance used as key have changed. – Mikhail Churbanov Sep 26 '11 at 19:31
  • yes, it seem to occurr, wenn i want to delete it. Checking for some details... – ltsstar Sep 26 '11 at 19:34
  • it also happens, when I try to get it. – ltsstar Sep 26 '11 at 19:35
  • try to print dictionary and compare instance memory addresses - it seems they are different in your variable and in dict. – Mikhail Churbanov Sep 26 '11 at 19:39
  • Why do you want to do this? If it's to associate extra information with an instance, you can do so directly: `classinstance = class(); classinstance.extra_message = 'hello world'` – Russell Borogove Sep 26 '11 at 20:38

5 Answers5

14

Your instances need to be hashable. The python glossary tells us:

An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() or __cmp__() method). Hashable objects which compare equal must have the same hash value.

Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

All of Python’s immutable built-in objects are hashable, while no mutable containers (such as lists or dictionaries) are. Objects which are instances of user-defined classes are hashable by default; they all compare unequal, and their hash value is their id().

Community
  • 1
  • 1
Buttons840
  • 9,239
  • 15
  • 58
  • 85
  • 6
    This is correct but misleading. By default all object instances are hashable. The hash code will be an identifier unique to the object instance. – mikerobi Sep 26 '11 at 19:33
  • 1
    "their hash value is their id()." This has changed since python3.x, see https://stackoverflow.com/a/11324771/2135504 – gebbissimo May 18 '20 at 22:12
6

The following code works well because by default, your class object are hashable :

Class Foo(object):
    def __init__(self):
        pass

myinstance = Foo()
mydict = {myinstance : 'Hello world'}

print mydict[myinstance]

Output : Hello world

In addition and for more advanced usage, you should read this post :

Object of custom type as dictionary key

Community
  • 1
  • 1
Sandro Munda
  • 39,921
  • 24
  • 98
  • 123
5

Try implementing the hash and eq methods in your class.

For instance, here is a simple hashable dictionary class I made:

class hashable_dict:
    def __init__(self, d):
        self.my_dict = d
        self.my_frozenset = frozenset(d.items())
    def __getitem__(self, item):
        return self.my_dict[item]
    def __hash__(self):
        return hash(self.my_frozenset)
    def __eq__(self, rhs):
        return isinstance(rhs, hashable_dict) and self.my_frozenset == rhs.my_frozenset
    def __ne__(self, rhs):
       return not self == rhs
    def __str__(self):
        return 'hashable_dict(' + str(self.my_dict) + ')'
    def __repr__(self):
        return self.__str__()
user
  • 7,123
  • 7
  • 48
  • 90
  • 3
    KISS : Keep it simple S* :-) I think that ltsstar has no need this complicated code. – Sandro Munda Sep 26 '11 at 19:39
  • 4
    I disagree. I think an example of a class written to put into a dictionary can be very useful. For a beginner, dictionaries can seem like magic, and it's very important to understand why objects would hash objects the same/differently to ensure your code works as desired. You and I may just have different personal taste, but I always love examples especially when at around 15 lines. :) – user Sep 26 '11 at 19:47
3

There is nothing wrong with using an instance as a dictionary key so long as it follows the rules: A dictionary key must be immutable.

jathanism
  • 33,067
  • 9
  • 68
  • 86
  • same questions, it is better to use tuples or whatever? – ltsstar Sep 26 '11 at 19:39
  • It's hard to say a tuple is better. A tuple is simpler. But if you have a need to store an instance as a dictionary key, that might be better for you, but also more complex. :) – jathanism Sep 26 '11 at 21:09
0

You can create a folder like 'Strategy' then you can use pickle to save and load the objects of your class.

import pickle
import os

# Load object as dictionary ---------------------------------------------------
def load_object():
    file_path = 'Strategy\\All_Pickles.hd5'
    if not os.path.isfile(file_path):
        return {}
    with open(file_path, 'rb') as file:
        unpickler = pickle.Unpickler(file)
        return dict(unpickler.load())


# Save object as dictionary ---------------------------------------------------
def save_object(name, value):
    file_path = 'Strategy\\All_Pickles.hd5'
    object_dict = load_object()
    with open(file_path, 'wb') as file:
        object_dict[name] = value
        pickle.dump(object_dict, file)
        return True


class MyClass:
    def __init__(self, name):
        self.name = name

    def show(self):
        print(self.name)


save_object('1', MyClass('Test1'))
save_object('2', MyClass('Test2'))
objects = load_object()
obj1 = objects['1']
obj2 = objects['2']
obj1.show()
obj2.show()

I created two objects of one class and called a method of the class. I hope, it can help you.

Mehdi Hasirchi
  • 236
  • 2
  • 5