Borislav Hadzhiev
Wed Apr 20 2022·3 min read
Photo by Ben Koorengevel
The Python "TypeError: unhashable type: 'dict'" occurs when we use a
dictionary as a key in another dictionary or as an element in a set
. To solve
the error, use a frozenset instead, or convert the dictionary into a JSON string
before using it as a key.
Here are 2 examples of how the error occurs.
# 👇️ using dictionary as a key in a dictionary # ⛔️ TypeError: unhashable type: 'dict' my_dict = {'name': 'Alice', {'country': 'Austria'}: 'address'} # 👇️ using dictionary as an element in a set # ⛔️ TypeError: unhashable type: 'dict' my_set = {{'name': 'Alice'}}
set
because dict
objects are mutable and unhashable.One way to solve the error is to use a frozenset.
my_key = {'country': 'Austria'} key = frozenset(my_key.items()) print(key) # 👉️ frozenset({('country', 'Austria')}) my_dict = {'name': 'Alice', key: 'address'} # 👇️ when you have to access the key print(my_dict[frozenset(my_key.items())]) # 👉️ 'address'
The dict.items method returns a new view of the dictionary's items ((key, value) pairs).
We used the dictionary's items to create a frozenset
which we can use as a key
in a dictionary (and an element in another set).
set
object, so it can be used as a key in a dictionary or an element in another set.Notice that you have to use the same approach to access the key in the dictionary.
You can store the result of calling frozenset(my_key.items())
in a variable
and reuse the frozenset when setting or accessing the key in the dictionary.
An alternative approach is to convert the dictionary to a JSON string before using it as a key.
import json # 👇️ convert dictionary to JSON string my_json = json.dumps({'country': 'Austria'}) my_dict = {'name': 'Alice', my_json: 'address'} print(my_dict) # 👉️ {'name': 'Alice', '{"country": "Austria"}': 'address'} # 👇️ when you have to access the key in the dictionary print(my_dict[json.dumps({'country': 'Austria'})]) # 👉️ address
The json.dumps method converts a Python object to a JSON formatted string. This works because strings are immutable and hashable.
Conversely, the
json.loads method
parses a JSON string into a native Python object, e.g.
my_dict = json.loads(my_json_str)
.
Most of the immutable built-in objects in Python are hashable, whereas mutable objects are unhashable.
set
, because these data structures use the hash value internallyHashable objects include - str
, int
, bool
, tuple
, frozenset
.
Unhashable objects include - list
, dict
, set
.
Note that tuples
and frozensets
are only hashable if their elements are
hashable.
You can check if an object is hashable by passing it to the built-in hash()
function.
print(hash('hello')) # 👉️ -1210368392134373610 # ⛔️ TypeError: unhashable type: 'dict' print(hash({'name': 'Alice'}))
The hash function returns the hash value of the passed in object (if it has one).
Hash values are integers and are used to compare dictionary keys during a dictionary lookup.
Objects like dictionaries are mutable because the contents of a dict
can be
changed.
my_dict = {'name': 'Alice'} my_dict['name'] = 'Bob' print(my_dict) # 👉️ {'name': 'Bob'}
On the other hand, fronzenset and tuple objects that contain primitive values are immutable (and hashable).
Dictionaries are indexed by keys and the keys in a dictionary can be any immutable type, e.g. strings or numbers.
If a frozenset or a tuple contains mutable objects such as lists, it cannot be
used as a key in a dictionary or an element in a set
.
If you aren't sure what type of object a variable stores, use the type()
class.
my_dict = {'name': 'Alice'} print(type(my_dict)) # 👉️ <class 'dict'> print(isinstance(my_dict, dict)) # 👉️ True my_str = 'hello' print(type(my_str)) # 👉️ <class 'str'> print(isinstance(my_str, str)) # 👉️ True
The type class returns the type of an object.
The isinstance
function returns True
if the passed in object is an instance or a subclass of
the passed in class.