I am interested in taking an arbitrary dict and copying it into a new dict, mutating it along the way.
One mutation I would like to do is swap keys and value. Unfortunately, some values are dicts in their own right. However, this generates a "unhashable type: 'dict'" error. I don't really mind just stringifying the value and giving it the key. But, I'd like to be able to do something like this:
for key in olddict:
if hashable(olddict[key]):
newdict[olddict[key]] = key
else
newdict[str(olddict[key])] = key
Is there a clean way to do this that doesn't involve开发者_Python百科 trapping an exception and parsing the message string for "unhashable type" ?
Python 3.x
Use collections.abc.Hashable
or typing.Hashable
.
>>> import typing
>>> isinstance({}, typing.Hashable)
False
>>> isinstance(0, typing.Hashable)
True
Note: both are the same one, the latter is simply an alias of the former. Also note that collections.Hashable
was removed in Python 3.10+ (deprecated since 3.7).
Python 2.6+ (an original answer)
Since Python 2.6 you can use the abstract base class collections.Hashable
:
>>> import collections
>>> isinstance({}, collections.Hashable)
False
>>> isinstance(0, collections.Hashable)
True
This approach is also mentioned briefly in the documentation for __hash__
.
Doing so means that not only will instances of the class raise an appropriate
TypeError
when a program attempts to retrieve their hash value, but they will also be correctly identified as unhashable when checkingisinstance(obj, collections.Hashable)
(unlike classes which define their own__hash__()
to explicitly raiseTypeError
).
def hashable(v):
"""Determine whether `v` can be hashed."""
try:
hash(v)
except TypeError:
return False
return True
All hashable built in python objects have a .__hash__()
method. You can check for that.
olddict = {"a":1, "b":{"test":"dict"}, "c":"string", "d":["list"] }
for key in olddict:
if(olddict[key].__hash__):
print str(olddict[key]) + " is hashable"
else:
print str(olddict[key]) + " is NOT hashable"
output
1 is hashable
string is hashable
{'test': 'dict'} is NOT hashable
['list'] is NOT hashable
Why not use duck typing?
for key in olddict:
try:
newdict[olddict[key]] = key
except TypeError:
newdict[str(olddict[key])] = key
精彩评论