Protocols vs ABCs in Python - When to Use Which One?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in pyth both protocols and Abstract base classes can be used to create a layer of abstraction by defining the interface but what's the difference really when do you use which I did a video about this already a long time ago when I was still young and I didn't have a beard yet it's a well-known fact that content is way better if there's a dude with a beard in it I refer you to deep space line if you want proof we are your allies major lock phases on M Char's engines in other words a missed opportunity so it's time for an update on protocols and ABCs and some of the weird things I encountered while using them for the past few years choosing between these two does impact the design of your software if you want to learn some of the other things you need to think about when designing software check out my freedesign guide. ion. c/d designu contains the seven steps I take whenever I design a new piece of software and hope it helps avoid some of the mistakes that I made in the past rn. codesign guide the link is also in the description of this video abstract base classes and protocol classes are both ways of defining interfaces in Python abstract based classes have been part of the Python standard library for a long time protocols have been added in Python 3.8 the main difference between them is that with ABCs you typically use inheritance whereas with protocols that's not necessary but as I've been using these for a while now I've also noticed I've started using ABC and protocols in slightly different ways and they also sort of overlap in features so even though I covered both of these ABCs and protocols in previous videos quite a few times I thought it might be nice to revisit them and take a look at some of the things that I've learned and also some of the idiosyncrasies that occur when you're dealing with protocols versus ABCs here's an example of what using an ABC could look like so I have a class here serialized file handle that is a subass of ABC so this is an abstract Base Class it has an initializer that sets a file name and then it has abstract methods so typically when you use an ABC you're going to have some abstract methods in there so in this case there is serialized method that take some data and returns bytes and we have a deserialize method that takes bytes and returns a dictionary then you can add other already implemented methods like in this case writing and reading that uses some of these abstract methods now of course we didn't Supply an actual implementation of this right they're abstract so that means that if in this main function I try to use a serialized file Handler here and then try to write the data and then read that data and print it so when I run this you see we get an error that we can't instantiate an abstract class serialized file handra without implementing the abstract methods and our error handling in Python even tells us which methods we we should Implement so if you can't create an instance of an abstract Base Class what do you actually use it for well it serves as an interface or a base implementation of other classes so here's an extended version of this example so we have again the serialized file hander with the abstract methods serialized der serialized just like before but now I've created implementations of this particular class and to illustrate how this works I'm using two serialization mechanism one using Json and another using pickle so for each I've now created a class that inherits from serialized file Handler and that implements these serialized and deserialized methods so the pickle Handler uses pickle to serialize and deize the data and the Json Handler uses Json dump and Json load so now in my main function instead of creating an instance of serialized file handle which I'm not allowed to do I can create instances of pickle Handler and Json Handler because these implement the serialized and deserialized methods and what's nice about this inheritance mechanism is that then both of these classes are also going to have the right and read methods because well because of the inheritance mechanism right so the way we use this is that say we have some data named joho h30 then we can use the pickle handle class that I've defined at the top and then write the data and read it it again and same for the Json Handler so in this case I'm writing the data to Json file and then reading it again and print it so let's run this example and now you see we get of course twice the same outputs but also we see that it created two files we have data. pickle which we can't read here but data. Json contains the actual Json data the serialized data so in short by using abstract base classes in this way you already can supply part of the implementation of a class and then use the inheritance mechanism to avoid code duplication because now we don't have to add these methods to all the classes that need to read and write information what's nice about ABC is that they really tie in neatly into Python's typing framework for example here I can check that pickle writer and Jason writer are both instances of serialized file Handler which is the case because you see we don't get an error when we try to run this and of course we can also check that this is an instance of pickle Handler which will also be true so when I run this I'm going to get exactly the same results so you can easily use ABCs for type checking and comparisons in this way Protocols are an alternative to ABCs that work slightly differently so whereas with ABCs you would typically use inheritance with protocols that's actually not necessary and that's because they rely on something called doct typing and that comes from the saying if it walks like a dock and tastes like a dock then in most restaurant months it's going to be a dock hopefully for you in practice what this means is that you can Define with a protocol what kind of methods or properties you expect an object to have and then at runtime python will just check if an object adheres to that protocol and if it does then there's no issue if it doesn't then it's going to raise an error so here I have an example of how that could work so I have a writable class which inherits from the protocol class that's similar to how we would use ABCs it has a write method that takes a dictionary and same I have a readable class that has a read method that returns a dictionary now as you can see in both cases these methods are not implemented just like with ABCs but now what you can do is use these protocol definitions as types for example you could have a method do write that gets a writable and that then calls the right method and it knows that writer has a right method because it adheres to this writable protocol and of course we can do the same thing for reading because that works in a similar way so let's say I have a class author and an author has a name and we're going to implement the right method and that right method does nothing that simply print out that name is writing some data so now what we can do is we can create an author with a name and then we can do write and pass the author to the method and so when I run this then you see we get this output just as we would expect what's interesting about this example is that author has no relation whatsoever with the readable or writable protocol it simply happens to implement the right method and that has the same signature as the right method in this particular protocol class so what happens if I change the signature here so let's say I change the right method and then call it write something I of course need to type something correctly very important but then when I try to run this you see that we get an attribute error that the author object doesn't have an attribute right and that goes wrong in this line of code so this is something that is checked at runtime you see that it's not being checked here while we're writing this though you can use tools like pyin to do type checking for you before you actually run the code which is really helpful but when you run this code the place where this goes wrong is here now what you can do similar to what we did with ABCs is that you explicitly inherit from the writable protocol like so the interesting thing is that when you try to run this then there is no error even though in this particular protocol example actually the right method is not implemented in the author subass just like with ABCs you can also make these methods abstract in a protocol class so abstract method The Decorator abstract method also works with protocol classes so when you run this again you see that but now we get again a type error that author can be instantiated without implementing the abstract method right so this works in more or less the same way so in a sense protocols is almost like ABCs except for it allows you to use dock typing instead of ABCs which use nominal typing explicit typing however there are a couple of weird things going on with protocols that you should know about so here I have another example I went back to the serialized file Handler example I showed you in the beginning of the video so that's still an ABC it has abstract serialized der serialized method it has writing and reading just like we had before I have the pickle Handler and I have the Json Handler and I've also added these writable and readable protocols here and now I have my write and read function that get a writable and readable that sounds like something we would really like to use protocols for right but then in the main function I create pickle writer I create ajacent writer just like I did before and then we do some asserts so we check whether pickle writer is of type writable and where the Json writer is of type readable so the question is is this going to work and is pickle writer an instance of writable I mean it kind of should be because we can pass it to the right function so we should expect the types to match right that's what duct typing is supposed to do so I'd expect this is in instance check to return true and same for Json writer to be of type readable I would also assume that to be true but what's interesting is when you try to run this you actually get a completely different error you see we get instance and class Tex can only be used with runtime checkable protocols and here you see a difference between protocols and ABCs protocols can be used by default for these types of runtime checks so these instance checks are going to fail if you use protocols and what we need to do is add the runtime checkable protocol just like the aror indicates so in order to fix this we should add runtime checkable to both writable and readable and this we should import from typing and now let's run this again and now we see we get the behavior as expected because we now enabled runtime type checking for our particular protocol classes but still it's not really a complete type check here I have another example so I have my writable protocol class that's runtime checkable so we're good to go right so it has the right method what I've done here is I've created a bytes IO object which is buffered iio implementation that uses a bite buffer doesn't really matter what this is from the io package so I've created an instance here and then I check that IO writer is an instance of writable so let's run this and see what happens so we see it doesn't crash so it's clearly an instance of writable but now let's say I call I writer. write which we should be able to do right because it is an instance of writable so when I run this now we get an error that I writer. write requires a bytes like object and not a dictionary so the reason this happens is because the runtime dock typing mechanism doesn't check all the little details because it's runtime so I guess they made some trade-off in the python interpreter to make sure it doesn't spend too much time checking in depth all the types so you can still run into these kinds of issues so in case of the protocol if it quacks like a dock and it tastes like a dock in the python restaurant it might be a dog or we're not completely sure so should we stop eating in Python restaurants that's the question let me know in the comments anyway all kidding aside protocols and ABCs are both useful for defining interfaces and it's a good thing to be explicit about this so if you Define abstract based class if you define a protocol class this helps you write code that's easier to read because you are more explicit about how the types are being defined in Python it's really easy to just omit all the types and do whatever right but that makes your code pretty hard to read so I try to avoid that at all times I find ABCs particularly useful when you already want to have a bit of implementation in your base class like in the serialized and deserialized example I showed you in this video so there we can already provide write and read methods and we don't have to reimplement them for every subass with protocols you would typically not do that because you wouldn't have the inheritance relationship even though you can still use protocols pretty much in the same way as ABCs but as I've also shown you there are some caveats in how protocols tie in with Python's type system they're not as well integrated as ABCs by the way if you're enjoying this video so far you might also like my Discord server there's a lot of knowledgeable people on there very interesting discussions you can join for free via the link below a very good use case of protocol classes if you want to specify what type of argument a function expects in terms of what kind of object that is this is exactly what you see in this example where the do write function specifies that it wants an object that has right method and that's why Protocols are very powerful and that means that you can pass an object to this function that's implements the right method but we don't really care what object this is so this can also be an instance of a class that's defined in a third party library that happens to have the right method and in that case ABCs wouldn't work because we can't change the class in the original code that's not our code but as I've also shown you in this example there are some caats in how stable and how predictable this is so this can lead to situations where you get a problem that's pretty hard to debug so that's just something to be aware of when you're using protocol classes typically I tend to use protocol classes more than ABCs you don't need to to use inheritance in that case but if you can it's a nice thing to do because then you're more explicit about your types so I hope this video gave you a bit more insight into protocols and ABCs and how they work on the hood whether you're using protocols or ABCs there's one place where these types of abstractions are really useful and that's if you're implementing dependency inversion this is a very powerful principle that helps you decouple your code if you want to learn more about that watch this video next thanks for watching and see you in the next one
Info
Channel: ArjanCodes
Views: 32,993
Rating: undefined out of 5
Keywords: protocols vs abcs, protocols vs abc, protocol python, protocol vs abc, protocol or abc, abstract base classes, abstract base class, python abc, abcs python, abstract base, python, python programming, python tutorial, python programming language, Abstract Base Classes and Protocols, abstract classes and methods, python programming basics
Id: dryNwWvSd4M
Channel Id: undefined
Length: 15min 30sec (930 seconds)
Published: Fri Mar 29 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.