Skip to main content

A TypeDict that allows subclasses of type keys to be used as keys

Project description

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

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

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.

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