On 10/21/11, Steven D'Aprano <st...@pearwood.info> wrote: > Alex Hall wrote: >> Hi all, >> I am just curious: I have seen classes that are subclasses initialize >> their parents through both super and parentClass.__init__. What is the >> difference, if any, and is one "better" or "more pythonic" than the >> other? > > > A simple question with a complicated answer... > > > First off, the answer depends on whether you are using so-called > "classic classes" or "new-style classes". I always use new-style (python2.7). > > If you are using Python 3, there are only new-style classes: classic > classes are gone. But in Python 2, classic classes are written like this: > > class MyClass: # Don't inherit from anything. > pass > > > while new-style classes inherit from either object or some other > built-in type which inherits from object: > > class MyClass(object): # Inherit from object, new-style class. > pass > class MyInt(int): pass > class MyStr(str): pass > class MyList(list): pass > # etc. > > > super *does not work* for classic classes, end of story. So in the > following discussion, I'm only talking about new-style classes, the only > sort of class in Python 3. > > Secondly, let's talk about the difference between simple, single > inheritance and multiple inheritance. Single inheritance is when each > class inherits from exactly one parent, or superclass: > > class A(object): pass > class B(A): pass > class C(B): pass > > gives an inheritance hierarchy (a family tree, if you like): > > object > | > A > | > B > | > C > > > In the case of single inheritance, super doesn't do anything special. It > is the recommended way to handle inheritance: you are encouraged to > write something like this: > > class C(B): > def method(self, arg): > x = super().method(arg) # Only works in Python 3 > # or in Python 2, use super(C, self).method(arg) > > instead of x = B.method(arg), but functionality-wise, there is no > difference between the two. In Python 3, super becomes a little more > convenient, but it doesn't really matter much which you use. (But keep > reading, for a reason why you *should* use super even in single > inheritance.) > > The situation is more complicated once you have multiple inheritance. In > multiple inheritance, at least one of the classes involved inherits from > two or more superclasses. Here's a particularly simple example: > > class A(object): pass > class B(A): pass > class C(A): pass > class D(B, C): pass # multiple superclasses > > or: > > object > | > A > / \ > B C > \ / > D > > > In full generality, multiple inheritance can be so complex that most > programming languages prohibit it, or put severe restrictions on it. > Python is one of the very few that support it with very few restrictions. > > The difficulty occurs when you override a method in D. Now you need to > ensure that each superclass (B and C) gets a shot at having their method > called too. Here is a simple example showing how NOT to do it: > > class A(object): > def save(self): > print("class A saves") > > class B(A): > def save(self): > print("B saves stuff") > A.save(self) # call the parent class method too > > class C(A): > def save(self): > print("C saves stuff") > A.save(self) > > class D(B, C): > def save(self): > print ("D saves stuff") > # make sure you let both B and C save too > B.save(self) > C.save(self) > > > Simple, obvious... but wrong. Try it and see: > > >>> d = D() > >>> d.save() > D saves stuff > B saves stuff > class A saves > C saves stuff > class A saves > > The problem is that the A.save method gets called twice. > > In general, it is very hard to solve this problem by hand, especially if > you have a complex family tree. You have to manage the entire family > tree, keeping track of which superclasses you have already called, and > avoid calling them a second time. That's fiddly and annoying and hard to > do right. > > But super can do it for you. Here's a version that works correctly: > > class A(object): > def save(self): > print("class A saves") > > class B(A): > def save(self): > print("B saves stuff") > super(B, self).save() > # In Python 3, you can abbreviate this as super().save() > > class C(A): > def save(self): > print("C saves stuff") > super(C, self).save() > > class D(B, C): > def save(self): > print ("D saves stuff") > super(D, self).save() > > > and in use: > > >>> d = D() > >>> d.save() > D saves stuff > B saves stuff > C saves stuff > class A saves > > Now each class gets called exactly once, and in the right order. That all makes sense, and explains a lot. > > All the smarts managing the entire inheritance hierarchy is built into > super, so each method gets called once and exactly once, provided that > every class *only* uses super. If you try to mix super calls and direct > method calls like B.method(self, arg), it probably won't work correctly, > and if it does, it will probably be by accident. I'll keep it in mind; super() is to be *always* used, or never at all. > > So please use super, even in single inheritance. Otherwise you are > restricting the usefulness of your class: it can never be used with > multiple inheritance. > > The one exception to this is if your class changes the method signature. > E.g. if A.method takes no arguments, but B.method requires an argument. > super cannot help you now. But changing the signature of methods is > almost always the wrong thing to do: it is a violation of good object > oriented design, and should be avoided. The main time it is justified is > in the class constructor methods, __new__ or __init__, in which case you > may need to avoid super and *carefully* manage the inheritance by hand. I'm not sure about this part. Could I not simply do something like: class a(object): def m(self, p1): pass
class b(a): def m(self, p1, p2, *args, **kwords): super(b, self).m(*args, **kwords) #different signatures, but a.m() still gets what it wants, if called correctly Also, what is the difference between __init__ (what I always use) and __new__? If you can change these, why not other methods? Of course these would be the most commonly changed, but the question stands. Thanks! > > -- > Steven > > _______________________________________________ > Tutor maillist - Tutor@python.org > To unsubscribe or change subscription options: > http://mail.python.org/mailman/listinfo/tutor > -- Have a great day, Alex (msg sent from GMail website) mehg...@gmail.com; http://www.facebook.com/mehgcap _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor