Let’s go look at some code. Okay, more classes about vehicles and including flying vehicles. You just sort of run out of examples after a while. At the top here, I have a parent class having
.model attributes and
.stop() methods. Let me scroll down a bit.
The syntax for inheriting from multiple classes is to comma-separate the list of classes in the declaration. The
FlyingCar is both a
Car and an
AirCraft, which of course also makes it a
Vehicle through its grandparents.
Multiple inheritance introduces a problem though you can get conflicts. Consider this diagram representing the classes you just saw. What happens if I extend the
.start() method in
Car, changing its behavior?
Now I have what is called the diamond problem, named after the shape of the class diagram. Which
FlyingCar get? The one from
Car or the one from
AirCraft inherited from the grandparent,
02:39 Different languages deal with this problem differently. Let’s talk about how Python does it. Python’s answer is called the method resolution order, or MRO to its friends. When you look for a member on a class or object, Python looks for it in the following order. First, it looks at the current class, then at the leftmost superclass.
That’s the first one listed in the inheritance declaration. That was
Car in my example. After that, it moves in order along the inheritance declaration. So after
Car, it would check in
AirCraft. If it still hasn’t found what you asked for, it then moves up to the grandparents, following the same inheritance declaration order until finally it gets to the ancestor of all objects. In Python, the
object class. That name’s not confusing.
03:40 All classes in Python inherit from it automatically. So, the short version of the MRO: the order of the class declaration statement is the order Python looks for things. Let’s go resolve some method orders.
Pardon the generic class names here, but sometimes an abstract concept makes it clearer. This file has four classes:
A is the grandparent,
B inherits from
C inherits from
D inherits from
C all have a method creatively named
D doesn’t override anything.
A mixin is a special name for a class that doesn’t have any attributes. You inherit from a mixin in order to add its methods to your class. This often serves the same purpose as that oh-so-common
util.py file everybody has where you put miscellaneous functions.
05:45 Mixins are never instantiated directly, and you’ll see them a lot in frameworks. For example, in Django, you might use one that adds database query features, and you’d mix it in with your database models.
06:33 The next couple sentences are a bit of a deep dive behind the scenes, and you really don’t have to worry about it when you’re writing classes, but methods are functions bound to a class using a reference.
When you invoke a method on an instance, it’s invoking the corresponding bound function on the class, passing in the instance. Because it’s an object, you can actually modify the reference on the class and point it to a different function. You really shouldn’t unless you’re trying to do something fancy, but that’s actually how it works. Why do I bring all this up? Well, if you look at the writable things on a class, that includes the methods as well as any class attributes. For the purpose of the mixin I’m about to show you, the important thing you have to remember is that
.__dict__ contains the attributes of an object. There’s an exception to all this, but I’ll leave that to a later lesson.
This file contains a mixin that does JSON serialization. The
JSONMixin is a class like any other. It has methods and no attributes. The
.to_json() method uses the
dumps() function to turn a dictionary into a string containing JSON.
This is a bit more complex than at the instance level. It contains two special attributes showing the module and docstring, and the
.__init__() method as a function reference. Like I said, more an implementation detail.
Become a Member to join the conversation.