TypeError: unhashable type: 'list'
1 · The lesson
readWhat this error means
You tried to use a list as a dictionary key or as a member of a set. Both are built on hashing: Python turns the key into a number once and uses that number to find it again later. A list can change after you've stored it. If you appended one item, its hash would change, and the dictionary could no longer find it. So Python refuses to hash lists at all. The same rule coversdict and set, with the same message and a different type name.
When you see it
Traceback (most recent call last):
File "dedupe.py", line 5, in <module>
seen.add(row)
TypeError: unhashable type: 'list'Why it happens
A mutable value was used where Python needs a value that can't change:1. A set of lists. Deduplicating rows with set(rows) or seen.add(row), when each row is a list, which is exactly what csv.reader gives you.
2. A list as a dict key. Counting or grouping by a pair of values stored as [city, year].
3. A list hiding inside a tuple. (1, [2, 3]) is a tuple, but it's only hashable if everything inside it is.
4. The dict version. set_of_records.add({"id": 7}) fails the same way, with unhashable type: 'dict'.
rows = [["Oslo", 2024], ["Lima", 2024], ["Oslo", 2024]] unique = set(rows) # TypeError: unhashable type: 'list'
How to fix it
Turn the list into a tuple. A tuple can't change, so it can be hashed. For a row of fixed values, a tuple is also the more accurate type:
rows = [["Oslo", 2024], ["Lima", 2024], ["Oslo", 2024]] unique = {tuple(row) for row in rows} print(unique) # {('Oslo', 2024), ('Lima', 2024)}
Need to keep the original order while removing duplicates? A set won't keep the order, but a dictionary keyed by tuples will:
unique_rows = list(dict.fromkeys(tuple(row) for row in rows)) # [('Oslo', 2024), ('Lima', 2024)] (the first appearance wins)
setup added so this can run · re-runs 2 earlier blocks on this page first
rows = ["alpha", "beta", "gamma"] # Earlier blocks on this page that this one builds on, re-run quietly first. _pm_earlier = [ 'rows = [["Oslo", 2024], ["Lima", 2024], ["Oslo", 2024]]\nunique = set(rows) # TypeError: unhashable type: \'list\'', 'rows = [["Oslo", 2024], ["Lima", 2024], ["Oslo", 2024]]\nunique = {tuple(row) for row in rows}\nprint(unique) # {(\'Oslo\', 2024), (\'Lima\', 2024)}', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
Counting by a combination of values? Key by a tuple.
from collections import Counter visits = [["Oslo", 2024], ["Lima", 2024], ["Oslo", 2024]] by_city_year = Counter(tuple(v) for v in visits) print(by_city_year[("Oslo", 2024)]) # 2
Order of the items doesn't matter? Use frozenset. Then {"python", "sql"} and {"sql", "python"} become the same key:
skills_seen = {frozenset(["python", "sql"])}
print(frozenset(["sql", "python"]) in skills_seen) # TrueA dict as the key? Use its identifying field instead (records_by_id[record["id"]]), and don't try to hash the whole dict.
When you'd see this in real code
- Removing duplicate rows from a CSV with
set(csv.reader(f)). - A cache decorator,
functools.lru_cache, wrapped around a function you call with a list argument. The cache uses the arguments as dictionary keys. - pandas
df.groupby(...)ordf.drop_duplicates()on a column whose cells hold lists. - Building a graph as
edges = {[a, b]: weight}instead of{(a, b): weight}.
Related errors
- TypeError: list indices must be integers or slices, not str: using a list where a dict was expected, the other way round.
- KeyError: 'X': the key was hashable, but it isn't in the dictionary.
- RuntimeError: dictionary changed size during iteration: another rule that exists so a dict can keep track of its keys.
See Also
- All Python errors: the full index, by type and by when it happens.
- Tuples: the immutable sequence, and why that makes it a good key.
- Sets: what can go in one, and why.
- Dictionaries: keys, hashing and lookups.
Practice this
on practicepython.inShort exercises that run in your browser and tell you what your code did, as well as whether a test passed.
Found this useful? Share it with a friend who’s learning Python.