00:13 Python is one of the few popular languages that supports this idea of multiple inheritance. Multiple inheritance allows one class to derive from, or inherit from, multiple other classes instead of just one.
But where would this be useful? Well, take this scenario. We want to add a new class to our employee tracking system that represents a temporary secretary. If you remember, the
Secretary class is a
We could achieve this with single inheritance—for example, by inheriting from
Secretary—so it’s tracked using the inherited
.work() method—and then creating our own
.calculate_payroll() method to calculate payroll as an hourly employee.
Let’s run this, and I will finish off this quick video. Ha. Yeah, quick videos aren’t really a thing in this course. We got an exception that says
.__init__() takes four arguments, but we gave it five.
This error can be a bit confusing because it includes the
self argument, which we don’t actually pass into the
.__init__() method ourselves, so just subtract one from each.
.__init__() takes three arguments, but we gave it four. That makes sense!
We supplied four arguments when creating our new object, but what
.__init__() method is it even checking against? In theory, we just inherited two, right? Well, if we move back into
employees.py, notice that I inherited from
Secretary and then
It looks like it’s trying to use the
.__init__() method, which takes only a
weekly_salary, instead of the two arguments required by the
HourlyEmployee. Let’s switch these and see what happens.
03:51 This seems kind of unpredictable, but luckily for us, there’s a way to see what it’s doing. It’s called the MRO, or method resolution order. Formally speaking, the MRO is a set of rules that defines the search path that Python will use when searching for the right method to use in cases of inheritance.
04:15 This search path is like an ordered list of classes, and every class has its own MRO. In this video, you’ll see how it’s used to demystify multiple inheritance, but it’s actually used in single inheritance too—although, then, it’s kind of trivial.
And when I press Enter, you see we get a listing of classes. This is the method resolution order for the
TemporarySecretary class. When we call any method on
.__init__(), this is the order in which it will be searched for.
TemporarySecretary defines no
.__init__() method itself, so it needs to use one that it inherits. The MRO says that searching order should always be left-to-right, children before parents, and so when it can’t find an
.__init__() method inside of
TemporarySecretary, Python searches
If we look at the definition for
HourlyEmployee, it looks like it has a matching signature for the
.__init__() method, but that method calls
super(), which tells the MRO to keep searching the list starting with the next class.
In this case, the next class it looks in is
Secretary, but if we look at that class, it looks like
Secretary doesn’t define an
.__init__() method, so it searches its parent,
SalaryEmployee. Here, the method signature for the
.__init__() method doesn’t match what we’ve passed in.
Now, I’m going to create an
.__init__() method that accepts all of the arguments it needs to be instantiated as an
HourlyEmployee. In essence, by overriding the
.__init__() method of the parents and not using the
super() function inside it, we are bypassing the MRO. Instead of
super(), I’ll call the parent class I want directly, which looks like this:
Our object will be instantiated fine, but when the
PayrollSystem tries to call
.calculate_payroll() on a
TemporarySecretary object, we’re going to get an exception telling us that we haven’t supplied a
That is because
TemporarySecretary doesn’t define a
.calculate_payroll() method, so naturally, Python searches its parents according to the MRO. The next class is
SalaryEmployee, which defines a
.calculate_payroll() method, but it requires a
.weekly_salary attribute and we don’t have that with this
TemporarySecretary since we only initialized it with
Luckily, this is a quick fix. All I’m going to do is define a
.calculate_payroll() method in the
TemporarySecretary class. And when that is called, I’ll tell it to return the
When this happens, the method resolution order is used to determine what order to search parent classes in. But, as you saw, this can get pretty messy and the only way we could fix it was with a sort of band-aid patch on our
TemporarySecretary class—and even then, we had to be careful. When you see a diamond, it’s typically time to rethink the design of your software.
10:38 The first one is “How does Python determine the method resolution order?” and the second is “How do we redesign our project to utilize multiple inheritance, but without the diamond problem?” The next video regarding the MRO is optional.
10:56 It’s not very important that you understand the algorithm behind it but I think it’s pretty cool, so I included it as sort of a bonus. If you’re not interested in that, you can skip to the following video in the course, where I show you how to redesign this project.
Become a Member to join the conversation.