Understanding Python: Abstract Base Classes

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] welcome back to understanding python my name is Jake and today we'll be diving into abstract base classes or ABCs in this video we'll explain what ABCs are how they work and how they can be used to enforce a class hierarchy if you're familiar with my previous videos on class inheritance then you'll be able to follow right along as we go if you learned something new let me know by liking the video now let's get started one of the simplest and most common ways you'll see abstract-based classes be used is the combination of the ABC class and Abstract method that python provides in its ABC module so to use those we'll say from ABC import ABC add abstract method Now to create a new abstract Base Class we simply just need to create a class we'll call it shape and it inherits from ABC from there all we need to do is Define some abstract methods so we'll decorate new methods with abstract method and we'll Define because this is a shape just two methods in here area and we're just going to say pass for now and then we'll also do one for we'll go with perimeter this can also be a pass and that's it we've literally just defined an abstract base class now the reason why we can just have pass for area and perimeter is because these don't actually do anything in this class definition while we're telling python is that in order for a subclass of shape to be valid it has to overwrite area and perimeter so if we were to implement a child class that doesn't override area or perimeter it can't actually be created python raise an error to demonstrate this let's create two new classes both of them will inherit from shape the first shape will be a circle circle is going to be a subclass of shape and we're just going to Define a simple Dunder knit so we can actually store some information about Circle luckily for area and perimeter of circles you only really need a radius so we'll just store that from there to be a valid child of shape we need to Define area and perimeter per Circle let's define area now we don't need any additional arguments and we'll simply just return the an approximation of Pi 3.14 times self dot radius squared and then for perimeter we'll return to times again approximation of Pi we could always just simplify this right now definition time but I think it reads better just how it is right now and then that's going to be times radius okay so at this point we have a valid Circle and to verify this let's load the file up in IPython and here we'll create a instance of circle just give it a radius of 5 and it creates a circle just fine if you do C1 dot area we get our area and then we can also do the same thing for perimeter and we get our perimeter with quite a bit of decimal Precision all right so what does it look like if we don't create a valid subclass well let's create triangle class this again is going to inherit from shape it will also have an init function though this time is going to need a few more things so for triangles you need a base height and we'll just accept the sides as a list and store those okay cool so let's skip defining area and just go straight to defining perimeter because perimeter is a bit easier to do because all we need to do is return the sum of all sides right so we'll save that load it up and we'll try to create an instance of triangle uh we'll give it a base of say five height of 13 and we'll give us some sides here of three four five oh look at that we got an error here it says type error can't instantiate abstract class triangle with abstract method area so because we didn't Define or override area which is defined up in our parent class shape when you try to create an instance of a class it gives you an error and that's one of the big values of abstract classes especially if you are a library author is you can Define the minimum amount of functionality that needs to be defined on child classes for them to be considered valid child classes so if we want triangle to work we'll need to Define area and for triangles that's one half or 0.5 and self.base times self dot height if we save this and we reload E1 is equal to the same triangles before we now get an instance of triangle because we've overrid an area and perimeter and just to verify we'll also check the area of this and also the perimeter perfect so how exactly is this working well if you watch my video on meta classes which I'll link in the top right now near the end I defined a class that was effectively the reverse version of an abstract Base Class and in that example if a child tried to override a method that was defined on the parent it would stop it from being created the inverse is true here for abstract classes so what python does is it has ABC which has a meta class defined of abc dot meta which we'll get to here in a little bit and that meta class will check through and see if there's any abstract methods that are still in the class that's trying to be instantiated and if there are it's going to raise that typer that we see here for that very same reason we can't create an instance of shape because it has two of these abstract methods intact the reason why these children can be instantiated is because they are overriding the definition that's provided on their parent and that's the basics of abstract base classes many times that you'll see these used it doesn't really get much more complex than this however if you do want to dig a bit deeper into how these work we'll do that now in the second more advanced example so from here on out we're going to dig a bit deeper into abstract base classes and some interesting things you can do with them especially if you're trying to write some type of plug-in type interface for this we're going to import just the ABC module itself and let's go ahead and Define a new service plugin class and for this instead of inheriting from abc dot ABC we're going to specify that it's meta class is ABC Dot ABC meta this helps to collapse The Inheritance tree a little bit more where instead of having ABC as a parent class of whatever your plug-in system is you can just have service plugin be the top level of course below object but you get that abstract Behavior by defining a meta class for the servers plugin I wanted to do a few things one I want it to be the primary interface for the plugins in our application in order to do that it's going to have to keep track of whatever plugins are available so we'll have a class level attribute of plugins which for now will just be an empty dictionary additionally most Services you don't want to create multiple instances of so they should exhibit effectively Singleton Behavior we can Define this on this Main Service Plugin class and then anything that inherits from service plugin will automatically have Singleton Behavior so I'll go ahead and write that out now okay so dundernew is now implementing Singleton Behavior Singletons themselves are pretty interesting and pretty easy to Define in Python they're a little bit out of scope for this lesson but I'll just give you the short version which effectively this checks to see if an instance has already been created for that class if so it Returns the instance if not it stores it and creates a new this effectively ensures that we can't create multiple instances of the same class there's different ways you can do that in Python some a little bit cheekier than others but this is a pretty good way to just force that behavior on child classes themselves and we'll just create a simple in it and it's just going to be a little noisy just saying initializing and then the class name and now for something that is not as widely known or perhaps not as widely understood when it relates to abstract based classes in Python is the ability to register a class to an abstract Base Class and this is behavior that we can override ourselves by defining our own custom register method in that call looks like ourselves and then what would be the plugging class so the main reason why you would want to register a Class 2 an abstract Base Class is if you're not a child of that class so you're not inheriting from it because inheritance automatically registers you as a subclass of the surface plugin class but you want to later on in code be able to pass assertions where they're checking to see if you are a subclass of this service plugin class and I'll show you exactly what that means here in a bit but what we're going to do now is we're going to use this registration to explicitly register all classes they're going to be plugins that way we create an instance of them right off the bat and then we can do things with them alright so with this register method we wanted to effectively have three behaviors the first check to see if the class being registered is already a subclass of service plugin if so then by definition it has to implement the abstract methods that we care about if it isn't a subclass of service plugin we need to check to see if it does implement the specific methods that we're looking for and if not the third Behavior we want to raise type error letting the user know that the class being registered has to Define these specific methods so first let's be a little noisy with the beginning of this saying that we are registering and then the plugin name or the class name next we'll check to see if it's already a subclass of our service plugin class if so we'll just initialize it remember that since these are subclasses of service plugin just creating an instance of that class as that class entry to our plugins dictionary so all we have to do create an instance of the class good to go from there next is the case where we want to check to see if it implements those specific methods if it isn't a subclass of service class so we'll do an LF condition we're going to check all and then this is going to be a little fancy list comprehension so we're going to check that it has attributes or each of the methods that we want or method in and then the name of the methods that we care about so those since it's going to be a service will be start stop and then status and here we're going to register the plugin as a subclass of service plugin in the way that we do that is by calling APC dot ABC meta dot register and then we're going to pass in our class here and then the plug-in class so what that's doing is it's calling the main registration method not our overridden version which then tells python that we want this additional class to be considered a subclass of service plugin even though it's technically not from there we do need to add it to our plugins dictionary so we'll do that now by creating an instance of the plugin now unless this plug-in class already has Singleton Behavior that's not something that we can easily enforce after the fact so we'll just create an instance here and then future behavioral will just be acting on that instance now it doesn't stop other places within the code from creating instances of the class but that's something that they're just gonna deal with otherwise we'll raise a type error letting whoever is trying to do this know that plugins must Define start stop and Status methods now we have our custom register method defined the rest of this is actually going to be pretty easy so these are going to be defining our abstract methods as you would guess we definitely want to have start as one of them this again can be passed and we'll just copy this for stop and status as well additionally we can add some more functionality to our service plugin class because we want this to be the main interface for our plugins right so let's define a new class method because we can't create an instance of our service plugin so we have to act on it from the class itself so we'll Define start all and this is simply going to iterate over all the plug-in instances in a list of class plugins dot values and this is just going to call plugin dot start and then we'll also do the same thing for stop all the sum just swapping start for stop easy enough Now using our service plugin class we can start all the plugins that are registered and stop all the plugins that are registered so with our main service plugin class defined let's go ahead and write a couple of plugins the first will simply just be called my plugin and this one is going to inherit from surface plugin with that it does need to find a start stop and status and this will be pretty simple we're just going to say starting my plugin and it'll do something similar for stop and status all right so we have our first plugin now let's go ahead and Define another plugin and what I mean is literally another plug-in this time it's not going to inherit from service class but it will still Implement all those methods that we care about right now we have our main service plugin abstract Base Class which implements all that functionality we did before we have my plugin which is a child of service plugin overriding start stop and status then we have another plug-in which is we'll consider an external plug-in which still implements start stop and status now let's load this in IPython and play around with it a bit okay no media errors so we're off to a good start so we have service plugin right right now there should be nothing in its plugins so we're good to go let's register my plugin okay so it tells us that we're registering my plugin and initializing my plugin good now if we check plugins we'll see we have a reference to the my plugin class and then the instance itself now let's go ahead and give another plugin a registration and we see that it registered another plugin now this one didn't tell us that it's initializing my plugin because it's not inheriting that init behavior from service plugin which is the noisy in it but if we look back in plugins we see that yes we have another plug-in class and then an instance of that plug-in class so now the behavior that we defined on Surface plugin where we can start all the plugins and we can stop all the plugins we use service plugin dot start all okay it started both my plugin and another plugin and let's see what happens when we stop all same thing stopping my plugin and stopping another plugin beautiful now what would happen if we didn't Define status on another plugin so let's go ahead and comment that out now reload it and then we'll register again another plugin here we go during registration it said registering another plug-in and then we get that type error plugins must Define start stop and Status methods beautiful our service plugin is working exactly as we would expect so as you see in this Behavior abstract methods are perfect for defining minimum Behavior but let's check that one additional thing here we'll revert that change load this again let's check if another plugin is a subclass of service plugin initially false but let's check it after we register that subclass and now it's true so that's the benefit of registration to an abstract Base Class even without that custom behavior that we defined before it allows you to do checks in your code for some type of subclass inheritance now one downside to that is by default the register method here doesn't check that all the abstract methods have been redefined on that child class so it won't do the validation that you'd normally get with a typical child like my plugin here so for that I recommend that if you are going to do registration in this way you should do a check here to make sure that all your app track methods are defined on that class that wants to be registered or you can just straight up Force registration only for plugins that directly inherit from your service plugin in general not allowing additional classes to register as a subclass the choice here really is yours and that wraps up this video now that you have a good understanding of how ABCs work try implementing them in your own projects and explore different use cases if you have any further questions or recommendations for others leave a comment down below to let me know as always today's code will be added to the understanding GitHub repo so check the description for a link and of course if you have any questions or suggestions for topics you'd like me to cover let me know in the comments section keep up with this series please consider subscribing thanks for watching [Music]
Info
Channel: Jake Callahan
Views: 4,175
Rating: undefined out of 5
Keywords: python abstract classes, python, python abstract base classes, python abstract class, abstract base class python, abstract base class python tutorial, abstract class, abstract class python, abstract classes in python, abstract classes, python abstract base class abc, abstract base class python 3, python abstract base class args, abstract base class, abstract base class python metaclass, python virtual class, abstract class register, register python class, python virtual classes
Id: IiXnwCyFVYo
Channel Id: undefined
Length: 21min 27sec (1287 seconds)
Published: Sun Apr 02 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.