Mikhail Gerasimov
Mikhail Gerasimov

Reputation: 39576

Should I use super() every time I call parent function or only inside overridden functions?

If we override parent class's method, we can use super() to avoid mention of parent class's name - that's clear.

But what about case, when we just use in subclass some function defined in parent class? What is preferable way: to use super().parent_method() or self.parent_method()? Or there's no difference?

class A:
    def test1(self):
        pass

    def test_a(self):
        pass

class B(A):
    def test1(self):
        super().test1()  # That's clear.

    def test_b(self):
        # Which option is better, when I want to use parent's func here?
        # 1) super().test_a()
        # 2) self.test_a()
        pass

Upvotes: 1

Views: 713

Answers (4)

Blckknght
Blckknght

Reputation: 104752

Usually you will want to use self.test_a() to call an inherited method. However, in some rare situations you might want to use super().test_a() even though it seems to do the same thing. They're not equivalent, even though they have the same behavior in your example.

To explore the differences, lets make two versions of your B class, one with each kind of call, then make two C classes that further extend the B classes and override test_a:

class A(object):
    def test_a(self):
        return "A"

class B1(A):
    def test_b(self):
        return self.test_a() + "B"

class B2(A):
    def test_b(self):
        return super().test_a() + "B"

class C1(B1):
    def test_a(self):
        return "C"

class C2(B2):
    def test_a(self):
        return "C"

When you call the test_b() method on C1 and C2 instances you'll get different results, even though B1 and B2 behave the same:

>>> B1().test_b()
'AB'
>>> B2().test_b()
'AB'
>>> C1().test_b()
'CB'
>>> C2().test_b()
'AB'

This is because the super() call in B2.test_b tells Python that you want to skip the version of test_a in any more derived class and always call an implementation from a parent class. (Actually, I suppose it could be a sibling class in a multiple inheritance situation, but that's getting even more obscure.)

Like I said at the top, you usually want to allow a more-derived class like the Cs to override the behavior of the inherited methods you're calling in your less-derived class. That means that most of the time using self.whatever is the way to go. You only need to use super when you're doing something fancy.

Upvotes: 3

daveoncode
daveoncode

Reputation: 19618

If we override parent class's method, we can use super() to avoid mention of parent class's name - that's clear.

actually super() is not syntactic sugar, its purpose is to invoke parent implementation of a certain method. You have to use super() when you want to override a parent method, you don't have to use super() when instead you want to overwrite a method. The difference is that in the first case you want to add extra behavior (aka code execution) before or after the original implementation, in the second you want a completely different implementation. You can't use self.method_name() in an override, the result will be a recursion error! (RuntimeError: maximum recursion depth exceeded)

Example:

class A:
    def m(self):
        print('A.m implementation')

class B(A):
     def m(self):
        super().m()
        print('B.m implementation')

class C(A):
     def m(self):
        print('C.m implementation')

class D(A):
    def m(self):
        self.m()


a = A()
a.m()

b = B()
b.m()

c = C()
c.m()

d = D()
d.m()

Given a base class A, with a method m, B extends A by overriding m, C extends A by overwriting m, and D generates an error!

EDIT:

I just realized that you actually have 2 different methods (test_a and test_b). My answer is still valid, but regarding your specific scenario:

you should use self.test_a() unless you override/overwrite that method in your class B and you want to execute the original implementation... so we can say that calling super().test_a() or self.test_a() it's the same given that you'll never override/overwrite the original test_a() in your subclasses... however is a nonsense to use super() if not for an override/overwrite

Upvotes: 1

Obscure Geek
Obscure Geek

Reputation: 749

Firstly both the ways super().test_a() and self.test_a() will result in execution of method test_a().

Since Class B does not override or overwrite test_a() I think use of self.test_a() will be much efficient as self is a mere reference to the current object which is there in memory.

As per documentation, super() results in creation of proxy object which contains other methods also. Owing to this reason I feel self will be the correct approach in your case.

Upvotes: 1

user5092827
user5092827

Reputation:

Since B is an A, it has a member test_a. So you call it as

self.test_a()

B does not overwrite A.test_a so there is no need to use super() to call it.

Since B overwrites A.test1, you must explicitly name the method you want to call.

self.test1()

will call B.test1, while

super().test1()

will call A.test1.

Upvotes: 1

Related Questions