Nagy László Zsolt <gand...@shopzeus.com> writes: > Today I come across this problem for the N+1st time. Here are some > classes for the example:
Thank you for the example. (Note that ‘__init__’ is not a constructor, because it operates on the *already constructed* instance, and does not return anything. Python's classes implement the constructor as ‘__new__’, and you very rarely need to bother with that.) For the reasons you describe (among others), participating in multiple inheritance is tricky. As described in numerous articles, for example <URL:https://rhettinger.wordpress.com/2011/05/26/super-considered-super/>, the right way to do this is: * Obey the Liskov Substitution Principle (sub-classes should override a method only when they allow all the parent's behaviour as well as their own). This also means that the sub-class should pass any unknown arguments along to the superclass's method to handle. * Once a parameter is handled in a method, remove it from the set and pass only the remaining arguments along to the superclass's method. > class Observable: > """Implements the observer-observable pattern.""" > > def __init__(self): > # initialization code here... > super(Observable, self).__init__() This should be: def __init__(self, **kwargs): # … super(Observable, self).__init__(**kwargs) > class Widget(Observable, AppServerSessionMixin): > def __init__(self, appserver, session): > self.appserver = appserver > self.session = session > # general widget initialization code here... > super(Widget, self).__init__() This should be: def __init__(self, appserver, session, **kwargs): self.appserver = appserver self.session = session # … super(Widget, self).__init__(**kwargs) > class VisualWidget(Widget): > def __init__(self, appserver, session): > # some more code here for visually visible widgets... > super(VisualWidget, self).__init__(appserver, session) Since this function doesn't do anything with the parameters, it doesn't need to have its own names for them: def __init__(self, **kwargs): # … super(VisualWidget, self).__init__(**kwargs) > class BaseDesktop: > def __init__(self, appserver, session): > # general code for all desktops is here... > super(BaseDesktop, self).__init__(appserver, session) > > class BootstrapWidget(VisualWidget): > def __init__(self, appserver, session): > # bootstrap specific code for all widgets (not just desktops) > super(BootstrapWidget, self).__init__(appserver, session) And again: def __init__(self, **kwargs): # … super(BaseDesktop, self).__init__(**kwargs) def __init__(self, **kwargs): # … super(BootstrapWidget, self).__init__(**kwargs) > class BootstrapDesktop(BootstrapWidget, BaseDesktop): > def __init__(self, appserver, session): > # there is NOTHING else here, it just connects bootstrap widget > implementation with desktop methods > super(BootstrapDesktop, self).__init__(appserver, session) If the ‘__init__’ method literally does nothing except call the superclass's method, don't define it in BootstrapDesktop at all. And likewise for the rest: pass along all remaining arguments, and don't write a do-nothing ‘__init__’. > Of course, I could explicitly call constructors of base classes. But > then I cannot use super() anywhere. Even not in places that are far > down in the class hierarchy. This results in typing all method > parameters many times, and also unnecesary refactoring. You avoid this by the ‘**kwargs’ idiom (no need to name arguments you don't explicitly handle), and by not writing any ‘__init__’ if you want the default behaviour (call the superclass's method). > This is time consuming and error prone. As pointed out in Raymond Hettinger's article <URL:https://rhettinger.wordpress.com/2011/05/26/super-considered-super/>, multiple inheritance is inherently tricky and there is an irreducible complexity that has to appear somewhere in your code. > In fact, I could never safely use super() in any case when the method > signature has changed. When signatures are changed, method resolution > must be done manually anyway. Use ‘**kwargs’, and always pass along the remaining ‘**kwargs’ minus-any-parameters-you-already-handled, to protect your existing classes from unnecessary signature changes. -- \ “Creativity can be a social contribution, but only in so far as | `\ society is free to use the results.” —Richard M. Stallman | _o__) | Ben Finney -- https://mail.python.org/mailman/listinfo/python-list