Hi Pythonistas!
Python dictionaries are powerful and flexible. You can store just about anything in them. But when it comes to dictionary keys, Python plays by some important rules. Let’s break it down in the simplest terms
Quick Refresher: What is a Dictionary?
A dictionary in Python is a collection of key-value pairs:
person = {
"name": "Harry",
"house": "Gryffindor"
}
You use the key (like "name") to get the value (like "Harry"). But not everything can be a key. Why? That’s where the concept of hashable comes in.
What Does "Hashable" Mean?
A value is hashable if:
- It has a hash value that doesn’t change during its lifetime.
- It implements the __hash__() method.
- It can be compared to other keys using __eq__().
In simple terms:
If Python can stick it in a hash table (like a dictionary) and reliably find it later, it’s hashable.
To check if something is hashable
>>> hash('hello')
9121822889609927891
>>> hash(1)
1
>>> hash([1, 2, 3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>>
Only immutable types are guaranteed to be hashable.
✅ Valid Dictionary Keys
Here are types that are commonly used as dictionary keys because they're hashable:
Type | Example | Why It's Valid? |
---|---|---|
int |
1 |
Immutable and hashable |
float |
3.14 |
Immutable and hashable |
str |
"hello" |
Immutable and hashable |
tuple |
(1, 2) |
Immutable and hashable if contents are hashable |
bool |
True |
Immutable and hashable |
frozenset |
frozenset({1, 2}) |
Immutable and hashable |
code
>>> data = {
... 'name': "harry",
... 1: "one",
... 0.5: 'half',
... (1, 2): "tuple",
... False: "false",
... frozenset([1, 2, 3]): "frozen set"}
>>> data
{'name': 'harry', 1: 'one', 0.5: 'half', (1, 2): 'tuple', False: 'false', frozenset({1, 2, 3}): 'frozen set'}
>>>
❌ Invalid Dictionary Keys
These types are mutable, so they’re not hashable:
Type | Why Not? |
---|---|
list |
Mutable – contents can change → hash breaks |
dict |
Mutable – same reason |
set |
Mutable – same issue |
code
>>> bad_dict = {[1, 2]: "dont work"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> bad_dict = {{1}: "dont work"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> bad_dict = {{1: 1}: "dont work"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
Even though tuples are immutable, they can still be unhashable if they contain mutable items:
code
>>> a = ([1, 2], 3)
>>> hash(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>>
So always make sure every element inside the tuple is also hashable.
Why Python Requires Keys to Be Hashable ?
When you do this: value = my_dict[key] python calls hash(key) to find the bucket. Uses == to confirm it’s the exact key.
If a key is mutable and its content changes after being used as a key, Python wouldn’t know where to find it anymore. That’s why the key must stay the same forever (i.e. immutable).
Summary
- A dictionary key in Python must be hashable.
- Most immutable types like int, str, and tuple (with hashable contents) work great as keys.
- Mutable types like list, dict, and set cannot be keys.
- You can test with hash(obj) to see if an object is hashable.
I hope you have learned something from this post. Please share your valuable suggestions with afsal@parseltongue.co.in