I would like to implement a forwarder class in Python that implements some base class, which takes in its constructor another implementation of the same base class and sends it to this class for each method in the base class.
This can be useful for providing a tuning point, adding caching for certain methods, logging around each call site, etc.
Just write it by hand. Given this base class:
class BaseClass(object): def method_a(self, *args): pass @property def prop_b(self): pass def method_c(self, a, b, **kwargs): pass
There is a direct forwarding implementation here.
class ForwardBaseClass(BaseClass): def __init__(self, underlying_implementation): self._impl = underlying_implementation def method_a(self, *args): return self._impl.method_a(*args) @property def prop_b(self): return self._impl.prop_b def method_c(self, a, b, **kwargs): return self._impl.method_c(a, b, **kwargs)
The disadvantage of writing code is that there are many code templates, and this code must be written for each method. Since methods are added to the base class, similar code must be added to the forwarding class; and if changes are desired in how the class performs its redirects, they should be distributed across all methods. (Imagine, for example, that we wanted to change a class so that it uses the context manager that it used for each call.)
Is there a short, Pythonic way to do this, either in the base language, with built-in modules, or with some reliable module in PyPI?
Desired features:
- Signatures of the exact method
- The forwarded signature must match the base class
- No
*args, **kwargs for each signature
- Methods with the
@property decorator wrapped correctly __<method>__ methods, if they exist, are properly wrapped- No extra cost per method call for straightforward implementation
dir(instance) does the same thing as a straightforward implementation
Nice to have:
- Error messages in which the base class does not meet certain criteria
- Significant docstrings
- Ability to output from the resulting object
- Methods with the
@staticmethod decorator @staticmethod sent to the embedded implementation class - Methods with the
@classmethod decorator @classmethod sent to the embedded implementation class __init__ and __new__ not redirected
Places where additional complexity is likely:
- The base class has a metaclass
- The base class has several base classes of its own.
- Some of the more esoteric
__<method>__ and their semantics
Really don't care:
- Several base classes
- Custom descriptor decoders other than
@property , @staticmethod and @classmethod - Changes to the base class after creating the redirect class