Classes

INPUT · Slides

Override it, and call the parent too

01 / 07

When what you inherited does not fit

The greet you wrote on the parent says hello. But you want a premium member to say "thank you as always".

Add a separate method with another name, something like premium_greet, and the side doing the calling has to change which name it calls depending on who it is holding. That is what you want to avoid.

02 / 07

Rewrite it under the same name

Write a method on the child with the same name as one on the parent and that is the one used for that child. This is overriding.

The caller still writes greet(), exactly as before. Only the behaviour is swapped out.

class Member:    def __init__(self, name):        self.name = name    def greet(self):        print(f"Hello, {self.name}")class PremiumMember(Member):    def greet(self):        print(f"Thank you as always, {self.name}")p = PremiumMember("Yui")p.greet()

Result

Thank you as always, Yui

03 / 07

The parent is untouched

The override applies only when you call through that child. The method on the parent is still there, intact, and other children are unaffected.

When a method is called, Python looks in the child first and goes up to the parent only if it is not there. If the child has the same name, it is found before the search gets that far — and that is all there is to it.

class Member:    def __init__(self, name):        self.name = name    def greet(self):        print(f"Hello, {self.name}")class PremiumMember(Member):    def greet(self):        print(f"Thank you as always, {self.name}")m = Member("Haruto")p = PremiumMember("Yui")m.greet()p.greet()

Result

Hello, Haruto
Thank you as always, Yui

04 / 07

Call the original with super()

Sometimes you want to override and still use the parent's original work. That is what super() is for.

super().greet() means "run the greet on the parent". Do the parent's part, then add your own on top.

class Member:    def __init__(self, name):        self.name = name    def greet(self):        print(f"Hello, {self.name}")class PremiumMember(Member):    def greet(self):        super().greet()        print("Thank you as always")p = PremiumMember("Yui")p.greet()

Result

Hello, Yui
Thank you as always

05 / 07

Give the child something extra to hold

You want a rank on premium members and nowhere else — which means overriding __init__ in the child.

When you do, call super().__init__(name) first. Leave the parent's job to the parent, and write only what the child adds. This is the most common shape in all of inheritance.

class Member:    def __init__(self, name):        self.name = nameclass PremiumMember(Member):    def __init__(self, name, rank):        super().__init__(name)        self.rank = rankp = PremiumMember("Yui", "gold")print(p.name)print(p.rank)

Result

Yui
gold

06 / 07

Forgetting to call super()

Write an __init__ on the child and the parent's __init__ stops running by itself. Of course it does — you overrode it.

Leave super().__init__(name) out and nobody puts name in. Worse, the error arrives not when the real one is made but when you try to use it. It is an easy one to miss.

class Member:    def __init__(self, name):        self.name = nameclass PremiumMember(Member):    def __init__(self, name, rank):        self.rank = rankp = PremiumMember("Yui", "gold")print(p.name)

Result

AttributeError: 'PremiumMember' object has no attribute 'name'

07 / 07

Knowing which way to write it

When you override, decide about super() like this.

  • The parent's work is not wanted at all → leave super() out
  • You want to add to the parent's work → call super(), then write the difference

__init__ is nearly always the "add to" case, so super().__init__(...) is the standard thing to write.

That is the whole toolkit for classes. Next comes the chapter review.