How to Solve "TypeError: unhashable type: 'set'" in Python
The TypeError: unhashable type: 'set'
error in Python occurs when you try to use a set
object in a context where a hashable object is required. The most common situations are:
- Using a
set
as a key in a dictionary. - Using a
set
as an element within anotherset
.
This guide explains why this error occurs and how to solve it using frozenset
(for immutable sets) or tuple
(if order matters).
Understanding Hashability and Mutability
- Hashable: An object is hashable if it has a hash value (an integer) that never changes during its lifetime. Hashable objects can be used as dictionary keys and set elements because these data structures use the hash value internally for fast lookups.
- Immutable: An object is immutable if its value can not be changed after it's created. Examples include strings, numbers, tuples, and frozensets.
- Mutable: An object is mutable if its value can be changed after creation. Examples include lists, dictionaries, and sets.
Key Principle: In Python, most immutable objects are hashable, and most mutable objects are not hashable. This is because if an object could change its value, its hash value would also need to change, which would break the fundamental workings of dictionaries and sets.
Why Sets are Unhashable
Standard Python set
objects are mutable. You can add and remove elements from them:
my_set = {'apple', 'banana'}
my_set.add('cherry')
print(my_set) # Output: {'apple', 'banana', 'cherry'} (order may vary)
Because sets are mutable, they are not hashable, and therefore you can not use them as dictionary keys or elements of other sets:
my_set = {'apple', 'banana'}
# ⛔️ TypeError: unhashable type: 'set'
# another_set = {'Alice', 'Bob', my_set} # Can't put a set inside a set
# ⛔️ TypeError: unhashable type: 'set'
# my_dict = {my_set: 'fruits'} # Can't use a set as a dictionary key
Solution 1: Using frozenset
(Recommended for Sets)
frozenset
is an immutable version of a set. It supports all the same set operations (union, intersection, difference, etc.), but you can not add or remove elements after it's created. Because it's immutable, it's also hashable.
my_set = frozenset({'apple', 'banana'}) # Create a frozenset
# Now you CAN use it in these contexts:
another_set = {'Alice', 'Bob', my_set} # OK!
print(another_set) # Output: {'Bob', frozenset({'banana', 'apple'}), 'Alice'}
print(frozenset({'apple', 'banana'}) in another_set) # Output: True
my_dict = {my_set: 'fruits'} # OK!
print(my_dict) # Output: {frozenset({'apple', 'banana'}): 'fruits'}
print(my_dict[frozenset({'apple', 'banana'})]) # Output: fruits
frozenset({'apple', 'banana'})
: Creates an immutable set. The syntax is slightly different from a regular set (you have to use thefrozenset()
constructor).- Now you can use a
frozenset
inside aset
or as a key in a dictionary.
Solution 2: Using tuple
(If Order Matters)
If the order of the elements is important, and you don't actually need set-like behavior, use a tuple
instead of a set
:
my_tuple = tuple({'apple', 'banana'}) # Or, more simply: my_tuple = ('apple', 'banana')
my_set = {'Alice', 'Bob', my_tuple} # OK
print(my_set) # Output: {('banana', 'apple'), 'Alice', 'Bob'}
print(tuple({'apple', 'banana'}) in my_set) # Output: False
my_dict = {my_tuple: 'fruits'} # OK
print(my_dict) # Output: {('apple', 'banana'): 'fruits'}
- You can create a tuple from a set, by passing the set object to the
tuple
class constructor. - Tuples are immutable and ordered, so they are hashable.
- Important:
('apple', 'banana')
is different from('banana', 'apple')
when used as a dictionary key or set element. Sets and frozensets are unordered.
Checking the type of a variable
You can check the type of variable using type
and/or isinstance
:
my_set = {'a', 'b'}
print(type(my_set)) # Output: <class 'set'>
print(isinstance(my_set, set)) # Output: True
my_tuple = ('a', 'b')
print(type(my_tuple)) # Output: <class 'tuple'>
print(isinstance(my_tuple, tuple)) # Output: True
my_frozenset = frozenset({'a', 'b'})
print(type(my_frozenset)) # Output: <class 'frozenset'>
print(isinstance(my_frozenset, frozenset)) # Output: True
- You can verify the types of the variables using
type()
orisinstance()
.
Conclusion
The TypeError: unhashable type: 'set'
error occurs because standard Python set
objects are mutable and therefore can not be used as dictionary keys or elements of other sets.
- The solution is to use the immutable
frozenset
if you need set-like behavior, or to use atuple
if order is important and you don't need set operations. - Understanding the difference between mutable and immutable types, and between hashable and unhashable objects, is fundamental to avoiding this common Python error.