15

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?

7
  • 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? Commented Sep 26, 2011 at 19:26
  • I use Python 2.7 + twisted framework. This message is shown at me: exceptions.KeyError: <__main__.xmpp instance at 0x02B2A530> Commented Sep 26, 2011 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. Commented Sep 26, 2011 at 19:31
  • yes, it seem to occurr, wenn i want to delete it. Checking for some details... Commented Sep 26, 2011 at 19:34
  • it also happens, when I try to get it. Commented Sep 26, 2011 at 19:35

5 Answers 5

18

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().

Sign up to request clarification or add additional context in comments.

2 Comments

This is correct but misleading. By default all object instances are hashable. The hash code will be an identifier unique to the object instance.
"their hash value is their id()." This has changed since python3.x, see stackoverflow.com/a/11324771/2135504
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

Comments

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__()

2 Comments

KISS : Keep it simple S* :-) I think that ltsstar has no need this complicated code.
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. :)
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.

2 Comments

same questions, it is better to use tuples or whatever?
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. :)
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.