Skip to main content
MahiDev — Learn. Build. Become AI-ready.

Lesson 14

Hashability Rules and Collection Conversions

Learn which Python objects can become dictionary keys or set elements, fix TypeError unhashable type, and master conversions between list, tuple, set, and dict.

Intermediate25 min

What you will learn

Hashability rules · Nesting validity · Collection conversions · Fixing TypeError: unhashable type

Learn which Python objects can become dictionary keys or set elements, fix TypeError: unhashable type, and master conversions between list, tuple, set, and dict.

Topic Why it matters
Hashable vs unhashable Dict keys and set members
Nesting rules Avoid runtime TypeError
Conversions Deduplicate, sort, rebuild
Fixes Interview and production debugging

After File 13 — Nested Dictionaries, you have seen combination patterns in practice. This lesson explains the underlying rule — hashability — and the conversion toolkit you will use everywhere.

Related: Mutable vs Immutable · Identity operators.

Learning roadmap

Hashable nesting convert fix TypeError roadmap

What is hashability?

A hashable object has a stable hash value throughout its lifetime. Python uses that hash to store objects efficiently inside sets and as dictionary keys.

Hashable vs unhashable types diagram

Golden rule

Golden rule hashable dict keys vs unhashable mutable containers
Can be dict key or set element Cannot be dict key or set element
int, float, str, bool list
tuple (hashable contents only) dict
frozenset set (mutable)

Memory hook: If it can change after creation, it usually cannot be hashed.

1. Nesting rules (interview table)

Inner → Outer Allowed?
List → List Yes
Dict → Tuple Yes
List → Set No
Dict → Set No
Tuple → Set Only if all elements hashable

Examples

Valid:

python
valid = {(1, 2), (3, 4)}
valid_set = {frozenset({1, 2}), frozenset({3, 4})}

Invalid:

python
bad = {[1, 2]}      # TypeError: unhashable type: 'list'
bad = {{1: 2}}      # TypeError: unhashable type: 'dict'

Full combination matrix: File 13 — Nested Dictionaries.

2. Mutable inside immutable

This is one of the most misunderstood Python concepts.

Tuple with mutable list inside still appendable

The tuple is immutable, but the list inside it is still mutable.

python
t = (10, [1, 2, 3])

t[1].append(4)

print(t)
# (10, [1, 2, 3, 4])

Key insight: Immutability applies only to the outer container, not automatically to nested objects.

Same idea for a dict inside a tuple or list — the outer shell may be fixed, but the inner dict can still change.

python
record = (100, {"x": 1})
record[1]["y"] = 2   # OK — mutating inner dict

But remember: a tuple containing a dict is not hashable, so it cannot go inside a set.

3. Collection conversion cheat sheet

These conversions appear constantly in interviews and production code.

Common conversion paths list tuple set dict zip
From To Code
List Tuple tuple(lst)
Tuple List list(t)
List Set set(lst)
Set List list(s)
String List list(text)
String Set set(text)
Pairs Dict dict(zip(keys, values))

Example: list → tuple

python
lst = [1, 2, 3]

t = tuple(lst)

print(t)
# (1, 2, 3)

Example: list → set (deduplication)

python
marks = [85, 90, 85, 78]

unique = set(marks)

print(unique)
# {90, 85, 78}  — order varies

Preserve order while deduplicating:

python
words = ["apple", "banana", "apple"]
print(list(dict.fromkeys(words)))   # ['apple', 'banana']

4. Dictionary conversions

Keys, values, and items as lists

python
d = {"a": 10, "b": 20}

print(list(d.keys()))
print(list(d.values()))
print(list(d.items()))

Output:

text
['a', 'b']
[10, 20]
[('a', 10), ('b', 20)]

Build a dictionary from two lists

python
keys = ["id", "name"]
values = [101, "RS"]

student = dict(zip(keys, values))

print(student)
# {'id': 101, 'name': 'RS'}

5. Deduplicate → sort → rebuild pipeline

This is an interview favorite.

