2

I've read the python documentation, but I still have questions about inheritance.

  • It seems in older versions of python you could pass arguments to super, but no longer. What if SuperClass does some sort of setup using its arguments?
  • If inheriting from object, should I call super? As far as I can tell, it doesn't make a functional difference.
  • Is this handled differently in python 2.7 vs. 3.x?

Is this how inheritance is supposed to be handled?

class SuperClass(object):
    def __init__(self, super_argument):
        super(object, self).__init__()
        self.super_argument = super_argument
        self.foo()

class ChildClass(SuperClass):
    def __init__(self, super_argument):
        self.super_argument = super_argument
        super(SuperClass, self).__init__()  

If so, does that make this an unworkable design for a class which might be inherited?

class SuperClass(object):
    def __init__(self, super_argument):
        super(object, self).__init__()
        self.foo(super_argument) # Argument passed instead without saving in self
5
  • "pass arguments to super" - do you mean super(here).method() or super().method(here)? Commented Jul 30, 2015 at 15:07
  • super(SuperClass, self).__init__(super_argument) or super(SuperClass, self, super_argument).__init__() Commented Jul 30, 2015 at 15:12
  • That's slightly unhelpful, because what you've done there is include both sets of arguments, rather than specify which ones you're asking about! You can leave out SuperClass, self if you're writing only for 3.x, but super_argument is still used as before. Commented Jul 30, 2015 at 15:13
  • I'm sorry, I'm not exactly sure where the confusion is. When I instantiate SuperClass on its own, i can pass it arguments which go to init. It doesn't seem like I can do that when instantiating it as a super class. Commented Jul 30, 2015 at 15:15
  • Could you show the failing case, with the full traceback? I've had a stab at answering, but I suspect we're still talking at cross purposes, and a minimal reproducible example might really clear things up. Commented Jul 30, 2015 at 15:17

1 Answer 1

4

It seems in older versions of python you could pass arguments to super, but no longer. What if SuperClass does some sort of setup using its arguments?

I think you've misunderstood which set of arguments you can leave out in 3.x. In Python 2.x, you needed to pass arguments to super to get the correctly-bound method:

class MyClass(...):

    def __init__(self, ...):
        super(MyClass, self).__init__(...)
            # ^ these arguments       ^ not these

In 3.x, you aren't required to supply those arguments, you can just call super().method(...), but it will accept them just fine.

This is the same as the behaviour with inheriting object - you must do it to get a new-style class in 2.x, but 3.x will create a new-style class whether or not you explicitly inherit object.


Either way, you can pass arguments to the method on super. So if you're writing only for 3.x, you could do something like:

class MyClass(SuperClass):

    def __init__(self, super_arg, my_arg):
        super().__init__(super_arg)
            # ^ don't need these
                       # ^ still need these
        self.my_arg = my_arg

If inheriting from object, should I call super?

Yes, because you may be involved in multiple inheritance. Compare:

>>> class SuperClass1(object):
    def __init__(self):
        print("SuperClass1.__init__")


>>> class SuperClass2(object):
    def __init__(self):
        print("SuperClass2.__init__")


>>> class MyClass(SuperClass1, SuperClass2):
    def __init__(self):
        print("MyClass.__init__")
        super(MyClass, self).__init__()


>>> MyClass()
MyClass.__init__
SuperClass1.__init__
<__main__.MyClass object at 0x02D0CC50>

with:

>>> class SuperClass1(object):
    def __init__(self):
        print("SuperClass1.__init__")
        super(SuperClass1, self).__init__()


>>> class SuperClass2(object):
    def __init__(self):
        print("SuperClass2.__init__")
        super(SuperClass2, self).__init__()


>>> class MyClass(SuperClass1, SuperClass2):
    def __init__(self):
        print("MyClass.__init__")
        super(MyClass, self).__init__()


>>> MyClass()
MyClass.__init__
SuperClass1.__init__
SuperClass2.__init__
<__main__.MyClass object at 0x02BCDC10>

In the former, because SuperClass1 doesn't call super, SuperClass2.__init__ never gets reached.


Is this handled differently in python 2.7 vs. 3.x?

Hopefully this is now clear - you need to be more explicit in 2.x (or if you're writing code that should work in both versions) but otherwise the functionality is identical, and you should call super at all levels in both.

Sign up to request clarification or add additional context in comments.

4 Comments

What does the first SuperClass2 do? Doesn't the second overwrite the first?
In your second example (the one after 'with:'), it seems like you define SuperClass2 twice. Was that a typo?
Okay, then thank you. I now understand perfectly. I was mostly confused about the differences between the old and new style of classes. Slightly off topic, but to make sure I'm understanding correctly, during multiple class inheritance, the class to the left instantiates the one to the right? Does that mean the ones further down the arguments list will overwrite methods of earlier ones if they have the same name?
@JamesFargotson no, the left-most inherited class is the first in the method resolution order (see the __mro__ attribute, and note that SuperClass1.__init__ is called before SuperClass2.__init__), so the opposite happens - its method implementations shadow any implementations on classes to the right of it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.