Inheritance in Python

00:00 In the previous lesson, I give you an overview of the course. In this lesson, I will introduce you to inheritance in Python. Inheritance is a way of structuring code where classes form hierarchies.

00:13 A child class is one based on a parent and gains all the aspects of the parent with the ability to override some of those features. This mechanism is useful for writing objects that reflect hierarchical relationships in the data itself and reducing the amount of code you write, keeping common code in a parent class and having one or more child classes inherit that code.

00:37 Inheritance terminology has a fair number of synonyms. The class you inherit from is sometimes called a parent, like I did in the previous slide, a super class, or a base class, with an abstract base class being a special case of a class that doesn’t fully implement all its methods.

00:55 It’s a placeholder saying my children should have a method that does this. A class that inherits from a parent can be called a child, like I’ve been doing here, a derived class, a subclass (as opposed to a superclass).

01:11 And the process of creating a child is sometimes known as extending the parent class. Why is there so much terminology? Partially because there are a whole whack of programming languages that have object-oriented concepts built in, and each has their own take. The different terms from different languages and academic papers have blended together over the years.

01:32 This can also lead to pedantic arguments like whether or not .__init__() is a constructor. It isn’t, but you shouldn’t care.

01:42 When a child extends a parent class, it gets all of the parents’ methods. The child class can then do one of three things with the inherited method. First, it can do nothing, meaning when the method is called, the code in the parent gets run. Second, the child class can override the method, making a method of the same name.

02:01 When the child’s version of the method is called, only the child’s version gets run, completely overriding the parent’s functionality. Third is to extend a method. In this case, the child is also writing a method of the same name, but somewhere in the code, it’s invoking the parent’s code.

02:19 This can be useful if you want to add to the functionality but not replace it, allowing for code reuse. In Python, you can access the methods in a parent class using a built-in callable named super().

02:32 This callable returns an instance of the current object within the parent’s context. So, super().method() invokes the parent’s copy of the method, allowing you to write a child version of that method that extends the parent’s functionality. Let’s go look at some code that uses inheritance.

02:51 This is the AirCraft class. It starts out with the keyword declaring it as a class. The special method for initialization called .__init__() is called after the instance object is instantiated, giving you the opportunity to set initial values on the object.

03:10 The arguments passed to the constructor are also passed to .__init__(), so a common pattern is to store those arguments on the object itself.

03:19 Remember, all instance methods need the self argument, a reference to the object you’re interacting with. This code stores the make and model arguments on the object and also creates a non-public attribute called ._flying.

03:35 The .takeoff() instance method prints out a message and changes the value of the non-public attribute ._flying to be true, and below it, the .land() method does the opposite. Let me scroll down.

03:49 This is the Plane class. The first thing you’ll notice is the parentheses wrapping the AirCraft class. This is how you denote inheritance in Python.

03:59 Line 18 says that the Plane is a child of AirCraft. All the members of AirCraft also become members of Plane, but I’m not going to leave that alone. I’m going to mess with them.

04:11 Plane’s .__init__() takes three arguments, make, model, and num_engines. Recall, the AirCraft’s version just takes make and model.

04:21 I could just redo the two lines that stores make and model on the object, but instead I’m invoking the parent’s .__init__(). Line 20 does that, using super() to get at the object in the parent’s context, and then directly calling its copy of .__init__() passing in the make and model.

04:40 Even if you know the parent does nothing but store these two values, it’s good practice to use super(). That way, if additional code is added to the parent class, you get it automatically without having to worry about what the child’s doing.

04:53 And since the parent class, AirCraft, doesn’t have the num_engines property, the Plane class stores it using the terminology from the previous slide.

05:03 Plane’s .__init__() is extending AirCraft’s .__init__(), keeping the parent’s functionality but adding a bit of its own. Plane also extends the .takeoff() instance method.

05:14 By defining a method with the same name, Plane can modify the parent’s behavior. On line 24, I use super() to call AirCraft’s .takeoff() method, making sure not to lose its functionality, and then add some more code in the line after with some extra printing.

05:31 The .land() method is similar. Okay, let’s build some flying stuff. First off, I’ll create an AirCraft object, so I need to import the class.

05:46 and here’s a zeppelin, passing in the make and model.

05:51 I can access the .make attribute using dot notation

05:58 and call its .takeoff() method. Let’s get a Plane.

06:10 Significantly faster than the Hindenberg, the plane Tom Cruise made famous, an F-14 Tomcat.

06:19 The make is stored on Plane because I invoked AirCraft’s .__init__() in Plane’s, .__init__() using super(). And when I call the .takeoff() method, it also uses super(), calling AirCraft’s .takeoff(), which prints out the first message, and then the extended code calls the gear up through the use of super().

06:38 You can control what parts of the parent’s code gets run, and you can also control when. Most of the time when you’re extending a method, you’ll invoke the parent’s version first, but you don’t have to.

06:50 Sometimes you might want to change your object’s state before calling the parent. The use of super() merely accesses the parent context. You can call whatever methods on it in whatever order as you need.

07:03 Inherited classes can also be extended, so you can end up with a whole hierarchy. This is a class object diagram. Each box represents a class and has three sections: the title, the middle section defining attributes, and the bottom section defining methods.

07:21 The Animal class on the top defines an attribute called .name and has no methods. The Mammal, Bird, and Fish classes each inherit from Animal, gaining its .name attribute, and then they further add their own attribute named .feature.

07:38 In this case, each class adds the same attribute, but that isn’t necessary. At first glance of this diagram, you might rightfully think that feature could be moved up into the parent, but you’ll see why it isn’t when I show you the actual code that goes with this.

07:53 The bottom layer here defines classes that extend Mammal, Bird, and Fish. Each defines a method for itself. That "None" denotes the return value of the method. Notice how Eagle and Penguin define different methods.

08:08 That’s why you don’t just want .fly() on bird, as not all birds can fly. The Flying Penguin would be a good name for a pub.

08:18 Here’s some Python that corresponds with that diagram. Animal’s .__init__() takes the name argument, which it stores on the object.

08:27 The Mammal, Bird, and Fish classes inherit from Animal and then each declare a class attribute describing special features for that group of animals.

08:36 This is why it wasn’t included as part of Animal, because it’s a class attribute. Class attributes were covered in detail in part one of this course.

08:45 The short version is these are common across all the instance objects that are built from the class. At the third level, you see some classes that inherit from Mammal, Bird, and Fish, each defining its own methods.

08:59 Not only can you have multiple levels of inheritance, but a child can be based on more than one parent. That’s what’s next.

Become a Member to join the conversation.