Method resolution for super(Class, obj).

Discussion in 'Python' started by ddtl, Sep 7, 2006.

  1. ddtl

    ddtl Guest

    Hello everybody.

    Consider the following code:


    class A(object):
    def met(self):
    print 'A.met'
    class B(A):
    def met(self):
    print 'B.met'
    super(B,self).met()
    class C(A):
    def met(self):
    print 'C.met'
    super(C,self).met()
    class D(B,C):
    def met(self):
    print 'D.met'
    super(D,self).met()
    d = D()
    d.met()


    When executed, it prints:

    D.met
    B.met
    C.met
    A.met

    The book (Python in a nutshell, 2nd edition) explains:

    "The solution is to use built-in type super. super(aclass, obj),
    which returns a special superobject of object obj. When we look
    up an attribute (e.g., a method) in this superobject, the lookup
    begins after class aclass in obj's MRO."

    But I don't understand - MRO means that when attribute is found
    somewhere in hierarchy, the search for it stops, that is: when
    d.met() is executed, it is supposed to print 'D met', call
    super(D,self).met() which should resolve met() to be B's attribute,
    and after B's met() is executed, we should be done. Why does the
    lookup proceeds from B to C as though met() wasn't found in B?
    Indeed, lookup order (according to a new-style MRO) is B, then C
    and at last A (because of a diamond inheritance), but only when
    attribute is not found in B it is looked up in C, and only if it
    is not found neither in B nor in C it is looked up in A...

    What is different here?

    ddtl.
    ddtl, Sep 7, 2006
    #1
    1. Advertising

  2. ddtl

    Jason Guest

    ddtl wrote:
    > Hello everybody.
    >
    > Consider the following code:
    >
    >
    > class A(object):
    > def met(self):
    > print 'A.met'
    > class B(A):
    > def met(self):
    > print 'B.met'
    > super(B,self).met()
    > class C(A):
    > def met(self):
    > print 'C.met'
    > super(C,self).met()
    > class D(B,C):
    > def met(self):
    > print 'D.met'
    > super(D,self).met()
    > d = D()
    > d.met()
    >
    >
    > When executed, it prints:
    >
    > D.met
    > B.met
    > C.met
    > A.met
    >
    > The book (Python in a nutshell, 2nd edition) explains:
    >
    > "The solution is to use built-in type super. super(aclass, obj),
    > which returns a special superobject of object obj. When we look
    > up an attribute (e.g., a method) in this superobject, the lookup
    > begins after class aclass in obj's MRO."
    >
    > But I don't understand - MRO means that when attribute is found
    > somewhere in hierarchy, the search for it stops, that is: when
    > d.met() is executed, it is supposed to print 'D met', call
    > super(D,self).met() which should resolve met() to be B's attribute,
    > and after B's met() is executed, we should be done. Why does the
    > lookup proceeds from B to C as though met() wasn't found in B?
    > Indeed, lookup order (according to a new-style MRO) is B, then C
    > and at last A (because of a diamond inheritance), but only when
    > attribute is not found in B it is looked up in C, and only if it
    > is not found neither in B nor in C it is looked up in A...
    >
    > What is different here?


    Let's examine what the mro order is for class D:
    >>> D.mro()

    [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>,
    <class '__mai
    n__.A'>, <type 'object'>]

    When you call d.met(), the call dispatches to the D.met() method.
    After printing out 'D.met', you use super() to get the next class in
    the mro order, and call that class's met method.

    As shown with the mro(), the class after D is B. So B.met() is called.
    Normally, we would be done. But take a look at B's method!

    > class B(A):
    > def met(self):
    > print 'B.met'
    > super(B,self).met()


    B.met calls super, and invokes the next met method! So, the code does
    exactly what you've asked it to do, and searches for the next class
    after B in the mro list: class C. You are then invoking met method of
    that class. So, class B is calling class C's met method.

    Class C also uses super, and calls the resulting met method on the
    result as well. This finds class A as the next class in the mro list,
    and invokes the met method on it as well.

    When you get to A's met method, you aren't calling another met method,
    so the print statements end.

    If you want the dispatch to end at B's method, comment out the
    'super(B,self).met()' line:
    >>> class B2(A):

    .... def met(self):
    .... print 'B2.met'

    Alternatively, you could do away with using super entirely, and
    actively call the superclass method that you want:
    >>> class D2(B2, C):

    .... def met(self):
    .... print 'D2.met'
    .... B2.met(self) # Invoke B2's method directly
    ....
    >>> d2 = D2()
    >>> d2.met()

    D2.met
    B2.met

    You don't need super() to call a superclass method. It can help with
    complex class heirarchies, but most single-descendent class structures
    don't need it. Either way, when designing a class heirarchy, you
    should either always use super() or never use super(). Mixing
    non-super-using and super-using can give you problems.

    (Rhetorical Q: Does this make me more or less super?)

    --Jason
    Jason, Sep 7, 2006
    #2
    1. Advertising

  3. ddtl

    Steve Holden Guest

    ddtl wrote:
    > On 7 Sep 2006 10:42:54 -0700, in comp.lang.python you wrote:
    >
    >
    >>Let's examine what the mro order is for class D:
    >>
    >>>>>D.mro()

    >>
    >>[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>,
    >><class '__mai
    >>n__.A'>, <type 'object'>]
    >>
    >>When you call d.met(), the call dispatches to the D.met() method.
    >>After printing out 'D.met', you use super() to get the next class in
    >>the mro order, and call that class's met method.
    >>
    >>As shown with the mro(), the class after D is B. So B.met() is called.
    >>Normally, we would be done. But take a look at B's method!
    >>
    >>
    >>>class B(A):
    >>> def met(self):
    >>> print 'B.met'
    >>> super(B,self).met()

    >>
    >>B.met calls super, and invokes the next met method! So, the code does
    >>exactly what you've asked it to do, and searches for the next class
    >>after B in the mro list: class C.

    >
    >
    > But when super(B,self).met() is invoked, isn't it supposed to look
    > at MRO order of *B*, which is:
    >
    > (<class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
    >

    No, that's the mistake people often make. An instance of type B would
    see B's MRO, but an instance of type D sees D's MRO.

    > and B doesn't have any relation with C, that is: A's met() is the to
    > be called as a result. In effect, what you say impies that a call to
    > super() is context dependant - if super(B,self).met() is invoked as
    > a result of a call to D().met(), the effect is different from the effect
    > of a call to B().met(). But a documentation of a super() doesn't mention
    > anything like that (or at least I didn't find it), and it seems a
    > significant piece of information. Doesn't it imply that there should
    > be another explanation?


    It's all rather better explained in the Nutshell Guide than it is in the
    Python documentation. But basically you've got it right: it's the class
    of the *instance* that determines the MRO used by super().

    regards
    Steve
    --
    Steve Holden +44 150 684 7255 +1 800 494 3119
    Holden Web LLC/Ltd http://www.holdenweb.com
    Skype: holdenweb http://holdenweb.blogspot.com
    Recent Ramblings http://del.icio.us/steve.holden
    Steve Holden, Sep 7, 2006
    #3
  4. ddtl

    ddtl Guest

    On 7 Sep 2006 10:42:54 -0700, in comp.lang.python you wrote:

    >Let's examine what the mro order is for class D:
    >>>> D.mro()

    >[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>,
    ><class '__mai
    >n__.A'>, <type 'object'>]
    >
    >When you call d.met(), the call dispatches to the D.met() method.
    >After printing out 'D.met', you use super() to get the next class in
    >the mro order, and call that class's met method.
    >
    >As shown with the mro(), the class after D is B. So B.met() is called.
    > Normally, we would be done. But take a look at B's method!
    >
    >> class B(A):
    >> def met(self):
    >> print 'B.met'
    >> super(B,self).met()

    >
    >B.met calls super, and invokes the next met method! So, the code does
    >exactly what you've asked it to do, and searches for the next class
    >after B in the mro list: class C.


    But when super(B,self).met() is invoked, isn't it supposed to look
    at MRO order of *B*, which is:

    (<class '__main__.B'>, <class '__main__.A'>, <type 'object'>)

    and B doesn't have any relation with C, that is: A's met() is the to
    be called as a result. In effect, what you say impies that a call to
    super() is context dependant - if super(B,self).met() is invoked as
    a result of a call to D().met(), the effect is different from the effect
    of a call to B().met(). But a documentation of a super() doesn't mention
    anything like that (or at least I didn't find it), and it seems a
    significant piece of information. Doesn't it imply that there should
    be another explanation?

    ddtl.
    ddtl, Sep 7, 2006
    #4
  5. ddtl a écrit :
    > On 7 Sep 2006 10:42:54 -0700, in comp.lang.python you wrote:
    >
    >
    >>Let's examine what the mro order is for class D:
    >>
    >>>>>D.mro()

    >>
    >>[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>,
    >><class '__mai
    >>n__.A'>, <type 'object'>]
    >>
    >>When you call d.met(), the call dispatches to the D.met() method.
    >>After printing out 'D.met', you use super() to get the next class in
    >>the mro order, and call that class's met method.
    >>
    >>As shown with the mro(), the class after D is B. So B.met() is called.
    >>Normally, we would be done. But take a look at B's method!
    >>
    >>
    >>>class B(A):
    >>> def met(self):
    >>> print 'B.met'
    >>> super(B,self).met()

    >>
    >>B.met calls super, and invokes the next met method! So, the code does
    >>exactly what you've asked it to do, and searches for the next class
    >>after B in the mro list: class C.

    >
    >
    > But when super(B,self).met() is invoked, isn't it supposed to look
    > at MRO order of *B*,


    No. It's supposed to look at the MRO of self for what comes after B.
    Bruno Desthuilliers, Sep 10, 2006
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Guest

    super.super.super how?

    Guest, Feb 19, 2005, in forum: Java
    Replies:
    24
    Views:
    10,736
    Darryl Pierce
    Feb 24, 2005
  2. Fernando Rodriguez

    Getting the super class via the super() function

    Fernando Rodriguez, Nov 21, 2003, in forum: Python
    Replies:
    2
    Views:
    708
    Bob Willan
    Nov 22, 2003
  3. metaperl
    Replies:
    4
    Views:
    412
    Steve Holden
    Sep 8, 2006
  4. zweibieren

    A need for super.super.method()

    zweibieren, May 7, 2009, in forum: Java
    Replies:
    0
    Views:
    441
    zweibieren
    May 7, 2009
  5. fi3nd
    Replies:
    0
    Views:
    370
    fi3nd
    Apr 8, 2010
Loading...

Share This Page