Skip to main content

SubclassDict

CI PyPI version Python versions Code coverage License: MIT

A TypeDict that allows subclasses of type keys to be used as keys. When a key is not found, it automatically looks for the closest superclass key, enabling polymorphic behavior in dictionary lookups.

Features

  • Polymorphic lookups: Subclasses automatically find values stored under their parent class keys
  • Performance optimized: Cached subclass lookups for O(1) performance after first access
  • Full dict compatibility: Implements all standard dictionary methods
  • Type safe: Full type hints with generic support
  • Comprehensive: Includes utility functions for class hierarchy traversal

Installation

pip install subclassdict

Quick Start

from subclassdict import SubclassDict

# Define a class hierarchy
class Animal:
    pass

class Dog(Animal):
    pass

class Puppy(Dog):
    pass

# Create a SubclassDict
d = SubclassDict()

# Store values under parent classes
d[Animal] = "I'm an animal"
d[Dog] = "I'm a dog"

# Subclasses can access parent values
print(d[Puppy])  # Output: "I'm a dog" (finds Dog's value)
print(d[Dog])    # Output: "I'm a dog" (direct match)
print(d[Animal]) # Output: "I'm an animal" (direct match)

Real-World Examples

Plugin System

from subclassdict import SubclassDict

class Plugin:
    def __init__(self, name: str):
        self.name = name

class DatabasePlugin(Plugin): pass
class WebPlugin(Plugin): pass
class APIPlugin(WebPlugin): pass

# Register plugins
plugins = SubclassDict()
plugins[Plugin] = "base_plugin"
plugins[DatabasePlugin] = "database_plugin"
plugins[WebPlugin] = "web_plugin"

# Plugin resolution
print(plugins[APIPlugin])  # "web_plugin" (finds WebPlugin)
print(plugins[DatabasePlugin])  # "database_plugin" (direct match)

Event Handling

from subclassdict import SubclassDict

class Event: pass
class UserEvent(Event): pass
class LoginEvent(UserEvent): pass
class LogoutEvent(UserEvent): pass

# Register event handlers
handlers = SubclassDict()
handlers[Event] = "generic_handler"
handlers[UserEvent] = "user_handler"

# Event handling
print(handlers[LoginEvent])   # "user_handler"
print(handlers[LogoutEvent])  # "user_handler"
print(handlers[Event])        # "generic_handler"

Serialization System

from subclassdict import SubclassDict

class Serializable: pass
class JSONSerializable(Serializable): pass
class XMLSerializable(Serializable): pass
class JSONAPISerializable(JSONSerializable): pass

# Register serializers
serializers = SubclassDict()
serializers[Serializable] = "generic_serializer"
serializers[JSONSerializable] = "json_serializer"
serializers[XMLSerializable] = "xml_serializer"

# Serialization
print(serializers[JSONAPISerializable])  # "json_serializer"
print(serializers[XMLSerializable])       # "xml_serializer"

API Reference

SubclassDict

The main class that provides polymorphic dictionary behavior.

Methods

  • __getitem__(key): Get value by key, with subclass lookup
  • __setitem__(key, value): Set value for key
  • __delitem__(key): Delete key
  • __contains__(key): Check if key exists (with subclass lookup)
  • get(key, default=None): Get value with default
  • setdefault(key, default=None): Set default if key not present
  • pop(key, default=None): Pop value with default
  • popitem(): Pop arbitrary item
  • copy(): Create shallow copy
  • clear(): Clear all items and cache

Performance Characteristics

  • First lookup: O(n) where n is the number of keys (searches for superclass)
  • Subsequent lookups: O(1) (cached)
  • Memory: O(k) where k is the number of unique keys accessed

Utility Functions

subclasses(cls)

Get all subclasses of a class recursively.

from subclassdict import subclasses

class Animal: pass
class Dog(Animal): pass
class Cat(Animal): pass
class Puppy(Dog): pass

print(subclasses(Animal))  # [Dog, Cat, Puppy]
print(subclasses(Dog))      # [Puppy]

