Today I come across this problem for the N+1st time. Here are some classes for the example:
class Observable: """Implements the observer-observable pattern.""" def __init__(self): # initialization code here... super(Observable, self).__init__() class AppServerSessionMixin: # There is no __init__ here, this is a mixin pass class Widget(Observable, AppServerSessionMixin): def __init__(self, appserver, session): self.appserver = appserver self.session = session # general widget initialization code here... super(Widget, self).__init__() class VisualWidget(Widget): def __init__(self, appserver, session): # some more code here for visually visible widgets... super(VisualWidget, self).__init__(appserver, session) 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) 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) class JqueryUiWidget(VisualWidget): def __init__(self, appserver, session): # jquery ui specific code for all widgets (not just desktops) super(JqueryUiWidget, self).__init__(appserver, session) class JqueryUiDesktop(Widget, BaseDesktopMixIn): def __init__(self, appserver, session): # there is NOTHING else here, it just connects jquery ui widget implementation with desktop methods super(JqueryUiDesktop, self).__init__(appserver, session) Here is a part of the hierarchy: Observable AppServerSessionMixin \ / \ / Widget (__init__ with two parameters is first introduced here) | VisualWidget | BootstrapWidget BaseDesktop \ / BootstrapDesktop The problem is obvious: because of the method resolution order, the super call in Observable.__init__ will try to call BaseDesktop.__init__ without arguments, but that constructor has needs to arguments. The arguments are lost when Widget calls super() without them. 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. This is time consuming and error prone. There is a single class (Widget) that has changed the signature of the constructor. I was thinking about cutting the MRO list somehow into two parts. It would be very nice to tell Python to create a separate MRO list for classes above and below the Widget class. Classes below Widget would not see any method above Widget, and that would allow me to use super() anywhere in the class hierarchy below Widget. I would only have to do an explicit call when the method signature is changed. That would save me a lot of parameter retyping and refactoring. 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. Here is a proposal: * method signature changes can be detected syntactically, relatively easily * raise an exception when super() is called in a method has changed the signature (from any of base class(es)) * when a method changes signature, then split the MRO automatically into two parts. The tail of the MRO "below" the signature-changing-class should end in the method that has changed signature, and that method would be responsible for calling (or not calling) the method(s) with the same name inherited from base classes. Of course, this would require Python to calculate an MRO that depends on the name of the method, and not just the class hierarchy. And also the signatures of the methods, but those can also be changed dynamically. So this may be a bad idea after all. Please let me know what you think. Laszlo -- https://mail.python.org/mailman/listinfo/python-list