Introduction
Sometimes while executing a python code, we might run into an error like TypeError: unhashable type: ‘dict’ . For example, if we try to hash a dictionary by trying to use it as a set element or as a dictionary key, we might get this error. A TypeError is raised when an operation or function is applied to an object of inappropriate type. To avoid this, we must ensure that a function is applied on the right type of object. In this article we will understand in detail why this error occurs, as well as ways to avoid it by using alternate datatypes.
Why this error occurs
If we try to use an unhashable datatype in our code where hashing is required the following error will occur. TypeError: unhashable type: name_of_datatype. Before getting any further, let us first understand the meaning of mutable and hashable in the context of Python. Understanding these concepts is crucial to really deep dive into the error and completely understand it.
Mutable and Immutable datatypes:
Mutable: In python, if we can change the value in an object without changing its identity, it is a mutable object. For example, if we create a list and try to change its individual elements, the operation is possible.
my_list = [1,2]
my_list[1] = 3
my_list

Immutable: In python, if we cannot change the value in an object without changing its identity, it is immutable.
For example: Changing the value of individual elements in a tuple is not allowed and would raise an error.
my_tuple = (1,2)
my_tuple[1] = 3

What is a Hashable Object:
An object is hashable if it has a hash value which never changes during its lifetime. Hashing allows for efficient lookup, insertion, and deletion of elements. Some objects in Python are hashed internally.
Hash value: We can view the hash value of objects using the hash() function in Python.
my_tuple = (1,2,3)
hash(my_tuple)

Not all objects have hash value. If an object does not have a Hash value, TypeError exception will be raised if we try to access its Hash value.
Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.
Most of Python’s immutable built-in objects are hashable.
1) Numbers and strings are hashable.
2) Tuples and frozenset are hashable if their individual elements are hashable.
3) Mutable datatypes like Lists and Dictionaries are unhashable.
Exploring the error
Let us examine some examples where this error might happen

Case 1: Using a mutable datatype as a Dictionary Key:
student ={"name": "abcd", "age": 22}
new_dict = {student:"highschool"}
In the first example, we are trying to use "student" which is a "dictionary data type" as a dictionary key for another dictionary new_dict.
Dictionary itself is a mutable data type : Hence unhashable
Dictionary keys are Hashed internally by Python, for fast accessibility
The code is trying to hash an unhashable student dictionary so that it can be used as a dictionary key. Hence the error
Case 2: Using a mutable datatype as an element of a Set:
set = {"aa", "bb", "cc", "dd", student}
In the second example, we are trying to use a dictionary data type student as an element of a Set.
As already mentioned above, Dictionary is a mutable data type: Hence unhashable. Elements of a set are hashed, for fast accessibility
This is the reason we get this error
Similar errors like: “TypeError: unhashable type: ‘list’ also occur because of the same reason. Lists are mutable, hence unusable as dictionary keys, or set elements
my_set = {[1,2]}

Solution
The solution is to use Immutable datatypes where we require hashability, i.e. when we want them to be used as elements of sets and keys for dictionary. Let us explore some alternate datatypes that can be used when we have a usecase where hashing is required.
Use Tuple instead of List
Suppose we need to use a group of integers [1,2,3] as a dictionary key.
Instead of using a list [1,2,3] we should convert it into a tuple (1,2,3) . This tuple when used as a dictionary key , would be hashed internally by Python. So, we will not get any error.
my_list = [1,2,3]
my_dict = {tuple(my_list):1}
my_dict

Convert Dictionary to Tuple
Even dictionary can also be converted into tuple and then used as key. Since tuple is hashable, it can definitely be used as dictionary key. Lets consider a simplified example. Here we are converting an unhashable dictionary student to a hashable tuple student_tuple. When we use this student_tuple as a dictionary key python is able to hash it internally and we do not get any error.
student = {"name":"abcd", "age": 22}
student_tuple = tuple(student.items())
new_dict = {student_tuple:1}
new_dict

The items may also be sorted before being converted into a tuple, to ensure consistent hashing as the dictionary elements are inherently unordered collections.
So, a better method would be:
student_tuple = tuple(sorted(student.items()))
Use frozenset instead of set
Instead of a set we may use a frozenset, when hashing is required. In python, frozenset are the immutable version of sets. So, the frozenset can definitely be hashed. Here we are converting an unhashable set my_immutable_object to a frozenset which is hashable. Then when we use it as a dictionary key in my_dict . Python is able to hash it internally. Hence, we would not get any error.
my_immutable_object = frozenset({1,2,3})
my_dict = {my_immutable_object:1}
my_dict

1) When using dictionaries, ensure that its keys are immutable datatypes
2) When using sets, ensure that all its elements are immutable datatypes
3) If there is a use case where a mutable datatype like list, set, or dictionary should be used as a dictionary key or set element, first convert it into an immutable datatype like tuple or frozenset
Conclusion
In a nutshell, the understanding of mutability and hashing will help avoid this type of errors. It is important to choose your datatypes carefully and apply appropriate functions to them, considering factors like mutablity and hashability. Hope this article gives sufficient insight into solving this type of error.