Pure Python mutable keys dictionary class.
Project description
MutableKeysDict
A pure Python dictionary class that allows the keys to be mutated after insertion.
Why MutableKeysDict?
Standard Python dictionaries use the hash of a key at insertion time. If you mutate a hashable object after using it as a key, the dictionary can't find it anymore because the hash has changed. MutableKeysDict solves this problem by tracking key mutations and maintaining access to your values even after the keys change.
Perfect for:
- Using mutable hashable objects as dictionary keys
- Tracking objects that change over time
- Building data structures where key identity matters more than key value
Note: Keys must still be hashable (implement __hash__). If you need truly unhashable keys, check out dictanykey.
Installation
pip install mutablekeysdict
Requirements: Python 3.8+
Quick Start
from mutablekeysdict import MutableKeysDict
# Create a hashable list class
class HashableList(list):
def __hash__(self):
return hash(tuple(self))
# Use it as a dictionary key
h = HashableList([1, 2, 3])
d = MutableKeysDict({h: 6})
# Mutate the key
h.append(4)
# Still works! 🎉
print(d[h]) # Output: 6
# Standard dict would raise KeyError here
standard_dict = {h: 6}
h.append(5)
# standard_dict[h] # KeyError!
Features
- ✅ Full dict API compatibility - Drop-in replacement for standard dictionaries
- ✅ Mutable key support - Access values even after keys are mutated
- ✅ Type hints - Full mypy compatibility
- ✅ Thoroughly tested - 95%+ code coverage with 52+ tests
- ✅ Modern Python - Supports Python 3.8+
- ✅ Pure Python - No dependencies
- ✅ Dict union operators - Supports
|and|=operators (Python 3.9+)
Usage Examples
Basic Operations
from mutablekeysdict import MutableKeysDict
# Create from dict
d = MutableKeysDict({'a': 1, 'b': 2})
# All standard dict operations work
d['c'] = 3
print(len(d)) # 3
print('a' in d) # True
print(list(d.keys())) # ['a', 'b', 'c']
# Update with another dict
d.update({'d': 4})
# Use dict union operators (Python 3.9+)
d2 = d | {'e': 5}
Working with Mutable Keys
class MutableKey:
def __init__(self, value):
self.value = value
self.metadata = []
def __hash__(self):
return hash(self.value)
def __eq__(self, other):
return self.value == other.value
# Create dictionary with mutable keys
k1 = MutableKey("key1")
k2 = MutableKey("key2")
d = MutableKeysDict({k1: "value1", k2: "value2"})
# Mutate the keys
k1.metadata.append("modified")
k2.metadata.append("also modified")
# Dictionary still works!
print(d[k1]) # "value1"
print(d[k2]) # "value2"
# Can iterate over mutated keys
for key in d.keys():
print(f"{key.value}: {key.metadata}")
Copy and Create Methods
# Create from keys
d = MutableKeysDict.fromkeys(['a', 'b', 'c'], 0)
# {'a': 0, 'b': 0, 'c': 0}
# Shallow copy
d2 = d.copy()
# Replace key
d.replace_key('a', 'new_a')
How It Works
MutableKeysDict maintains an internal mapping between keys and stable indices. When you access a key:
- It checks if any keys have been mutated (hash changed)
- If mutations are detected, it rebuilds the internal mapping
- Returns the value associated with the stable index
This allows the dictionary to track the same key object even when its hash changes, as long as you use the same object reference.
API Reference
MutableKeysDict implements the full collections.abc.MutableMapping interface. All standard dictionary methods are supported:
Standard Methods:
__getitem__,__setitem__,__delitem__keys(),values(),items()get(),pop(),popitem()update(),setdefault(),clear()copy(),fromkeys()(class method)
Additional Methods:
replace_key(old_key, new_key)- Replace a key with a new one while preserving the value
Operators:
==,!=- Equality comparison|,|=- Dict union operators (Python 3.9+)in- Membership testinglen()- Get sizeiter()- Iterate over keys
Version History
v0.1.0 (2025-10-22)
- 🐛 Fixed critical bugs in
__setitem__,popitem(),get(), andupdate() - ✨ Added missing dict methods:
copy(),fromkeys(),__or__(),__ior__() - 🎯 Full mypy type checking support
- ✅ Comprehensive test suite with 95%+ coverage
- 📦 Modernized packaging with pyproject.toml
- 🔧 Python 3.8+ support
Contributing
Contributions are welcome! Here's how to set up your development environment:
Setting Up Development Environment
- Clone the repository:
git clone https://github.com/eddiethedean/mutablekeysdict.git
cd mutablekeysdict
- Install development dependencies:
pip install -e ".[dev]"
This installs the package in editable mode along with:
pytest- Testing frameworkpytest-cov- Coverage reportingmypy- Type checkingruff- Fast lintingblack- Code formatting
Running Tests
Run the full test suite:
pytest tests/
With coverage report:
pytest tests/ --cov=mutablekeysdict --cov-report=term-missing
Run specific test:
pytest tests/test_mutablekeysdict.py::TestMutableKeysDictBasics::test_empty_init
Code Quality
Linting:
ruff check mutablekeysdict tests
Auto-fix issues:
ruff check --fix mutablekeysdict tests
Formatting:
black mutablekeysdict tests
Type checking:
mypy mutablekeysdict
Run all checks:
ruff check mutablekeysdict tests && \
black --check mutablekeysdict tests && \
mypy mutablekeysdict && \
pytest tests/
Project Structure
mutablekeysdict/
├── mutablekeysdict/
│ ├── __init__.py # Package initialization
│ └── mutablekeysdict.py # Main implementation
├── tests/
│ └── test_mutablekeysdict.py # Test suite
├── pyproject.toml # Project configuration
├── README.md # This file
└── CHANGELOG.md # Version history
License
This project is licensed under the MIT License - see the LICENSE file for details.
Author
Odos Matthews
- Email: odosmatthews@gmail.com
- GitHub: @eddiethedean
Links
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
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 mutablekeysdict-0.1.1.tar.gz.
File metadata
- Download URL: mutablekeysdict-0.1.1.tar.gz
- Upload date:
- Size: 8.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb7e7a8b3d3cacb1ca0b0966b6f4a49d9003daede3af49be7aa2a9eb1fbb2145
|
|
| MD5 |
b94981e5a62251f3ae59c7d64c10c327
|
|
| BLAKE2b-256 |
92891da7a0b5f668c74f8ebd2128ee24ac68fd5736f9dc958afa7cd15272a3c6
|
File details
Details for the file mutablekeysdict-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mutablekeysdict-0.1.1-py3-none-any.whl
- Upload date:
- Size: 5.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4541aae8e026946c75852d7ef7932471591e6d5b529f5f398df398a2d028df4
|
|
| MD5 |
7a477ba73537a68cd37870a8d2931330
|
|
| BLAKE2b-256 |
b2cf16b99a9a603aa0c5cffbaf72c63306503e4e67aa76434cf41d81ac135719
|