Advanced Usage

Custom Type Keys

SubclassDict works with any hashable type, not just classes:

d = SubclassDict()
d[str] = "string type"
d[int] = "integer type"

# Non-type keys work normally (no subclass lookup)
d["string"] = "string value"

Cache Management

The cache is automatically managed, but you can inspect it:

d = SubclassDict()
d[Animal] = "animal"

# Access to populate cache
d[Dog]  # This populates the cache

# Inspect cache
print(d._subclass_cache)  # {Dog: Animal}

Performance with Large Hierarchies

SubclassDict is optimized for large class hierarchies:

# Create a deep hierarchy
classes = []
prev_class = None
for i in range(100):
    if prev_class is None:
        new_class = type(f'Class{i}', (), {})
    else:
        new_class = type(f'Class{i}', (prev_class,), {})
    classes.append(new_class)
    prev_class = new_class

d = SubclassDict()
d[classes[0]] = "root"

# Even deep lookups are fast after caching
print(d[classes[-1]])  # Fast O(1) lookup

Comparison with Alternatives

Feature SubclassDict Regular dict Custom lookup
Polymorphic lookups ✅ Automatic ❌ Manual ✅ Manual
Performance ✅ O(1) cached ✅ O(1) ❌ O(n)
Type safety ✅ Full typing ✅ Full typing ❌ Manual
Standard dict methods ✅ All methods ✅ All methods ❌ Manual
Memory usage ✅ Minimal ✅ Minimal ❌ Can be high

Development

Setup

git clone https://github.com/eddiethedean/subclassdict.git
cd subclassdict
pip install -e .[dev]

Running Tests

pytest

Code Quality

# Linting
ruff check .

# Formatting
ruff format .

# Type checking
mypy src/

Pre-commit Hooks

pre-commit install

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Run the test suite
  6. Submit a pull request

See CONTRIBUTING.md for detailed guidelines.

License

MIT License - see LICENSE for details.

Changelog

See CHANGELOG.md for version history.

Troubleshooting

Common Issues

Q: Why doesn't my subclass find the parent's value? A: Make sure the parent class key exists in the dictionary. SubclassDict only looks up the hierarchy, not down.

Q: Performance seems slow with many keys? A: The first lookup for each key is O(n), but subsequent lookups are O(1) due to caching.

Q: Can I use non-class keys? A: Yes, but subclass lookup only works with type objects. Non-type keys work like a regular dictionary.

Performance Tips

  1. Pre-populate cache: Access keys you'll use frequently to populate the cache
  2. Use specific keys: Store values under the most specific class possible
  3. Avoid deep hierarchies: Very deep inheritance chains can impact first-lookup performance

Support

Download files

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

Source Distribution

subclassdict-0.1.1.tar.gz (15.5 kB view details)

Uploaded Source

Built Distribution

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

subclassdict-0.1.1-py3-none-any.whl (8.2 kB view details)

Uploaded Python 3

File details

Details for the file subclassdict-0.1.1.tar.gz.

File metadata

  • Download URL: subclassdict-0.1.1.tar.gz
  • Upload date:
  • Size: 15.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for subclassdict-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d5b84edbcee800182cf8f1782f7e28b05b25020bf6fcb3c504686f12a94ccc45
MD5 352037713c35389c83dee62fb8c9928f
BLAKE2b-256 e08ef02e2255a12fbf36e971a0878a8d57cff9f7ba0212d6ac8de7fddc62e45c

See more details on using hashes here.

File details

Details for the file subclassdict-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: subclassdict-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 8.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for subclassdict-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 89839c6cc1a6a5082bb60d3e42d0711ae6edd0ccd3153b39f7bbbbf5c303846a
MD5 3760273b98af8a11342908b7307deba9
BLAKE2b-256 717d048b619d25f48891a17f3e053c5582cc6ba8528f47f9f16cd996d821623a

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

0.0.1

2 files

Supported by

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