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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f047bb34376c8369098194bd194e5759b934103455e0e79ce90e3d8a5e9d51c8
|
|
| MD5 |
f9e1edcd39062e6b86cacf71f77deab6
|
|
| BLAKE2b-256 |
777b01a30d2c1da1af1e0b699fc658f15dd26bde5704f6f0bbed311903cba1af
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
168a8508f488e1f82f2fed7cca71e8d03dd409820f28b58cedb8647c241bdf82
|
|
| MD5 |
e14f0e68e6a89eb0f79ff2c0b62a1446
|
|
| BLAKE2b-256 |
186e3baf607efa47299af8d3c829af74094a2bf2ee34dd21f0b15e2b81dcc3e6
|