How to Fix TypeError: unhashable type: ‘list’

5/5 - (3 votes)

The TypeError: unhashable type: 'list' usually occurs when you try to use a list object as a set element or dictionary key and Python internally passes the unhashable list into the hash() function. But as lists are mutable objects, they do not have a fixed hash value. The easiest way to fix this error is to use a hashable tuple instead of a non-hashable list as a dictionary key or set element.

We’ll show how this is done in the remaining article. The last method is a unique way to still use lists in sets or dictionary keys that you likely won’t find anywhere else, so keep reading and learn something new! 🐝

Problem Formulation and Explanation

πŸ’¬ Question: How to fix the TypeError: unhashable type: 'list' in your Python script?

There are two common reasons for this error:

This is not a trivial problem because Python lists are mutable and, therefore, not hashable.

Here’s the first example:

my_list = [1, 2, 3]
my_dict = {}
my_dict[my_list] = 'hello Finxters!'
'''
Traceback (most recent call last):
  File "C:\Users\xcent\Desktop\code.py", line 3, in <module>
    my_dict[my_list] = 'hello Finxters!'
TypeError: unhashable type: 'list'
'''

And here’s the second example:

my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
my_set = set(my_list)
'''
Traceback (most recent call last):
  File "C:\Users\xcent\Desktop\code.py", line 2, in <module>
    my_set = set(my_list)
TypeError: unhashable type: 'list'
'''

As you’ve seen in the previous two code snippets, the TypeError: unhashable type: 'list' usually occurs when you try to use a list object as a set element or dictionary key.

But let’s dive deeper to find the real reason for the error:

πŸͺ² Minimal Reproducible Error Example: Lists are mutable objects so they do not have a fixed hash value. In fact, the error can be reproduced most easily when calling hash(lst) on a list object lst.

This is shown in the following minimal example that causes the error:

hash([1, 2, 3])

The output is the error message:

Traceback (most recent call last):
  File "C:\Users\xcent\Desktop\code.py", line 1, in <module>
    hash([1, 2, 3])
TypeError: unhashable type: 'list'

Because you cannot successfully pass a list into the hash() function, you cannot directly use lists as set elements or dictionary keys.

But let’s dive into some solutions to this problem!

Method 1: Use Tuple Instead of List as Dictionary Key

The easiest way to fix the TypeError: unhashable type: 'list' is to use a hashable tuple instead of a non-hashable list as a dictionary key. For example, whereas d[my_list] will raise the error, you can simply use d[tuple(my_list)] to fix the error.

Here’s an example of what you can do instead:

my_list = [1, 2, 3]
my_dict = {}
my_dict[tuple(my_list)] = 'hello Finxters!'

print(my_dict)
# {(1, 2, 3): 'hello Finxters!'}

The error may also occur when you try to use a list as a set element. Next, you’ll learn what to do in that case:

Method 2: Use Tuple Instead of List as Set Element

To fix the TypeError: unhashable type: 'list' when trying to use a list as a set element is to use a hashable tuple instead of a non-hashable list. For example, whereas set.add([1, 2]) will raise the error, you can simply use set.add((1, 2)) or set.add(tuple([1, 2])) to fix the error.

Here’s a minimal example:

my_set = set()

# Error: my_set.add([1, 2])

# This is how to resolve the error:
my_set.add((1, 2))
# Or: my_set.add(tuple([1, 2]))

print(my_set)
# {(1, 2)}

If you want to convert a list of lists to a set, you can check out my detailed tutorial on the Finxter blog:

🌎 Related Tutorial: How to convert a list of lists to a set?

Method 3: Use String Representation of List as Set Element or Dict Key

To fix the TypeError: unhashable type: 'list', you can also use a string representation of the list obtained with str(my_list) as a set element or dictionary key. Strings are hashable and immutable, so Python won’t raise the error when using this approach.

Here’s an example:

my_list = [1, 2, 3]

# 1. Use str repr of list as dict key:
d = {}
d[str(my_list)] = 'hello Finxters'


# 2. Use str repr of list as set element:
s = set()
s.add(str(my_list))

In both cases, we used the string representation of the list instead of the list itself. The string is immutable and hashable and it fixes the error.

But what if you really need a mutable set or dictionary key? Well, you shouldn’t but you can by using this approach:

Method 4: Create Hashable Wrapper List Class

You can still use a mutable list as a dictionary key, set element, or argument of the hash() function by defining a wrapper class, say HackedList, that overrides the __hash__() dunder method.

Python’s built-in hash(object) function takes one object as an argument and returns its hash value as an integer. You can view this hash value as a unique fingerprint of this object.

The Python __hash__() method implements the built-in hash() function.

Here’s the minimal code example that creates a wrapper class HackedList that overrides the __hash__() dunder method so you can use an instance of HackedList as a dictionary key, set element, or just as input to the hash() function:

my_list = [1, 2, 3]

class HackedList:

    def __init__(self, lst):
        self.lst = lst

    def __hash__(self):
        return len(self.lst)


my_hacked_list = HackedList(my_list)

# 1. Pass hacked list into hash() function:
print(hash(my_hacked_list)) # Output: 3

# 2. Use hacked list as dictionary key:
d = dict()
d[my_hacked_list] = 'hello Finxters'

# 3: Use hacked list as set element:
s = set()
s.add(my_hacked_list)

Here’s the content of the dictionary and set defined previously:

{<__main__.HackedList object at 0x0000016CFB0BDFA0>: 'hello Finxters'}
{<__main__.HackedList object at 0x0000016CFB0BDFA0>}

If you want to fix the ugly output, you can additionally define the __str__() and __repr__() magic methods like so:

my_list = [1, 2, 3]

class HackedList:

    def __init__(self, lst):
        self.lst = lst

    def __hash__(self):
        return len(self.lst)

    def __str__(self):
        return str(self.lst)

    def __repr__(self):
        return str(self.lst)


my_hacked_list = HackedList(my_list)

# 1. Pass hacked list into hash() function:
print(hash(my_hacked_list)) # Output: 3

# 2. Use hacked list as dictionary key:
d = dict()
d[my_hacked_list] = 'hello Finxters'

# 3: Use hacked list as set element:
s = set()
s.add(my_hacked_list)


print(d)
print(s)

Beautiful output:

{[1, 2, 3]: 'hello Finxters'}
{[1, 2, 3]}

Summary

The five most Pythonic ways to convert a list of lists to a set in Python are:

Feel free to check out more free tutorials and cheat sheets for learning and improving your Python skills in our free email academy:


Nerd Humor

Oh yeah, I didn’t even know they renamed it the Willis Tower in 2009, because I know a normal amount about skyscrapers.xkcd (source)