70

I am working with some code that has 3 levels of class inheritance. From the lowest level derived class, what is the syntax for calling a method 2 levels up the hierarchy, e.g. a super.super call? The "middle" class does not implement the method I need to call.

smci
  • 32,567
  • 20
  • 113
  • 146
SeanLabs
  • 1,739
  • 4
  • 18
  • 22
  • 10
    Why do you need that? A single `super()` call should suffice, unless you have overwritten the method in the middle class , in which case the middle class should take care of calling the super()'s method right? – Anand S Kumar Jul 05 '15 at 16:00
  • 2
    If the middle class does not implement that method just call `super().()` it should work , because by inheritence your middle class would inherit the methods from the super class – Anand S Kumar Jul 05 '15 at 16:05
  • 2
    Do you mean you want to *skip* an implementation in the MRO? – jonrsharpe Jul 05 '15 at 16:05

5 Answers5

86

This works for me:

class Grandparent(object):
    def my_method(self):
        print "Grandparent"

class Parent(Grandparent):
    def my_method(self):
        print "Parent"

class Child(Parent):
    def my_method(self):
        print "Hello Grandparent"
        super(Parent, self).my_method()
Tomasz
  • 1,001
  • 8
  • 8
  • 18
    This is probably the answer that must be marked as the right answer – nesdis Feb 08 '18 at 03:08
  • 7
    This isn't the best answer because this solution wouldn't work for situations with higher order ancestors. The child class method is hard-coding the call to the Parent's super class. CrazyCasta's first answer, although bad practice, is the right answer to this question. – Tushar Vazirani Apr 02 '19 at 09:38
  • 5
    @TusharVazirani On the other hand, this is the right approach if you specifically want to skip Parent, and want the method from the first class before that, whatever it may be. – oulenz Dec 12 '19 at 15:29
83

Well, this is one way of doing it:

class Grandparent(object):
    def my_method(self):
        print "Grandparent"

class Parent(Grandparent):
    def my_method(self):
        print "Parent"

class Child(Parent):
    def my_method(self):
        print "Hello Grandparent"
        Grandparent.my_method(self)

Maybe not what you want, but it's the best python has unless I'm mistaken. What you're asking sounds anti-pythonic and you'd have to explain why you're doing it for us to give you the happy python way of doing things.

Another example, maybe what you want (from your comments):

class Grandparent(object):
    def my_method(self):
        print "Grandparent"

class Parent(Grandparent):
    def some_other_method(self):
        print "Parent"

class Child(Parent):
    def my_method(self):
        print "Hello Grandparent"
        super(Child, self).my_method()

As you can see, Parent doesn't implement my_method but Child can still use super to get at the method that Parent "sees", i.e. Grandparent's my_method.

CrazyCasta
  • 26,917
  • 4
  • 45
  • 72
  • I don't think you can do nested `super` calls anyway because the type would be `super`. – Malik Brahimi Jul 05 '15 at 16:02
  • In my case the Parent class does not implement my_method, and I don't want to add it just for the sake of getting the child call to work. – SeanLabs Jul 05 '15 at 16:05
  • 4
    You don't need to, middle class inherits methods from parent classes, so doing `super().method()` would work. – Anand S Kumar Jul 05 '15 at 16:06
  • Is the 1st method or 2nd method preferred? Are there any cases where they won't have the same behaviour? – information_interchange Aug 28 '17 at 05:00
  • 2
    @information_interchange Well, generally it's a pretty bad idea to use the first method. I only gave it because I thought it was what was being asked for. The second method is by far preferred. You should not be trying to skip through a higher class if you can help it. – CrazyCasta Aug 28 '17 at 18:42
  • @CrazyCasta One question. Is it usable in interactive IDLE python shell? I think calling super method just works when we save files and running them. – Reza Akraminejad Oct 17 '17 at 11:48
  • @Hamed_gibago If you're asking if you define the classes in the interactive shell whether it will work or not, yes it will work. AFAIK IDLE python shell is just a more GUIish version of the command line shell and it works fine in the command line shell. Run my code, followed by "a = Child()" and "a.my_method()". – CrazyCasta Oct 18 '17 at 05:19
  • @CrazyCasta I didn't find AFAIK IDLE shell, but thank you for make me aware to search for other shell. ;) – Reza Akraminejad Oct 18 '17 at 06:41
  • @Hamed_gibago No, I'm saying As Far As I Know (AFAIK) IDLE Python shell... I don't have IDLE Python to test with, but I'd be willing to bet if it's not working it's either a version issue (2.7 vs 3.x) or some confusion. – CrazyCasta Oct 18 '17 at 22:07
  • @Hamed_gibago Yeah, np. Btw, I checked and it doesn't work in python 3, so if you're using python 3 that would be why (need to put parenthesis around the print arguments). – CrazyCasta Oct 22 '17 at 01:16
