Separating Concerns Using Object Roles |
Separating Concerns Using Object Roles |
====================================== |
====================================== |
|
|
(New in version 0.6: ``ClassRole.for_frame()``, ``Registry``) |
(NEW in version 0.6: the``Registry`` base class, and the |
|
``ClassRole.for_frame()`` classmethod.) |
|
|
In any sufficiently-sized application or framework, it's common to end up |
In any sufficiently-sized application or framework, it's common to end up |
lumping a lot of different concerns into the same class. For example, you |
lumping a lot of different concerns into the same class. For example, you |
one (or is a new-style class with a read-only ``__dict__``), they are stored in |
one (or is a new-style class with a read-only ``__dict__``), they are stored in |
a special dictionary linked to the subject via a weak reference. |
a special dictionary linked to the subject via a weak reference. |
|
|
By default, the dictionary key is a one-element tuple containing the role |
By default, the dictionary key is the role class, so there is exactly one role |
class, so that there is exactly one role instance per subject:: |
instance per subject:: |
|
|
>>> aThing.__dict__ |
>>> aThing.__dict__ |
{<class 'Persistence'>: <Persistence object at...>} |
{<class 'Persistence'>: <Persistence object at...>} |
... |
... |
AttributeError: 'NoDict' object has no attribute '__leech__' |
AttributeError: 'NoDict' object has no attribute '__leech__' |
|
|
Of course, if an object doesn't have a dictionary *and* isn't weak- |
Of course, if an object doesn't have a dictionary *and* isn't |
referenceable, there's simply no way to store a role for it:: |
weak-referenceable, there's simply no way to store a role for it:: |
|
|
>>> ob = object() |
>>> ob = object() |
>>> Leech(ob) |
>>> Leech(ob) |
Alternately, you can pass a specific Python frame object via the ``frame`` |
Alternately, you can pass a specific Python frame object via the ``frame`` |
keyword argument to ``for_enclosing_class()``, or use the ``for_frame()`` |
keyword argument to ``for_enclosing_class()``, or use the ``for_frame()`` |
classmethod instead. ``for_frame()`` takes a Python stack frame, followed by |
classmethod instead. ``for_frame()`` takes a Python stack frame, followed by |
any additional arguments needed to create the key. |
any extra positional arguments needed to create the key. |
|
|
|
|
Class Registries |
Class Registries (NEW in version 0.6) |
~~~~~~~~~~~~~~~~ |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
For many of common class role use cases, you just want a dictionary-like object |
For many of common class role use cases, you just want a dictionary-like object |
with "inheritance" for the values in base classes. The ``Registry`` base class |
with "inheritance" for the values in base classes. The ``Registry`` base class |