views:

161

answers:

4

In Python, while designing a multiple inheritance subclass, should I place my app class first or language/framework/third-party class first?

Based on your experience which do you recommend:

1) My app class before a native or third party class

class MyClass(MyAppBaseClass, SomeLibraryOrNativePythonClass):

or

2) A native or third party class before My app class

class MyClass(SomeLibraryOrNativePythonClass, MyAppBaseClass ):

I am concerned, I will accidentally name my methods in MyAppBaseClass such that they will override the same named method in SomeLibraryOrNativePythonClass or its parent classes.

I prefer 1) but as a newbie in multiple inheritance issues, it would be good know, based on your experience with multiple inheritance, which is better approach.

A: 

since you do not want to override any methods on the library base class, you do not need multiple inheritance here, using single inheritance and adding an instance of your own base class as a instance variable seems like the best choice.

you can even go further and override getattr method to check your member instance's variables also, but this may confuse anyone but you in the team.

M. Utku ALTINKAYA
Awesome, I totally forgot about instance variables, thanks! I am new to py as well as MI, so great to know about this. Do you think I need to be concerned about class variables?
Ingenutrix
you are kidding right ?
M. Utku ALTINKAYA
;-) See my response to Alex Martelli's accepted answer
Ingenutrix
A: 

You don't want to override anything unless you're doing so explicitly.

Overriding something in the framework class may break other aspects that depend on it.

Overriding something you created is just going to confuse you because it's not behaving the way you wrote it.

Avoiding conflicts isn't that hard. Look at the documentation for your framework and avoid using really obvious names.

Gabriel Hurley
A: 

The class listed first takes precedence, so if you don't want to override third-party class's members put it second. But then of course the third-party members will override yours so you still have the same problem. That'll always happen with multiple inheritance, you're squishing two namespaces together, so you need to have a good knowledge of well-defined interfaces before you begin.

In any case, if you don't want to override those third-party methods, there's really no point in using multiple inheritance. MI in Python is messy, especially now everything inherits from object so you always get diamond problems for common methods (in particular __init__). You should never include a third party class in MI unless that class is deliberately designed to support MI and documents that decision as part of the interface — otherwise you'll get a dreadful mess on initialisation.

MI really is best avoided if at all possible; composition can usually do better. I'm not at all sure what you're trying to do with MI in your example; if your AppBaseClass is simply there to mark classes as belonging to your module, you could probably do that with a separate flag member (or even just by checking __class__.__module__).

bobince
+2  A: 

I you don't want to override things, it's unlikely that you want to inherit -- possible, as it may offer other advantages, but if inheritance is causing you even the slightest worry, then since it's giving you NO substantial advantages (zero, zilch, none at all whatsoever), then why get involved with inheritance at all?!

If you do want to be able to do explicit overrides but are terrified of accidental one then you might want to proceed as follows. Define a simple decorator:

def override(f):
  f.override = True
  return f

Define all your methods that are explicit, deliberate overrides as:

@override
def foobar(self): ...

Via a class decorator, a custom metaclass, or an explicit call to "check(MyClass)" after the end of class Myclass...:, you can then check that all overrides were explicitly defined to be so. Using a class decorator (2.6 and better only) as an example, so you'd code:

@checkedclass
class MyClass(whateverbasesyouwantorneed):
    ...

you would have

import inspect

def checkedclass(klass):
    oopses = []
    class Fakeclass(klass.__bases__): pass
    for m in inspect.getmembers(klass, inspect.ismethod):
        if not hasattr(Fakeclass, m.__name__): pass
        if hasattr(m, 'override'): pass
        oopses.append(m)
    if oopses:
        ...scream and shout about the accidents!!!...
    return klass

I don't personally fear the need to wear both braces and TWO belts to safeguard against programming errors, but, if you disagree, Python makes it pretty easy to safeguard yourself openly and explicitly just as much as you want!

If you adopt this approach, you will have your custom classes before ones you get from the framework, and the @override on deliberately-overriding methods plus the @checkedclass on every class you define will keep you entirely safe from this very specific kind of programming accident anyway.

Alex Martelli
No, I don't fear programming. If so, I would not be moving from C#/Java to py. I have been dabbling in py for just few months and I moving towards making it my primary lang for next few years :-)and no, I wont be including this approach when I am sole programmer or in company of good programmers but I have worked with some ( where I have no choice ), when I want to leave nothing to a chance.btw, if we all programmers are so sure about our design/coding, why is the emphasis on automated unit/system testing growing so rapidly.and thanks a lot for taking time to write such a detailed answer
Ingenutrix
btw, I am not sure if it is possible to leave comment on a profile at SO. I tried and I could not find a way to.I just wanted to say, I am extremely impressed that you actually took time to code a solution for this question. Thanks.2 thumbs up to you! it is people like you who make SO a great community.
Ingenutrix
Good point on testing! Indeed in tests I do perform deeply introspective sanity checks like the above one. I don't normally have them at runtime, but at startup, eg right after a class or import statement, it might be good to.
Alex Martelli