list to set to sorted to tuple pipeline

Remove duplicates → sort → create immutable tuple.

python
data = (10, 5, 10, 3, 5)

result = tuple(sorted(set(data)))

print(result)
# (3, 5, 10)

Why this works:

  1. set() removes duplicates
  2. sorted() returns a sorted list
  3. tuple() converts it into an immutable sequence

One-liner for a list:

python
marks = [85, 90, 85, 78, 90]
print(tuple(sorted(set(marks))))

6. Fixing "unhashable type" errors

Most common Python collection error:

text
TypeError: unhashable type: 'list'
Wrong list in set vs correct tuple in set

Wrong

python
my_set = {[1, 2]}
# TypeError

Correct

python
my_set = {(1, 2)}

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

Another common mistake

Wrong:

python
cache = {{1: 2}: "value"}   # TypeError

Correct:

python
cache = {("x", "y"): "value"}
cache = {frozenset({"read"}): "viewer"}

Reason: Dictionary keys must always be hashable.

Error context Fix
List in set Use tuple(lst) if elements are hashable
Dict in set Not allowed — use list of dicts or frozenset of keys
Dict as key Use str, int, tuple, or frozenset

Mini project — role permission cache

Use tuples and frozensets as hashable keys.

Role permission cache with tuple and frozenset keys
python
valid = {
    (1, 2),
    frozenset({"read"})
}

permissions = {
    ("read", "write"): "admin",
    ("read",): "viewer"
}

print(valid)
print(permissions[("read", "write")])

Output:

text
{(1, 2), frozenset({'read'})}
admin

Interview summary

Concept Remember
Hashable Can be dict key or set element
Unhashable Mutable containers (list, dict, set)
Tuple Hashable only if contents are hashable
Frozenset Immutable + hashable
Deduplication set(list)
Sorted unique tuple tuple(sorted(set(data)))
Pairs → dict dict(zip(keys, values))

Common interview mistakes

Mistake 1 — using a list as a set element:

python
# TypeError
# s = {[1, 2]}
s = {(1, 2)}

Mistake 2 — assuming all tuples are hashable:

python
# TypeError — list inside tuple
# hash((1, [2, 3]))
hash((1, 2, 3))   # OK

Mistake 3 — forgetting set loses order:

python
# Need sorted unique list, not just set
sorted(set([3, 1, 2, 1]))        # [1, 2, 3]
tuple(sorted(set([3, 1, 2, 1]))) # (1, 2, 3)

Mistake 4 — confusing outer immutability with inner mutability:

python
t = (10, [1, 2])
t[1].append(3)   # works — list inside is mutable
# t[0] = 99      # TypeError — tuple shell is fixed

Practice questions

Test yourself before File 15 — Practice Programs:

  1. Why is {[1, 2]} invalid?
  2. Convert [1, 2, 2, 3] into a sorted unique tuple.
  3. Can a tuple containing a list be a set element?
  4. How do you build a dict from two parallel lists?
  5. What is the fix for TypeError: unhashable type: 'dict' as a key?

Knowledge check

Q1: Why is {[1, 2]} invalid?
Answer: Lists are mutable and unhashable — they cannot be set elements.

Q2: Convert [1, 2, 2, 3] into a sorted unique tuple?
Answer: tuple(sorted(set([1, 2, 2, 3]))) → (1, 2, 3).

Q3: Can a tuple containing a list be a set element?
Answer: No — the inner list makes the tuple unhashable.

Q4: Build dict from keys = ["a","b"], values = [1, 2]?
Answer: dict(zip(keys, values)).

Q5: Dict as dictionary key — allowed?
Answer: No — use tuple, frozenset, str, or int instead.

Key takeaways

  • Hashable = stable hash → valid dict key or set element.
  • Mutable containers (list, dict, set) are unhashable.
  • Tuple is hashable only when every element inside is hashable.
  • Convert with tuple(), list(), set(), and dict(zip(...)).
  • Pipeline: tuple(sorted(set(data))) for sorted unique immutable results.

Loading playground…