Borislav Hadzhiev
Wed Apr 20 2022·3 min read
Photo by Ross Sokolovski
The Python "TypeError: unhashable type: 'set'" occurs when we use a set
as a
key in a dictionary or an element in another set
. To solve the error, use a
frozenset
instead, because set
objects are mutable and unhashable.
Here are 2 examples of how the error occurs.
my_set = {'apple', 'banana'} # 👇️ using set as an element in another set # ⛔️ TypeError: unhashable type: 'set' another_set = {'Alice', 'Bob', my_set} # 👇️ using set as a key in a dictionary # ⛔️ TypeError: unhashable type: 'set' my_dict = {my_set: 'fruits'}
set
as a key in a dictionary or as an element in another set
because set
objects are mutable and unhashable.One way to solve the error is to use a frozenset.
my_set = frozenset({'apple', 'banana'}) another_set = {'Alice', 'Bob', my_set} print(another_set) # 👉️ {'Bob', frozenset({'banana', 'apple'}), 'Alice'} # checking if element in set print(frozenset({'apple', 'banana'}) in another_set) # 👉️ True # --------------------------------------------------------------- my_dict = {my_set: 'fruits'} print(my_dict) # 👉️ {'Bob', frozenset({'banana', 'apple'}), 'Alice'} # 👇️ accessing key in dictionary print(my_dict[frozenset({'apple', 'banana'})]) # 👉️ fruits
We used a frozenset
instead of a set
. The frozenset
class takes an iterable as an argument.
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.
Alternatively, you can use another immutable type such as a tuple
if that
suits your use case.
my_tuple = tuple({'apple', 'banana'}) my_set = {'Alice', 'Bob', my_tuple} print(my_set) # 👉️ {'Alice', 'Bob', ('banana', 'apple')} print(tuple({'apple', 'banana'}) in my_set) # 👉️ True # ----------------------------------------------------- my_dict = {my_tuple: 'fruits'} print(my_dict) # 👉️ {('banana', 'apple'): 'fruits'} print(my_dict[tuple({'apple', 'banana'})]) # 👉️ 'fruits'
Tuple objects are immutable and are hashable.
You can also declare a tuple directly by wrapping the items in parenthesis and not square brackets.
my_tuple = ('a', 'b', 'c') print(my_tuple) # 👉️ ('a', 'b', 'c') print(type(my_tuple)) # 👉️ <class 'tuple'>
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: 'set' print(hash({'a', 'b', 'c'}))
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 sets are mutable because the contents of a set
can be changed.
my_set = {'a', 'b'} my_set.add('c') print(my_set) # 👉️ {'c', 'a', 'b'}
On the other hand, frozensets and tuples 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_set = {'a', 'b'} print(type(my_set)) # 👉️ <class 'set'> print(isinstance(my_set, set)) # 👉️ True my_tuple = ('a', 'b') print(type(my_tuple)) # 👉️ <class 'tuple'> print(isinstance(my_tuple, tuple)) # 👉️ 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.