Skip to content

How to Check Key Value Hashability in Python

Learn how to verify if an object is hashable in Python using hash() with try-except or collections.abc.Hashable, and convert unhashable types (like lists) to tuples for dictionary keys or sets.

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:
        hash(obj)
        return True
    except TypeError:
        return False

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):
    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.

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.

mixed_tuple = (1, 2, [3, 4])

try:
    print(f"Hash: {hash(mixed_tuple)}")
except TypeError as e:
    print(f"Error: {e}")

safe_tuple = (1, 2, (3, 4))
print(f"Safe Hash: {hash(safe_tuple)}")

Output:

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

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)

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.
Navigation