Can I use an object (an instance of a class) as a dictionary key in Python?
Asked Answered
V

5

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?

Volleyball answered 26/9, 2011 at 19:22 Comment(7)
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?Pentahedron
I use Python 2.7 + twisted framework. This message is shown at me: exceptions.KeyError: <__main__.xmpp instance at 0x02B2A530>Volleyball
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.Pentahedron
yes, it seem to occurr, wenn i want to delete it. Checking for some details...Volleyball
it also happens, when I try to get it.Volleyball
try to print dictionary and compare instance memory addresses - it seems they are different in your variable and in dict.Pentahedron
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'Being
G
17

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

Gizmo answered 26/9, 2011 at 19:31 Comment(2)
This is correct but misleading. By default all object instances are hashable. The hash code will be an identifier unique to the object instance.Joleen
"their hash value is their id()." This has changed since python3.x, see https://mcmap.net/q/258862/-what-is-the-default-__hash__-in-pythonAudy
F
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

Flatfooted answered 26/9, 2011 at 19:31 Comment(0)
R
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__()
Rabush answered 26/9, 2011 at 19:34 Comment(2)
KISS : Keep it simple S* :-) I think that ltsstar has no need this complicated code.Flatfooted
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. :)Rabush
R
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.

Reality answered 26/9, 2011 at 19:33 Comment(2)
same questions, it is better to use tuples or whatever?Volleyball
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. :)Reality
B
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.

Bone answered 2/3, 2022 at 7:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.