2

given below python program .

class FooBase(object):
   def foo(self): pass

class A(FooBase):
    def foo(self):
        super(A, self).foo()
        print 'A.foo()'

class B(FooBase):
    def foo(self):
        super(B, self).foo()
        print 'B.foo()'

class D(B):
    def foo(self):
        super(D, self).foo()
        print 'D.foo()'


class C(A,D,B):
    def foo(self):
        super(C, self).foo()
        print 'C.foo()'

c=C()
c.foo()

output is

B.foo()
D.foo()
A.foo()
C.foo()

but when i ran below program

class A1(object):
    def get(self):
        print 'A1'
class A2(object):
    def get(self):
        print 'A2'
class A3(object):
    def get(self):
        print 'A3'
class B2(A2):
    def get(self):
        super(B2,self).get()
        print 'b2'
class B3(A3):
    def get(self):
        super(B3,self).get()
        print 'b3'
class C3(B3):
    def get(self):
        super(C3,self).get()
        print 'c3'
class Foo(C3, A1, B2):
    def get(self):
        super(Foo,self).get()
        print 'Foo'



#print Foo.__mro__
Foo().get()

when i excuted the above i got the output as below

output

A3
b3
c3
Foo

the question why does the A1.get() and B2.get() was not called.is there any wrong with the calling of super?

i was expecting the output

A3
b3
c3
A1
A2
b2
Foo

Edit: if anyone explain what is difference between first and second example would be great:)

sundar nataraj
  • 8,524
  • 2
  • 34
  • 46
  • @jonrsharpe this might be different from that. i already got three reopen votes.please reopen and i am seeking better answer. – sundar nataraj Sep 08 '14 at 12:48

1 Answers1

2

You are defining a new style class, subclassing from multiple classes (multiple inheritance). As such,

For old-style classes, the only rule is depth-first, left-to-right. Thus, if an attribute is not found in DerivedClassName, it is searched in Base1, then (recursively) in the base classes of Base1, and only if it is not found there, it is searched in Base2, and so on.

With new-style classes, dynamic ordering is necessary because all cases of multiple inheritance exhibit one or more diamond relationships (where at least one of the parent classes can be accessed through multiple paths from the bottommost class). For example, all new-style classes inherit from object, so any case of multiple inheritance provides more than one path to reach object. To keep the base classes from being accessed more than once, the dynamic algorithm linearizes the search order in a way that preserves the left-to-right ordering specified in each class

Thus, in the linear ordering, only C3.get is called, which in turn calls B3.get, and which calls A3.get


If you want to print the get methods from other classes as well, use the following Foo class:

class Foo(C3, A1, B2):
    def get(self):
        print '='*20 + 'Foo'
        super(Foo, self).get()
        print '='*20 + 'A1'
        super(A1, self).get()
        print '='*20 + 'B2'
        super(B2, self).get()

Then, the code on running should output the right text

$ python file.py 
====================Foo
A3
b3
c3
====================A1
A2
b2
====================B2
A2
Community
  • 1
  • 1
Anshul Goyal
  • 73,278
  • 37
  • 149
  • 186
  • how can i call A1 and b2 get?how does python know which style to use. first example all the class were called and in second example only some . – sundar nataraj Sep 08 '14 at 12:09
  • The problem is that `A1`, `A2`, and `A3` do not call `super` in their implementations of `get`, breaking the chain of calls. To fix, they need to do so, as well as inheriting from a *single* base class (such as `_getroot`) which implements `get` without calling `super`, so that you don't end up trying to call the nonexistent `object.get`. – chepner Sep 08 '14 at 12:16
  • @sundarnatarajСундар Check edits – Anshul Goyal Sep 08 '14 at 12:17
  • when you called A1 how come b2 has come there? – sundar nataraj Sep 08 '14 at 12:19
  • `super` does not invoke the parent's method. Rather, each class has a fixed ordering of all its ancestor classes, and `super(A1, self)` returns a proxy for the next class in the order for `type(self)`, which is not necessarily the parent (or a parent) of `A1`. – chepner Sep 08 '14 at 12:21
  • You can see the method resolution order for the class `Foo` by examining the tuple `Foo.__mro__`. It is (roughly) obtained by doing a depth-first search of the inheritance tree rooted at `Foo`. – chepner Sep 08 '14 at 12:30
  • ```>>> Foo.mro() [, , , , , , , ]``` – wwii Sep 08 '14 at 12:32
  • please comment to question rather than answer.:) – sundar nataraj Sep 08 '14 at 12:32
  • @chepner how does first example differ from second – sundar nataraj Sep 08 '14 at 12:35
  • In the first example, every class that calls `foo` ultimately inherits from `FooBase`. In the second, classes that provide `get` have three distinct "base" classes `A1`, `A2`, and `A3`, which independently "invent" `get`, rather than inheriting from a single ancestor. – chepner Sep 08 '14 at 12:39
  • @chepner thank you i got it. so if there is no proper ancestors.it rather go from left to right in multiple in heritance. if proper ancestors it do right to left .thats correct – sundar nataraj Sep 08 '14 at 12:46
  • 1
    See [this page](https://www.python.org/download/releases/2.3/mro/) for details on how the order is computed. It includes a link to the original paper that defined the C3 resolution order for the programming language Dylan (which uses the much better name `next-method` for its version of `super`). – chepner Sep 08 '14 at 12:51