Last updated: Apr 8, 2024
Reading timeยท5 min
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.
The error occurs when you use a dictionary as a key in another dictionary.
# ๐๏ธ Using a dictionary as a key in a dictionary # โ๏ธ TypeError: unhashable type: 'dict' my_dict = {'name': 'Bobby', {'country': 'Austria'}: 'address'}
Or when you use a dictionary as an element in a set
object.
# ๐๏ธ Using a dictionary as an element in a set # โ๏ธ TypeError: unhashable type: 'dict' my_set = {{'name': 'Bobby'}}
set
because dict
objects are mutable and unhashable.One way to solve the error is to convert the dictionary to a JSON string before using it as a key.
import json # ๐๏ธ Convert the dictionary to JSON string my_json = json.dumps({'country': 'Austria'}) my_dict = {'name': 'Bobby', my_json: 'address'} print(my_dict) # ๐๏ธ {'name': 'Bobby', '{"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)
.
frozenset
to solve the errorAn alternative 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': 'Bobby', 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).
# ๐๏ธ dict_items([('name', 'bobby'), ('age', 30)]) print({'name': 'bobby', 'age': 30}.items())
We used the dictionary's items to create a frozenset
that we can use as a key
in a dictionary (and an element in another set
).
frozenset
is an immutable version of the Python 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.
Another way to solve the error is to convert the dictionary to a tuple.
dict_key = {'id': 1, 'country': 'Austria'} # โ Convert to tuple my_tuple = tuple(dict_key) print(my_tuple) # ๐๏ธ ('id', 'country') my_dict = {'name': 'Bobby', my_tuple: 'address'} print(my_dict) # ๐๏ธ {'name': 'Bobby', ('id', 'country'): 'address'} # ๐๏ธ When you have to access the key in the dictionary print(my_dict[my_tuple]) # ๐๏ธ address
When you convert a dictionary to a tuple, the tuple only contains the keys of the dictionary.
Tuples are immutable, so a tuple containing a dictionary's keys can safely be used as a key in another dictionary.
You can't use a dictionary as a key in another dictionary, but you can use one as a value.
dict_value = {'id': 1, 'country': 'Austria'} my_dict = {'name': 'Bobby', 'data': dict_value} # ๐๏ธ {'name': 'Bobby', 'data': {'id': 1, 'country': 'Austria'}} print(my_dict) print(my_dict['data']) # ๐๏ธ {'id': 1, 'country': 'Austria'}
We set one dictionary as a value in another dictionary.
This is allowed as the restrictions don't apply to dictionary values.
You can use a for loop if you need to add all of the key-value pairs of one dictionary to another.
another_dict = {'id': 1, 'country': 'Austria'} my_dict = {'name': 'Bobby'} for key, value in another_dict.items(): my_dict[key] = value # ๐๏ธ {'name': 'Bobby', 'id': 1, 'country': 'Austria'} print(my_dict)
The dict.items method returns a new view of the dictionary's items ((key, value) pairs).
my_dict = {'id': 1, 'name': 'BobbyHadz'} # ๐๏ธ dict_items([('id', 1), ('name', 'BobbyHadz')]) print(my_dict.items())
On each iteration, we set the key-value pair to the other dictionary.
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 internally.Hashable 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('bobbyhadz.com')) # ๐๏ธ 4905958875846995527 # โ๏ธ TypeError: unhashable type: 'dict' print(hash({'name': 'Bobby Hadz'}))
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'] = 'Bobby Hadz' print(my_dict) # ๐๏ธ {'name': 'Bobby Hadz'}
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': 'Bobby Hadz'} print(type(my_dict)) # ๐๏ธ <class 'dict'> print(isinstance(my_dict, dict)) # ๐๏ธ True my_str = 'bobbyhadz.com' 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.
You can learn more about the related topics by checking out the following tutorials: