Inheritance Best Practices
00:00 You’ve now learned how to write what is fundamentally the same software project using both inheritance and composition. The rest of this course will be about learning when to use each one, and more importantly, when not to use them.
00:18 We’ll start with inheritance. First off, it’s a good idea to try to follow the Liskov substitution principle when you can. If you remember, this states that if some interface requires a specific type of object, you can substitute in a class that is a child of that type so long as it properly inherits the interface it needs.
We use this in our employee management program—both the productivity and payroll systems required a list of employees to operate on—but instead of just giving them
Employee objects we gave them subclasses of
Additionally, the Python language requires that we make exception types inherit from
BaseException, but we inherited from
Exception, which is okay because
Exception itself inherits from
01:24 When you have two classes and you’re trying to determine whether or not you should inherit one from the other, think about the is a relationship that inheritance models. In general, you want to use inheritance only if the relationship works in one direction—that is, A is a B but B is not an A.
It sounds like this relationship works either way, so we probably shouldn’t use inheritance. To show you what would happen if we do, I’m going to create a
Rectangle class and then a
Square class that inherits from
Rectangle. I’ll make the
Rectangle have instance attributes for the length and the height.
It almost looks like it’s an attribute. That’s because we marked that method as a property. We can use a property for this method because we aren’t passing any data to the
.area() method. We’re just calling it, so it calculates the area based on the instance attributes already set in the object. Next, I’ll create a square of length
It looks like everything is okay so far. Right now,
Square just acts as a specialized
Rectangle. But now what happens if we have to add support for resizing the rectangle after it’s been created? That doesn’t sound too hard.
And now we see that it’s working, unfortunately. We’ve just created a
Square object and transformed it into what’s really a rectangle, but it’s still of type
Square; now it’s just an invalid square. There are ways that we can fix this, but it’s going to be awkward any way we do it.
We could override the
.resize() method in the
Square class, ignoring the
height parameter, but then we’d have a bunch of
Rectangle objects where only some of them are resized with two parameters—the rectangle—and others—the squares—are resized with one. The
Square and the
Rectangle require different interfaces because their
.resize() methods require a different number of arguments.
Become a Member to join the conversation.