python - perfectly mimic inheritance with composition -
i attempting wrap class third-party package in such way new class looks subclass of third-party class. third-party class not support inheritance, , has nontrivial features, such functions have __getitem__
method. can wrap every attribute , method using solution based on wrapping class methods return instances of class , how can intercept calls python's "magic" methods in new style classes?. however, still need override __init__
method of third-party class. how can that? note: using new-style classes.
code far:
import copy class wrappermetaclass(type): """ works `wrapper` class create proxies wrapped object's magic methods. """ def __init__(cls, name, bases, dct): def make_proxy(name): def proxy(self, *args): return getattr(self._obj, name) return proxy type.__init__(cls, name, bases, dct) if cls.__wraps__: ignore = set("__%s__" % n n in cls.__ignore__.split()) name in dir(cls.__wraps__): if name.startswith("__"): if name not in ignore , name not in dct: setattr(cls, name, property(make_proxy(name))) class wrapper(object): """ used provide (nearly) seamless inheritance-like interface classes not support direct inheritance. """ __metaclass__ = wrappermetaclass __wraps__ = none # note __init__ method ignored wrappermetaclass __ignore__ = "class mro new init setattr getattr getattribute dict" def __init__(self, obj): if self.__wraps__ none: raise typeerror("base class wrapper may not instantiated") elif isinstance(obj, self.__wraps__): self._obj = obj else: raise valueerror("wrapped object must of %s" % self.__wraps__) def __getattr__(self, name): if name '_obj': zot = 1 orig_attr = self._obj.__getattribute__(name) if callable(orig_attr) , not hasattr(orig_attr, '__getitem__'): def hooked(*args, **kwargs): result = orig_attr(*args, **kwargs) if result self._obj: return self elif isinstance(result, self.__wraps__): return self.__class__(result) else: return result return hooked else: return orig_attr def __setattr__(self, attr, val): object.__setattr__(self, attr, val) if getattr(self._obj, attr, self._obj) not self._obj: # update _obj's member if exists setattr(self._obj, attr, getattr(self, attr)) class classtowrap(object): def __init__(self, data): self.data = data def theirfun(self): new_obj = copy.deepcopy(self) new_obj.data += 1 return new_obj def __str__(self): return str(self.data) class wrapped(wrapper): __wraps__ = classtowrap def myfun(self): new_obj = copy.deepcopy(self) new_obj.data += 1 return new_obj # can't instantiate wrapped directly! problem! obj = classtowrap(0) wr0 = wrapped(obj) print wr0 >> 0 print wr0.theirfun() >> 1
this works, seamless inheritance-like behavior, need instantiate wrapped
directly, e.g.
wr0 = wrapped(0)
which throws
valueerror: wrapped object must of <class '__main__.classtowrap'>
i attempted override defining new proxy __init__
in wrappermetaclass
, rapidly ran infinite recursions.
my codebase complex users @ different skill levels, can't afford use monkey-patching or solutions modify definition of example classes classtowrap
or wrapped
. hoping extension code above overrides wrapped.__init__
.
please note question not duplicate of e.g. can mimic inheritance behavior delegation composition in python?. post not have answer detailed i'm providing here.
it sounds want wrapper.__init__
method work differently does. rather taking existing instance of __wraps__
class, should take arguments other class expects in constructor , built instance you. try this:
def __init__(self, *args, **kwargs): if self.__wraps__ none: raise typeerror("base class wrapper may not instantiated") else: self._obj = self.__wraps__(*args, **kwargs)
if want wrapper
remain same reason, put logic in new wrapped.__init__
method instead:
def __init__(self, data): # i'm explicitly naming argument here, use *args super(self, wrapped).__init__(self.__wraps__(data)) # , **kwargs make extensible
Comments
Post a Comment