inheritance - How to mixin behavior using class decorators in Python? -
i have base class has lot of direct sub classes. there multiple independent features shared multiple of sub classes. use case python's cooperative inheritance. however, features should wrap behavior outside, need earlier in method resolution order.
class wrappedsub(featurea, featureb, featurec, realsub): def __init__(self, *args, **kwargs): featurea.__init__(foo=42) featureb.__init__(bar=13) featurec.__init__(foobar=546) realsub.__init__(*args, **kwargs) class realsub(base): # lots of code ...
it nice decorate child classes instead.
@mixin(featurea, 42) @mixin(featureb, 13) @mixin(featurec, 546) class realsub(base): # lots of code ...
precisely, need @mixin
decorator first block below equivalent second.
@mixin(sub, *feature_args, **feature_kwargs) class realsub: # lots of code ... class realsub: # lots of code ... class wrappedsub(feature, realsub): def __init__(self, *sub_args, **sub_kwargs): feature.__init__(self, *feature_args, **feature_kwargs) realsub.__init__(self, *sub_args, **sub_kwargs) realsub = wrappedsub
how possible in python 3?
you can use python's cooperative multiple-inheritance system write mixin classes, rather trying implement them class decorators. how i've understood term "mixin" used in python oop.
class base: def method(self, param): value = param + 18 return value class featureone: # inherit base def method(self, param): if param == 42: return 13 else: return super().method(param) # call next class in inheritance chain class child(featureone, base): def method(self, param): value = super().method(param) value *= 2 return value
this isn't quite same wanted, since calls featureone
class's method
implementation between base
, child
classes' versions, rather before child
thing. instead add new grandchild
class inherits feature
s care first, , child
last, if can't adjust methods work in order (the grandchild
class's body empty).
if want use decorators flip order around, think make work, decorator building "grandchild" class (though doesn't know normal inheritance hierarchy). here's rough attempt @ mixin
decorator works want:
def mixin(*mixin_classes, **mixin_kwargs): # decorator factory function def decorator(cls): # decorator function class wrapper(*mixin_classes, cls): def __init__(self, *args, **kwargs): wrapped_kwargs = mixin_kwargs.copy() # use passed kwargs update wrapped_kwargs.update(kwargs) # mixin args, caller can override super().__init__(*args, **wrapped_kwargs) # maybe modify wrapper's __name__, __qualname__, __doc__, etc. match cls here? return wrapper return decorator
the mixin classes should call super().__init__(*args, **kwargs)
own __init__
method (if have one), can accept (and not pass on) keyword-only arguments of own want passed mixin
decorator:
class featureone: def __init__(self, *args, foo, **kwargs): # note foo keyword-only argument self.foo = foo super().__init__(*args, **kwargs) def method(self, param): if param == self.foo: return 13 else: return super().__method__(param) @mixin(featureone, foo=42) class child(base): def method(self, param): return super().method(param) * 2
the decorator should work either mixin classes passed 1 decorator call (e.g. @mixin(featurea, featureb, featurec, foo=42, bar=13, foobar=546)
), or several nested decorator calls. mro of final class same either way.
Comments
Post a Comment