Generate a Deterministic Hash for Deduplication in Python

Create a stable SHA-256 fingerprint from nested data and file contents to deduplicate records in a data pipeline.

Easy Python 3.10+ Aug 9, 2026 Data pipelines & processing 15 views 0 copies

Python code

41 lines
Python 3.10+
import hashlib
import json
from pathlib import Path

def natural_key_hash(data, salt=""):
    """
    Generate a deterministic fingerprint from raw data (dict/list/str).
    Uses JSON canonical-ish serialization with sorted keys and SHA-256.
    """
    canonical = json.dumps(data, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
    return hashlib.sha256((salt + canonical).encode("utf-8")).hexdigest()

def file_fingerprint(filepath, chunk_size=65536):
    """Compute a deduplication fingerprint for a file's content."""
    hasher = hashlib.sha256()
    with Path(filepath).open("rb") as f:
        for chunk in iter(lambda: f.read(chunk_size), b""):
            hasher.update(chunk)
    return hasher.hexdigest()

if __name__ == "__main__":
    # Deduplicate identical records with different field order
    records = [
        {"name": "Alice", "age": 30, "city": "NYC"},
        {"city": "NYC", "age": 30, "name": "Alice"},
        {"name": "Bob", "age": 25, "city": "LA"},
    ]
    seen = set()
    unique = []
    for rec in records:
        fp = natural_key_hash(rec)
        if fp not in seen:
            seen.add(fp)
            unique.append(rec)
    print("Unique records:", unique)

    # Example file fingerprint (temporary file)
    p = Path("/tmp/dedup_test.txt")
    p.write_text("hello world")
    print("File fingerprint:", file_fingerprint(p))
    p.unlink()

Output

stdout
Unique records: [{'name': 'Alice', 'age': 30, 'city': 'NYC'}, {'name': 'Bob', 'age': 25, 'city': 'LA'}]
File fingerprint: 2ef7bde608ce5404e97d5f042f95f89f1c232871

How it works

The natural_key_hash function serializes data with json.dumps using sort_keys=True to ensure the same logical data regardless of key order produces the same canonical string. SHA-256 is then applied to produce a fixed-length, deterministic fingerprint. For files, the content is hashed chunk-by-chunk to avoid loading large files into memory, which is essential for deduplication at scale. The salt parameter allows domain-specific separation (e.g., per dataset or environment), making fingerprints unique across contexts. This pattern guarantees that identical data—even with different field ordering—collides to the same hash, enabling efficient deduplication with a set.

Common mistakes

  • Forgetting `sort_keys=True` in `json.dumps`, causing different key orders to produce different hashes.
  • Using `hash()` on strings or dicts, which is randomized per Python process and not suitable for deduplication.
  • Not handling non-string data such as floats or bytes during serialization, leading to serialization errors.
  • Hashing entire files without chunking, which can exhaust memory for large data files.

Variations

  1. Use `hashlib.blake2b` for faster hashing with a custom digest size.
  2. Add a version prefix to the salt to handle schema changes without breaking existing fingerprints.

Real-world use cases

  • Deduplicate event records in an ETL pipeline where the same event may appear with different JSON key order.
  • Identify duplicate files in cloud storage by hashing file content and comparing fingerprints across buckets.
  • Generate idempotency keys for API writes by hashing the request payload, preventing duplicate submissions.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Data pipelines & processing

Related tutorials and quizzes for this topic.