Base types collections.¶
Module Contents¶
Exception for Multiton identity errors. |
Multiton. |
|
Metaclass for the Multiton pattern. |
|
A metaclass that make class immutable. |
|
A metaclass that make class derivation static. |
|
Protocol defining the interface for frozen… |
|
A frozen data class with immutable attributes. |
The type of the |
|
A constrained type variable. |
|
Type alias for a filepath. |
|
Type alias for a file path of any string type. |
|
Sentinel value indicating an attribute has not… |
- exception IDError[source]¶
Extends:
TypeErrorException for Multiton identity errors.
Raised during Multiton instance creation when
__id__arguments do not match__match_args__.See
Multitonfor details.Initialize self. See help(type(self)) for accurate signature.
- class Multiton[source]¶
Multiton.
Implements the Multiton pattern, which extends the Singleton pattern to allow a limited number of instances based on identifying values.
Each unique combination of constructor arguments maps to a single instance. Subsequent calls with the same arguments return the same instance, while different argument combinations create new instances (up to the limit of unique argument combinations).
By default, instances are stored using weak references to prevent memory leaks. When no strong references to an instance remain, it is automatically removed from the internal cache. To disable weak reference behavior and maintain strong references to all instances, set
weakref=Falsewhen defining the class:- class MyClass(Multiton, weakref=False):
…
The __init__ method of each instance is guaranteed to be called exactly once per unique instance, unless explicitly invoked by user code.
To use this class, subclasses must either:
Define a __match_args__ class attribute listing the attribute names used for instance identification, or
Override the __id__ class method to return a tuple of hashable values that uniquely identify instances based on constructor arguments.
Note
The default weak reference behavior means instances will be garbage collected when no longer referenced elsewhere in the program. To keep instances alive, maintain a strong reference to them.
Warning
Overriding
__id__or__match_args__incorrectly can lead to unexpected behavior where different constructor arguments might return the same instance or identical arguments might create different instances.Examples:
>>> class Point(Multiton): ... __match_args__ = ('x', 'y') ... ... def __init__(self, x, y): ... self.x = x ... self.y = y ... >>> p1 = Point(1, 2) >>> p2 = Point(1, 2) >>> p1 is p2 True >>> p3 = Point(3, 4) >>> p1 is p3 FalseSubclassing Interface¶
Multiton provides two overridable methods to customize instance identification and retrieval:
__id__(cls, *args, **kwds) -> tuple[object, ...]Generates a unique instance identifier from constructor arguments.
The default implementation uses
__match_args__to construct a namedtuple from the constructor’s positional and keyword arguments. Override this method to provide custom identification logic when__match_args__alone is insufficient.This method accepts any positional (
*args) and keyword (**kwds) arguments passed to the class constructor and returns a tuple of hashable values that uniquely identify the instance. RaisesIDErrorif the provided arguments do not match the attributes defined in__match_args__and__id__has not been overridden.Examples:
>>> class Point(Multiton): ... __match_args__ = ('x', 'y') ... def __init__(self, x, y): ... self.x = x ... self.y = y ... >>> Point.__id__(1, 2) tmp(x=1, y=2) >>> Point.__id__(x=3, y=4) tmp(x=3, y=4)__get_instance__(cls, value: int, default: T | None = None) -> T | NoneRetrieve an existing instance by its identifier hash.
This method looks up a previously created Multiton instance using the hash value computed from the identifier tuple returned by
__id__. It is intended to be called by a publicget()class method that provides a more user-friendly interface.The
valueparameter should be the integer hash of the instance identifier tuple. Thedefaultparameter specifies the value to return if no instance with the given identifier hash exists (defaults toNone).Examples:
>>> class Point(Multiton): ... __match_args__ = ('x', 'y') ... def __init__(self, x, y): ... self.x = x ... self.y = y ... >>> p1 = Point(1, 2) >>> Point.__get_instance__(hash(Point.__id__(1, 2))) is p1 True >>> Point.__get_instance__(9999) is None True
- class MultitonType(*_args: Any, **_kwds: Any)[source]¶
Extends:
typeMetaclass for the Multiton pattern.
Implements the Multiton pattern where each unique combination of constructor arguments maps to a single instance. Full documentation and usage details are provided in the
Multitonbase class.Example:
class Point(metaclass=MultitonType): __match_args__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = yType creation.
-
ID_METH_NAME =
"'__id__'"¶
-
INSTANCES_MAP_NAME =
"'__instances__'"¶
-
WEAKREF_FLAG_NAME =
"'__multiton_weakref__'"¶
-
ID_METH_NAME =
- class FrozenType[source]¶
Extends:
typeA metaclass that make class immutable.
FrozenType creates types that cannot have their attributes modified after class creation. This provides compile-time safety and prevents accidental or intentional changes to class-level state.
- Immutability Rules:
Deletion: Attributes cannot be deleted from the class
Assignment: Most attributes cannot be modified after creation
- Exceptions:
The following attributes are exempt from immutability and can be modified:
__abstractmethods__: Required for ABC/Protocol functionality__protocol_attrs__: Required for Protocol functionalityAny attribute that is currently
Unset
- Use Cases:
Create classes that should never be modified
Prevent accidental class attribute changes in large codebases
Provide a stable class interface that cannot be altered by consumers
Serve as a base for other metaclasses that need immutability (e.g.,
StaticType)
Examples
Create a frozen class:
class Constants(metaclass=FrozenType): VERSION = "1.0" MAX_SIZE = 100 # These raise TypeError Constants.VERSION = "2.0" # TypeError: cannot set 'VERSION' attribute... del Constants.VERSION # TypeError: cannot delete 'VERSION' attribute...Check if a class is frozen:
class Mutable: pass class Immutable(metaclass=FrozenType): pass type(Mutable) # Returns <class 'type'> type(Immutable) # Returns <class 'FrozenType'>Note
FrozenType only prevents changes at the class level. Instance attributes (stored in
__dict__) are not affected — only class attributes defined on the type itself.
- class StaticType(*_args: Any, **_kwds: Any)[source]¶
Extends:
FrozenType,_ProtocolMetaA metaclass that make class derivation static.
StaticType creates types that “borrow” their attributes (methods, classmethods, staticmethods, etc.) from a base class without using normal class inheritance. When a class inherits from a StaticType-based type, it automatically becomes a new StaticType and borrows all attributes from its parent.
This approach avoids the drawbacks of inheritance (method resolution order issues, diamond problems, tight coupling) while allowing derived classes to use the borrowed behaviors as if they were their own.
- The borrowing mechanism:
Attributes are copied (not referenced) from the parent to the child
The child becomes a new StaticType, allowing further derivation
__slots__from parent and child are merged if both are defined
- Single Inheritance Restriction:
Because a class can only borrow from one source, multiple concrete base classes are not supported. However, this metaclass supports special combination with
typing.Protocolorabc.ABCto allow borrowing from a Protocol while remaining a Protocol.- Immutability:
Like
FrozenType, StaticType makes the created class immutable — attributes cannot be set or deleted after class creation.- Relation to Traits:
StaticType shares the core philosophy of the Traits design pattern: composing behavior without traditional inheritance. However, there are key differences:
Implementation vs Interface: Traits define a contract (interface) that must be implemented by consuming classes. StaticType copies behavior from an already-implemented class—the source already has full implementations, not just signatures.
Multiple Composition: Traits allow composing multiple traits into a single class. StaticType supports only a single borrowing source per class (linear derivation chain).
Commutativity: Traits are commutative—
A + Bis equivalent toB + A. StaticType is not commutative: deriving fromAproduces a different result than deriving fromB, and importantly, you can only derive from one source at a time.Associativity: Traits are associative—
(A + B) + Cis equivalent toA + (B + C). StaticType is not associative. Since you can only borrow from one parent, the derivation is a linear chain:Child → Parent → GrandParent, not a tree or composition.
Examples
First, create a class using StaticType as its metaclass. This class serves as the source of borrowed implementations:
class Vehicle(metaclass=StaticType): def start(self) -> str: return "Engine started" def stop(self) -> str: return "Engine stopped"Now derive from it—attributes are copied (borrowed) to the new class:
class Car(Vehicle): pass # Car borrows start() and stop() from Vehicle c = Car() c.start() # Returns "Engine started"Deriving again creates a linear chain—each level borrows from its parent:
class SportsCar(Car): pass # Linear chain: SportsCar → Car → Vehicle # SportsCar borrows from Car, which borrowed from Vehicle sc = SportsCar() sc.start() # Returns "Engine started"Combine with
typing.Protocolto create a non-instantiable interface that can be implemented by derivation:class Drawable(Protocol, metaclass=StaticType): def draw(self) -> None: ... # Drawable cannot be instantiated (it's a Protocol) Drawable() # Raises TypeError class Shape(Drawable): def draw(self) -> None: print("Drawing shape") # Shape implements Drawable by derivation Shape().draw() # Prints "Drawing shape"
- UnsetType¶
The type of the
Unsetsingleton.The Unset singleton is design to act as a sentinel value that can be assigned to any type and mimics None where possible, while being type-checker friendly.
Example
>>> foo: str = None # static type checker may complain >>> bar: str = Unset # should be valid for static type checker >>> isinstance(bar, str) False >>> not Unset True >>> UnsetType() is Unset TrueSee also
Unset: The singleton instance of this type.
- AnyStr¶
A constrained type variable.
AnyStr is meant to be used for functions that may accept str or bytes arguments but cannot allow the two to mix.
Note
despite its name, AnyStr has nothing to do with the Any type, nor does it mean “any string”. In particular, AnyStr and str | bytes are different from each other and have different use cases.
-
FilePath : TypeAlias =
'AnyStr | PathLike[AnyStr]'¶ Type alias for a filepath.
Represents a path that can be either a string/bytes or an
os.PathLikeobject. The type is parameterized byAnyStr, so a filepath can be either astrorbytesbacked path, but not a mix of the two.Example
>>> def load_config(path: FilePath[str]) -> dict[str, Any]: ... ...
-
AnyFilePath : TypeAlias =
'FilePath[str] | FilePath[bytes]'¶ Type alias for a file path of any string type.
Represents a path that can be either a
str-backed orbytes-backed file path. UnlikeFilePath, this type explicitly allows mixing string and bytes paths at the cost of losing the constraint that paths must be of a consistent type.Example
>>> def find_resource(path: AnyFilePath) -> str: ... ...
- Unset : deluxe._types.UnsetType¶
Sentinel value indicating an attribute has not been set.
This singleton serves as a type-safe alternative to None for indicating the absence of a value. It can be assigned to any type annotation without causing static type checker warnings.
- class FrozenProtocol[source]¶
Extends:
ProtocolProtocol defining the interface for frozen data objects.
This protocol specifies the minimal interface that
Frozenand similar frozen data classes must implement.Example
>>> def process_frozen(obj: FrozenProtocol) -> None: ... for value in obj: ... print(value)
- class Frozen[source]¶
Extends:
FrozenProtocol,deluxe._types._FrozenA frozen data class with immutable attributes.
Frozen provides a declarative way to create immutable objects with named attributes. Attributes are specified via the __frozen__ class variable and become read-only after initial assignment.
Performance¶
Object instantiation is moderately slower than Nameduple but significantly faster than @dataclass or hand-rolled pure python implementations.
Benchmarks (creation time for 3-field objects):
mutable dict or slotted classes are almost equivalent
Named tuple: 1.4x slower
Frozen: 1.6x slower
dataclasses: 2.5x slower
Hand-rolled frozen: 2,5x slower
Use Cases¶
Need Inheritance: Supports inheritances of frozen attributes
Need ABC Mixin: Can combine with ABC for interface design
Allow Gradual Initialization: Frozen attributes can be set after instantiation
Need Mutable Attribute: defining __slots__ allow additional mutable attributes (eg., need a private attribute for internal state)
Prefer NamedTuple for defining simpler immutable type:
faster instantiation
less verbose declaration
simpler type hinting
better support with static type checker
- __frozen__¶
Tuple of attribute names that define the frozen structure. Must be set in subclasses.
- Iteration Protocol:
The class supports iteration over its values. Unset attributes are yielded as Unset sentinel values.
- Example:
>>> class Point(Frozen): ... __frozen__ = ("x", "y") >>> p = Point() >>> p.x = 1 >>> p.y = 2 >>> list(p) [1, 2]
- Sequence Protocol:
Implements sequence-like access via __getitem__ using positional indices (0 to len-1) and supports in, len(), count(), and index() operations.
- Comparison Protocol:
Implements __eq__ for value-based equality comparison with other iterables. Implements __hash__ only when all attributes are set.
- Pickling Support:
Supports serialization via __reduce__ and reconstruction via __setstate__. Frozen instances can be pickled and unpickled while preserving their attribute values.
- raises TypeError:
If an attribute is set twice (immutability violation).
- raises TypeError:
If __hash__ is called when any attribute is still Unset.
- raises AttributeError:
If attempting to delete an attribute.
- raises IndexError:
If __getitem__ receives an out-of-range index.
Example
>>> class User(Frozen): ... __frozen__ = ("name", "email", "age") >>> user = User() >>> user.name = "Alice" >>> user.email = "alice@example.com" >>> user.age = 30 >>> user.name 'Alice' >>> hash(user) -1234567890 >>> user == User(name="Alice", email="alice@example.com", age=30) TrueSee also
FrozenProtocol: Protocol interface for frozen objects.Unset: Sentinel value for unset attributes.