Skip to main content

How to Check Key Value Hashability in Python

In Python, understanding hashability is essential when working with dictionaries and sets. An object is hashable if it has a hash value that never changes during its lifetime and can be compared to other objects. Only hashable objects can be used as dictionary keys or stored in sets.

This guide explains how to programmatically verify if an object is hashable, differentiates between mutable and immutable types, and provides solutions for making unhashable data usable in hash-based collections.

Understanding Hashability

An object is hashable if it has a __hash__() method that returns an integer. In Python:

  • Immutable types are generally hashable: int, float, str, tuple (if contents are hashable), frozenset.
  • Mutable types are generally unhashable: list, dict, set.

If you try to use an unhashable object as a dictionary key, Python raises a TypeError.

Method 1: Using the hash() Function (Try-Except)

The most robust way to check for hashability is to attempt to hash the object and catch the error if it fails. This follows the Pythonic "Ask for Forgiveness, not Permission" (EAFP) principle.

def is_hashable(obj):
try:
# ✅ Correct: Attempt to compute the hash
hash(obj)
return True
except TypeError:
# ⛔️ Error: Object is not hashable (e.g., list, dict)
return False

# Test Cases
print(f"Integer (42): {is_hashable(42)}")
print(f"String ('TutorialReference'): {is_hashable('TutorialReference')}")
print(f"List ([1, 2]): {is_hashable([1, 2])}")

Output:

Integer (42): True
String ('TutorialReference'): True
List ([1, 2]): False

Method 2: Using collections.abc.Hashable

For a cleaner, type-checking approach, you can check if an object is an instance of the abstract base class Hashable.

from collections.abc import Hashable

def check_hashability_abc(obj):
# ✅ Correct: Check against the abstract base class
if isinstance(obj, Hashable):
print(f"Object '{obj}' is hashable.")
else:
print(f"Object '{obj}' is NOT hashable.")

check_hashability_abc((1, 2)) # Tuple
check_hashability_abc({"a": 1}) # Dict

Output:

Object '(1, 2)' is hashable.
Object '{'a': 1}' is NOT hashable.
warning

isinstance(obj, Hashable) might return True for some objects (like tuples containing lists) that will still fail at runtime. The try-except hash() method (Method 1) is safer for complex nested structures.

Handling Unhashable Types (Tuples vs Lists)

A common scenario involves trying to use a list as a dictionary key. Since lists are mutable, they are unhashable. The solution is to convert the list into a tuple.

Problem: Nested Unhashable Elements

Even tuples can be unhashable if they contain mutable items.

# A tuple containing a list
mixed_tuple = (1, 2, [3, 4])

try:
# ⛔️ Error: The tuple is immutable, but the list inside is not
print(f"Hash: {hash(mixed_tuple)}")
except TypeError as e:
print(f"Error: {e}")

# ✅ Solution: Convert inner list to tuple
safe_tuple = (1, 2, (3, 4))
print(f"Safe Hash: {hash(safe_tuple)}")

Output:

Error: unhashable type: 'list'
Safe Hash: 3794340727080330424
note

Hash may vary.

Practical Example: Making Data Hashable

If you need to use a list of data as a key, create a helper to freeze it.

def make_hashable(value):
if isinstance(value, list):
return tuple(make_hashable(v) for v in value)
return value

data = [1, [2, 3], 4]
key = make_hashable(data)

# Now it works as a dictionary key
my_dict = {key: "Processed Data"}
print(f"Dictionary Key: {list(my_dict.keys())[0]}")

Output:

Dictionary Key: (1, (2, 3), 4)

Conclusion

To check if a value can be used as a dictionary key or set element:

  1. Use hash(obj) inside a try-except TypeError block for the most reliable verification.
  2. Use isinstance(obj, Hashable) for quick static type checking (with caveats on nested structures).
  3. Convert mutable types (lists) to immutable types (tuples) if you need to hash them.