7

If you want two levels up, why not just do

class GrandParent(object):                                                       

    def act(self):                                                               
        print 'grandpa act'                                                      

class Parent(GrandParent):                                                       

    def act(self):                                                               
        print 'parent act'                                                       

class Child(Parent):                                                             

    def act(self):                                                               
        super(Child.__bases__[0], self).act()                                    
        print 'child act'                                                        


instance = Child()                                                               
instance.act()

# Prints out
# >>> grandpa act
# >>> child act      

You can add something defensive like checking if __bases__ is empty or looping over it if your middle classes have multiple inheritance. Nesting super doesn't work because the type of super isn't the parent type.

IamnotBatman
  • 342
  • 3
  • 7
  • 1
    To my opinion, this should be accepted as the best answer. Slight improvement suggestion: Instead of `super(Child.__bases__[0], self).act()` one could also use `super(type(self).__bases__[0], self).act()`, avoiding hard coding the class name of `Child`. – Sebastian Thomas Dec 29 '20 at 19:14
0

You can do this by following ways

class Grandparent(object):
    def my_method(self):
        print "Grandparent"

class Parent(Grandparent):
    def my_other_method(self):
        print "Parent"

class Child(Parent):
    def my_method(self):
        print "Inside Child"
        super(Child, self).my_method()

In this case Child will call base class my_method but base class my_method is not present there so it will call base class of parent class my_method in this way we can call my_method function of grandparent

Another Way

class Grandparent(object):
    def my_method(self):
        print "Grandparent"

class Parent(Grandparent):
    def my_other_method(self):
        print "Parent"

class Child(Parent):
    def my_method(self):
        print "Inside Child"
        super(Parent, self).my_method()

In this way we are directly calling function base class my_method function of the parent class

Another way but not pythonic way

class Grandparent(object):
    def my_method(self):
        print "Grandparent"

class Parent(Grandparent):
    def my_other_method(self):
        print "Parent"

class Child(Parent):
    def my_method(self):
        print "Inside Child"
        Grandparent.my_method()

In this way we are directly calling my_method function by specifying the class name.

Anand Tripathi
  • 14,556
  • 1
  • 47
  • 52
  • 10
    Never, *ever*, EVER use `self.__class__` in `super()`. Not even to get at the bases. `self.__class__` is **not always the class on which you defined the method**, it could be a subclass. If you add another two levels of inheritance, you now have an infinite loop. – Martijn Pieters May 31 '17 at 13:01
0

Made and tested in python 3

class Vehicle:

    # Initializer / Instance Attributes
    def __init__(self, name, price):
        self.name = name
        self.price = price

    # instance's methods
    def description(self):
        print("\nThe car {} has a price of {} eur".format(self.name, self.price))
#Object Vehicle

m3 = Vehicle("BMW M3", 40000)

m3.description()

class Camper(Vehicle):

     def __init__(self,nome,prezzo,mq):
         super().__init__(nome,prezzo)
         self.mq=mq

         # instance's methods

     def description(self):
         super().description()
         print("It has a dimension of",format(self.mq)+" mq")

#Camper Object(A camper is also a Vehicle)
marcopolo=Camper("Mercede MarcoPolo",80000,15)

marcopolo.description()

Output:
The car BMW M3 has a price of 40000 eur
The car Mercede MarcoPolo has a price of 80000 eur
It has a dimension of 15 mq

Albin Paul
  • 3,330
  • 2
  • 14
  • 30
LucianoDemuru
  • 131
  • 1
  • 4