 Welcome back. A couple of minutes late, so real quick, Andy is a senior engineer here at Bloomberg and a member of our Python Guild who's responsible for spreading good practices across the firm. Also one of the engineers in our data license group. Over to you, Andy. OK, hello, and welcome to making multiple inheritance not work in Python. To be clear, if you think I'm going to tell you how to make multiple inheritance work in Python, that's another talk. This talk is intended to illustrate a couple techniques that might be helpful for various purposes, but not any particular examples that you should actually put to use. The techniques are what's being shown, not the examples. So before we can talk about multiple inheritance, we should probably cover inheritance. Inheritance is a mechanism of basing an object or class upon another object. That would be prototype or class-based inheritance, retaining a similar implementation. It comes from an initial implementation in Simula all the way back from 1965, and it's kind of been used ever since. When we talk about multiple inheritance and we try to say what the problem with it is, we quickly wind up with the diamond problem, which can be easily explained thusly or explained thusly, if not easily. You start with a base class. You create two inherited classes. From there, you create a new class that inherits from both, and then you try to reason about this. We had multiple inheritance in Python. In Python 2, we had the old style classes, and multiple inheritance worked like this. Class A, B, C, and D, just like the diamond. Define just like the diamond. Everyone has a constructor. Every constructor calls its base class constructors. And if you look at how this plays out, when we construct an instance of D, D calls B and C's constructors. B and C's constructors both calls A's constructors. But the problem is, B's constructor calls A's constructor, then C's constructor calls A's constructor, and you have to hope that that didn't mess up something that B's constructor did. And if you were in Python 2 old style classes, you just had to deal with that. Fortunately, that was a long time ago. When you get to Python 2.2, you got the new style classes, which in Python 3, we call classes. And that introduced something called the method resolution order. So if you write the same code in Python 3, you can go to D and you can look at DunderMRO. And DunderMRO will say that there's an order. And the order is D, B, C, A. And that's defined by something called the C3 linearization algorithm. Doesn't matter much what that algorithm is. It created an order for us, and the order makes some sense. It's more important that there is an order than the sensibilities of that order, because if we introduce super, then when we say D, just call whatever your super class constructor is, and C, and B, and A, and so on, then D calls its super class constructor, which turns out to be B, OK. C, B calls its super class constructor, which somewhat unintuitively, the first time you see this, turns out to be C, which, OK, fine. C calls its super class constructor, which turns out to be A, which is actually exactly what it expected. Everything gets called once, everything gets called, and it's actually a thing that can be managed, and can be managed successfully. If you want to figure out how to manage it successfully, go view one of the courses or classes on making multiple inheritance work. We're obviously going to be playing some games with this, so let's talk about where we're going to be playing those games. The first thing we're going to be playing with are class decorators. Class decorators were introduced in Python 2.6. Just like any other decorator, they take a callable, they return a callable. Who knows what they did to that callable along the way? Maybe something, maybe nothing. But it gets bound to the same name, and that's great. So here, like most class decorators, is a simple descriptive decorator. It takes the class, it prints the class, it returns the class. It didn't really do anything to it. We just see that when we declare this class with my decorator, it prints the class. We could do a little bit more. Here's a graffiti decorator. When we get a class through the graffiti decorator, it tags the class. It applies a tag that says Killvary was here. We may find something to do with that. The metaclass is a favorite for this sort of thing, but to define it loosely, this actually existed well before Python 2.2, but it was something that only existed in the C code, and it still exists there in some other forms. But in Python 2.2, and ever since, it was exposed in the Python level, and it is the class of a class. So we can see this very simply. We create a class, and we say, what's dunder class? OK, it's type. Fine. Well, we inherit from type. We define that. We create a class, but we say the metaclass is my meta, and we ask, what's the class of this? OK, that's my meta. Well, OK, fine. Let's do something. Normally, if we create a class and we say, what's the truthiness of this? It's true. There's some rules about that. We'll break them. Let's create a metaclass that defines a dunder-bool method. Now, of course, the dunder-bool method applies to instances of that class, and it says, what's the truthiness of instances of this class? OK, so we'll set the metaclass of our negativity class to be false meta, and now we ask, what the truthiness of the class object is. OK, now we have a class where the class object itself is false. OK, there's some other things on here. I just told you what the method resolution order is doing. The metaclass lets us define what it is. Surely not relevant. So yeah, right there, def-mro lets you set what the method resolution order will be. There's another one I actually do not show you, but I will point out to you. Dunder-nu lets you totally define what the class is going to be as it passes through the metaclass. So if I haven't done enough here, go ahead and look that one up after the talk. Python 2.7 gave us operator overloading for, or effectively operator overloading for, is instance and is subclass via new magic methods on the metaclass. These are called subclass check and instance check. This was done to support abstract base classes. If you start thinking about how something like the mapping abstract base class or the sequence abstract base class has to work, it has to do some checking to figure out whether that is or is not a mapping. These return true or false, or they probably should go ahead and call super to figure out whether you have a subclass or an instance. So just to show you how those work, here's a check-checked meta that's just a probe. We'll figure out when you're calling. And check-checker has this metaclass. And then is none an instance of check-checker? Well, false, of course it's not, but we'll just print out the fact that you asked. Is object a subclass of check-checker? No, but thanks for asking. The last one we're going to use is a Python 3.6 feature. In its subclass, added the ability of a class to control the initialization of subclasses. It's basically a built-in class decorator. It's basically a built-in class decorator. The signature is like this. And usage of this is something like this. Let's say I want to say all subclasses of my class have one extra attribute, class field count, that says how many attributes there are in the class stick. OK, fine. It's a bit weird, but I can count them up after you initialize the class and add that. So here, sized container has this in its subclass magic method. And jar is a sized container. It has pickles. It has some number of pickles. And it has some amount of juice in it. And it has a field count of four. That's the name, the module, the pickles, and the juice. OK, let the games begin. So abstract-based classes are great. Abstract-based classes are wonderful. But they do allow you to have a mix of abstract and concrete methods. And for some reason, let's say we didn't want that. Let's say for some reason we did not want any concrete method on our interfaces. So here, where we're defining this sloppy interface that has a mix, we do not want it to be making sandwiches. When someone calls make sandwich afterwards, we would like it not to be there at all. So how can we do this? Well, we could put a class decorator there that simply removes it like that. We simply look at the field. We look at the descriptor. If the descriptor is not an abstract method, and the field is not one of these fields that we probably should leave alone. Dict module, let's leave the documentation. If anyone was kind enough to write it, we'll leave it there. Weak reference, abstract methods. You probably should expand this list if you write this into production. Or more accurately, don't write this into production. We'll delete that. And that will be your class. Now, there is a problem with this, probably a few more. But the problem is we're assuming that the developer that forgot they weren't supposed to put concrete methods here will remember to put the class decorator there. So let's not count on that. Let's use an it subclass. Because then if they inherit from the right thing, which we can probably check automatically, they will automatically have their transgressions removed for them. So this is the same code. It's just put into Dunder in its subclass. And then we can inherit from that. And that will remove it. This creates its own problem, because now it's there. And trying to actually implement it will have every time you try to implement it, every implementation removed. So at some point, you will need to actually create a real sandwich, which we'll need to remove in its subclass, so that you can actually define a brief brisket sandwich. So you probably should do something a little bit different. Real talk here. Abstract-based classes are fine. This is an inferior replacement. But doing something to enforce some degree of convention standard or implementation through an it subclass is something you may wish to do, because this is controlling the construction further down. OK. Moving on, let's assume we'll someday write code based on types, but none of that is ready yet. So here we have stock and preferred stock. They're basically stubs. IBM Common and IBM Preferred, IBM C&P, are also just stubs. You can see the type flags line these up. But if we do, is IBM C a subtype of preferred stock? Of course, it's not. IBM Common Stock is not preferred stock. But is IBM C a subtype of common stock? Yeah, sure. But if we look at the bases, there's nothing backing this up. Is IBM C an instance of stock? Yeah? Yeah? OK, so I might have slipped something in behind here. And what I've slipped behind here is a meta class. It's the fake interface meta. You can see it there. And it's defining instance check and subclass check. And what these two are doing, instance check is just saying, well, it's an instance if the subclass passes. And subclass check is saying, well, if there's no type flag, do things normally. However, if there's a type flag, completely ignore any question of how you would normally check instance check. How you would normally check instances. Just look at the type flag. Real talk. This alone is not enough to justify using his instance's subclass. Generally, you would avoid doing that in preference to some degree of duct typing. But if you are already using it for other reasons, you can use this to enable special rules. You could use this if previously you had a class hierarchy. And now things are coming serialized out. And they turned into just plain ordinary dictionaries or plain old objects, or they're coming out of a database now. And you just need to check them and move along, or if they will be. OK. Let's take another example. I have some methods I don't want to inherit. So we have cars, and we have taxis. A car is an automobile. A car has a name. It's automobile. It has a method to start. Taxi is a kind of car. Fine. They start the same. Taxi, if I ask what its name is, it's a taxi. Car, if I ask what its name is, it's an automobile. Some of you may pick up something a little bit odd there, because taxi should be saying it's an automobile. But if we look at the method resolution order, we'll see that I've slipped something in. There is one additional class that's been inserted into the method resolution order, utility class. So when I look at the method resolution order of taxi, before it gets to car, where it would pick up the name of automobile, it's going to utility class and picking up something else. Of course, car has a base class of vehicle, and that has a meta class on it. And what's happening in that meta class? Oh, what's happening in that class? Well, I've attached the meta class. That method class is playing with the method resolution order. What it is doing is it's calculating the method resolution order normally using type, which is that base meta class. And it's saying, if utility class is in the method resolution order, remove it and then reinsert it in the second position, exactly where we found it. The utility class is simply a class that has a property called name and says, use the class name, which gives us exactly the result we saw. Real talk. In my opinion, this might actually be the safest thing to use in this talk. Not so much that you would want to use it in code that you're developing around. This would be used more around a configuration file, something where you're creating a domain-specific language, or a very limited subset, perhaps used by analysts, or a special purpose section of your code that is known to obey special rules like this. But within that context, inserting something like this to control what can and cannot happen is fairly reasonable. So you know what? I'm tired of the diamond. Let's give it to this diamond. Here's the diamond from the beginning. Let's put an N to it. Here's what I want. You write A, B, C, D. You write the darn diamond. I'm taking C out. You can write it, but I'm not doing it. I'm just taking C out. And here's how I'm going to do it. I have simple object in there on A. Obviously, I'm going to throw a meta class in this. And what I'm going to do is I'm going to completely rewrite the method resolution order. The method resolution order I'm using is not C3. I am going to take the class. I'm going to traverse the bases. I'm going to take each thing in bases. I'm going to take the first base. I'm going to add that to the method resolution order. I'm going to return that. And that is going to be it. Whatever you put that was not the first base will be removed. I could probably write this real talk as don't do this. But the point is not that you would actually do this. The point is that you can pick and choose some features, not that you would pick and choose this feature. If you did something very close to this, you should probably raise an error for your users, especially in a development environment. In production, you might want to do something that avoids errors if you could do something exactly specific and clear and that were exactly safe to do. Which it's probably not. But you would know your system. But the overall point is that you can pick features. If you did something ever close to this, you probably should remove the base classes so that it doesn't test as it is an instance of this when it clearly no longer is by most conventions. So we've seen four hooks that let us twist inheritance into a relative pickle. Class decorator in its subclass, subclass check and instance check, and the meta class MRO method. Well, it's rare that we actually want to tweak these. The results when we do are quite frankly rather dramatic. Usually we go to, it's more important to know these exist for when we bump into something that has tweaked these or for when we want to temporarily tweak these to find out what's happening. Insert a probe on one of these. See what has happened. Real cases for tweaking these tend to be centered around domain specific languages or creating a highly specific section or a highly specific framework. They're what I call shovels. They are good for getting yourself out of a hole but should not be used early for fear of digging yourself into a hole and leaving you at the bottom of a hole with a broken shovel. And with that, if there's any time left, I will take some questions. There's a career page up there for anyone that needs it. Thank you very much, Andy. We have time for one question if it's quick. OK, I'm going to play like John Humphries. You have 30 seconds. Let me check that I've understood this. So I can subclass tuple and by playing with the MRO, I can hide all the elements from item access. You could hide. By playing with the MRO, you could hide. I subclass tuple and tuple has got item access methods. Yep. Can I subclass tuple and prevent ordinary item access? Of course. I mean, you could just implement a new item access method that doesn't do it. Yeah, yeah. OK, so what difference would you like to do? To make it not even show up in the IDE, that depends how the IDE is searching for it. You could remove it from probably, it depends how the IDE is searching for it. Because at some point, you could subclass tuple and make it not be a tuple. And then the IDE wouldn't find it, but it also wouldn't be a tuple. So let's bring that to a close. I think the answer is probably yes and no, and it's a crazy thing to do. Thank you very much, Andy.