Reputation: 18625
There are two main ways for a derived class to call a base class's methods.
Base.method(self):
class Derived(Base):
def method(self):
Base.method(self)
...
or super().method():
class Derived(Base):
def method(self):
super().method()
...
Suppose I now do this:
obj = Derived()
obj.method()
As far as I know, both Base.method(self)
and super().method()
do the same thing. Both will call Base.method
with a reference to obj
. In particular, super()
doesn't do the legwork to instantiate an object of type Base
. Instead, it creates a new object of type super
and grafts the instance attributes from obj
onto it, then it dynamically looks up the right attribute from Base
when you try to get it from the super object.
The super()
method has the advantage of minimizing the work you need to do when you change the base for a derived class. On the other hand, Base.method
uses less magic and may be simpler and clearer when a class inherits from multiple base classes.
Most of the discussions I've seen recommend calling super()
, but is this an established standard among Python coders? Or are both of these methods widely used in practice? For example, answers to this stackoverflow question go both ways, but generally use the super()
method. On the other hand, the Python textbook I am teaching from this semester only shows the Base.method
approach.
Upvotes: 2
Views: 3006
Reputation: 36299
Using super()
implies the idea that whatever follows should be delegated to the base class, no matter what it is. It's about the semantics of the statement. Referring explicitly to Base
on the other hand conveys the idea that Base
was chosen explicitly for some reason (perhaps unknown to the reader), which might have its applications too.
Apart from that however there is a very practical reason for using super()
, namely cooperative multiple inheritance. Suppose you've designed the following class hierarchy:
class Base:
def test(self):
print('Base.test')
class Foo(Base):
def test(self):
print('Foo.test')
Base.test(self)
class Bar(Base):
def test(self):
print('Bar.test')
Base.test(self)
Now you can use both Foo
and Bar
and everything works as expected. However these two classes won't work together in a multiple inheritance schema:
class Test(Foo, Bar):
pass
Test().test()
# Output:
# Foo.test
# Base.test
That last call to test
skips over Bar
's implementation since Foo
didn't specify that it wants to delegate to the next class in method resolution order but instead explicitly specified Base
. Using super()
resolves this issue:
class Base:
def test(self):
print('Base.test')
class Foo(Base):
def test(self):
print('Foo.test')
super().test()
class Bar(Base):
def test(self):
print('Bar.test')
super().test()
class Test(Foo, Bar):
pass
Test().test()
# Output:
# Foo.test
# Bar.test
# Base.test
Upvotes: 3