How do I get the instance method39s next-in-line parent class from super in Python

De openkb
Aller à : Navigation, rechercher

Sommaire

Questions

I d like to know the type of an instance obtained from super() function. I tried print(super()) and __print(type(super()))__

class Base:
    def __init__(self):
        pass

class Derive(Base):
    def __init__(self):
        print(super())        
        print(type(super()))        
        super().__init__()

d = Derive()

The result is

<super: <class  Derive >, <Derive object>>
<class  super >

With those result, I was wondering how super().__init__() calls the correct constructor.

Answers

From your comments, you want to know how super knows which method to call next. Super inspects the mro of the instance, knows the current class method it s in, and calls the next one in line. The following demo will work in Python 2 and 3, and in Python 2, it prints the name of each class thanks to the metaclass, so I ll use that output:

First the imports and setup to make the printing nicer:

import inspect

class Meta(type):
    def __repr__(cls):
        return cls.__name__

Next, we define a function to tell us what s going on based on the super object itself

def next_in_line(supobj):
    print( The instance class: {} .format(supobj.__self_class__))
    print( in this class s method: {} .format(supobj.__thisclass__))
    mro = inspect.getmro(supobj.__self_class__)
    nextindex = mro.index(supobj.__thisclass__) + 1
    print( super will go to {} next .format(mro[nextindex]))

https://en.wikipedia.org/wiki/C3_linearization https://en.wikipedia.org/wiki/C3_linearization

class O(object):
    __metaclass__ = Meta

    def __init__(self):
        next_in_line(super(O, self))
        super(O, self).__init__()

class A(O):
    def __init__(self):
        next_in_line(super(A, self))
        super(A, self).__init__()


class B(O):
    def __init__(self):
        next_in_line(super(B, self))
        super(B, self).__init__()


class C(O):
    def __init__(self):
        next_in_line(super(C, self))
        super(C, self).__init__()


class D(O):
    def __init__(self):
        next_in_line(super(D, self))
        super(D, self).__init__()


class E(O):
    def __init__(self):
        next_in_line(super(E, self))
        super(E, self).__init__()


class K1(A, B, C):
    def __init__(self):
        next_in_line(super(K1, self))
        super(K1, self).__init__()


class K2(D, B, E):
    def __init__(self):
        next_in_line(super(K2, self))
        super(K2, self).__init__()


class K3(D, A):
    def __init__(self):
        next_in_line(super(K3, self))
        super(K3, self).__init__()


class Z(K1, K2, K3):
    def __init__(self):
        next_in_line(super(Z, self))
        super(Z, self).__init__()

Now when we print the mro of Z, we get the method resolution order defined by this algorithm applied to the inheritance tree:

>>> print(inspect.getmro(Z))
(Z, K1, K2, K3, D, A, B, C, E, O, <type  object >)

And when we call Z(), because our function uses the mro, we ll visit each method in order:

>>> Z()
The instance class: Z
in this class s method: Z
super will go to K1 next
The instance class: Z
in this class s method: K1
super will go to K2 next
The instance class: Z
in this class s method: K2
super will go to K3 next
The instance class: Z
in this class s method: K3
super will go to D next
The instance class: Z
in this class s method: D
super will go to A next
The instance class: Z
in this class s method: A
super will go to B next
The instance class: Z
in this class s method: B
super will go to C next
The instance class: Z
in this class s method: C
super will go to E next
The instance class: Z
in this class s method: E
super will go to O next
The instance class: Z
in this class s method: O
super will go to <type  object > next

And we stop at object.__init__. From the above we can see that super always knows what class of the instance it is in, the class s method that it is currently in, and can deduce from the instance class s MRO where to go next.


I d like to know the name of the base class?

If you only want the direct base (or more than one, in the case of multiple inheritance), you can use the __bases__ attribute, which returns a tuple

>>> Derive.__bases__
(<class __main__.Base at 0xffeb517c>,)

>>> Derive.__bases__[0].__name__
 Base 

I recommend the inspect module for getting the Method Resolution Order (which super follows based on the original caller s class):

>>> import inspect
>>> inspect.getmro(Derive)
(<class __main__.Derive at 0xffeb51dc>, <class __main__.Base at 0xffeb517c>)
  Getting it from super   

super().__self_class__ gives the instance class, and super().__thisclass__ gives us the current class. We can use the instance s MRO and look up the class that comes next. I presume you wouldn t do this in the final parent, so I m not catching an index error:

class Base:
    def __init__(self):
        print(super().__self_class__)
        print(super().__thisclass__)


class Derive(Base):
    def __init__(self):
        print(super().__self_class__)
        print(super().__thisclass__)
        mro = inspect.getmro(super().__self_class__)
        nextindex = mro.index(super().__thisclass__) + 1
        print( super will go to {} next .format(mro[nextindex]))
        super().__init__()


>>> d = Derive()
<class  __main__.Derive >
<class  __main__.Derive >
super will go to <class  __main__.Base > next
<class  __main__.Derive >
<class  __main__.Base >

Source

License : cc by-sa 3.0

http://stackoverflow.com/questions/32014260/how-do-i-get-the-instance-methods-next-in-line-parent-class-from-super-in-p

Related

Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Outils