Skip to main content

A decorator that makes objects immutable after their hash is calculated

Project description

lazy-freeze

A Python decorator that makes objects immutable after their hash is calculated.

Overview

lazy-freeze provides a simple solution to a common problem in Python: ensuring immutability of objects after they're used as dictionary keys. This is implemented as a decorator that makes objects behave normally until their hash is calculated, at which point they become immutable.

Installation

Clone this repository:

git clone https://github.com/username/lazy-freeze.git
cd lazy-freeze

Usage

Basic Usage

from lazy_freeze import lazy_freeze

@lazy_freeze
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __hash__(self):
        return hash((self.name, self.age))
    
    def __eq__(self, other):
        if not isinstance(other, Person):
            return False
        return self.name == other.name and self.age == other.age

# Create a person
p = Person("Alice", 30)

# Modify before hash - this works fine
p.age = 31

# Take the hash - this freezes the object
h = hash(p)

# Try to modify after hash - this raises TypeError
try:
    p.age = 32
except TypeError as e:
    print(f"Error: {e}")  # Error: Cannot modify Person after its hash has been taken

Debug Mode

Enable debug mode to capture stack traces when an object's hash is taken:

@lazy_freeze(debug=True)
class DebugPerson:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __hash__(self):
        return hash((self.name, self.age))

# Create and hash a person
p = DebugPerson("Alice", 30)
h = hash(p)

# Attempting to modify will show where the hash was calculated
try:
    p.age = 32
except TypeError as e:
    print(f"Error:\n{e}")
    # Output will include the stack trace from when hash(p) was called

Selective Attribute Freeze

If your __hash__ implementation only depends on certain attributes, you can selectively freeze only those attributes:

@lazy_freeze(freeze_attrs=["name", "age"])
class PartiallyFrozenPerson:
    def __init__(self, name, age, description):
        self.name = name
        self.age = age
        self.description = description  # Not used in hash
        
    def __hash__(self):
        return hash((self.name, self.age))  # Only uses name and age
    
    def __eq__(self, other):
        if not isinstance(other, PartiallyFrozenPerson):
            return False
        return self.name == other.name and self.age == other.age

# Create and hash a person
p = PartiallyFrozenPerson("Alice", 30, "Software Engineer")
h = hash(p)

# Frozen attributes cannot be modified
try:
    p.name = "Bob"  # This will raise TypeError
except TypeError as e:
    print(f"Error: {e}")

# Non-frozen attributes can still be modified
p.description = "Senior Engineer"  # This works fine

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lazy_freeze-0.1.0.tar.gz (6.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lazy_freeze-0.1.0-py3-none-any.whl (6.5 kB view details)

Uploaded Python 3

File details

Details for the file lazy_freeze-0.1.0.tar.gz.

File metadata

  • Download URL: lazy_freeze-0.1.0.tar.gz
  • Upload date:
  • Size: 6.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.3

File hashes

Hashes for lazy_freeze-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f047bb34376c8369098194bd194e5759b934103455e0e79ce90e3d8a5e9d51c8
MD5 f9e1edcd39062e6b86cacf71f77deab6
BLAKE2b-256 777b01a30d2c1da1af1e0b699fc658f15dd26bde5704f6f0bbed311903cba1af

See more details on using hashes here.

File details

Details for the file lazy_freeze-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: lazy_freeze-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.3

File hashes

Hashes for lazy_freeze-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 168a8508f488e1f82f2fed7cca71e8d03dd409820f28b58cedb8647c241bdf82
MD5 e14f0e68e6a89eb0f79ff2c0b62a1446
BLAKE2b-256 186e3baf607efa47299af8d3c829af74094a2bf2ee34dd21f0b15e2b81dcc3e6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page