Trent
Trent

Reputation: 601

Is it possible to use a class as a dictionary key in Python 3?

I'm trying to reduce copy/paste in my code and have stumbled upon this problem. I've googled for the answer but all answers use an instance of a class as the key, I can't find anything on using a class definition itself as the key (I don't know if it's possible).

My code is this:

# All chunkFuncs keys are class definitions, all values are functions
chunkFuncs = {Math_EXP : Math_EXPChunk, Assignment : AssignmentChunk, Function : FunctionChunk}

def Chunker(chunk, localScope):
    for chunkType in chunkFuncs:
        if isinstance(chunk,chunkType):
            # The next line is where the error is raised
            localScope = chunkFuncs[chunk](chunk,localScope)
            return localScope

and the error is this

TypeError: unhashable type: 'Assignment'

Here are the class definitions:

class Math_EXP(pyPeg.List):
    grammar = [Number,Symbol],pyPeg.maybe_some(Math_OP,[Number,Symbol])

class Assignment(pyPeg.List):
    grammar = Symbol,'=',[Math_EXP,Number]

class Function(pyPeg.List):
    grammar = Symbol,'(',pyPeg.optional(pyPeg.csl([Symbol,Number])),')'

Are there any alternative methods I could use to get the same effect?

Thanks.

Upvotes: 6

Views: 5701

Answers (2)

Tim Peters
Tim Peters

Reputation: 70735

OK, the comments are getting out of hand ;-)

It seems certain now that the class object isn't the problem. If it were, the error would have triggered on the first line, when the dict was first constructed:

chunkFuncs = {Math_EXP : Math_EXPChunk, Assignment : AssignmentChunk, Function : FunctionChunk}

If you try to construct a dict with an unhashable key, the dict creation fails at once:

>>> {[]: 3}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

But you got beyond that line, and Assignment is a key in the dict you constructed. So the error is in this line:

        localScope = chunkFuncs[chunk](chunk,localScope)

Best guess is that it's an instance of Assignment that's unhashable:

>>> class mylist(list):
...   pass
...
>>> hash(mylist)
2582159
>>> hash(mylist())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'mylist'

See? mylist is hashable, but the instance mylist() is not.

Later: best guess is that you're not going to be able to worm around this. Why? Because of the name of the base class, pyPeg.List. If it's mutable like a Python list, then instances won't be hashable - and shouldn't be (mutable objects are always dangerous as dict keys). You could still index a dict by id(the_instance), but whether that's semantically correct is something I can't guess without knowing a lot more about your code.

Upvotes: 6

icktoofay
icktoofay

Reputation: 129139

You should be able to, yes, but you might need an extra type call:

>>> class X:
...     pass
...
>>> class_map = {X: 5}
>>> my_x = X()
>>> class_map[type(my_x)]
5

Upvotes: 5

Related Questions