SIMPLIFY your code with decorators (+ typing)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
decorators are a really cool part about python that allow you to extend functions beyond their original functionality they allow you to remove code duplication but I mean they could be used to do all sorts of crazy things but they are also something that tends to trip people up quite a lot especially people coming into python for the first time they look at a decorator and think what the hell does that do so in this video I'm going to be going over the process of creating a decorator from the ground up so we're going to be starting by creating a simple decorator then we're going to type hint that decorator then we're going to create a parameterized decorator and we're also going to learn how to type pint that as well so you get the fundamentals of how they're built and also how to type pint them cuz Ty hinting them is a challenge in and of itself of course if you find the video helpful at any point then consider leaving a like to let me know and maybe subscribe if you want to see more videos like this but that other the way let's get decorating so we already have some test code on the screen this is just a little function for factorial and then you're running the factor function I'm actually going to change it to 100 not a thousand because the factoral of a thousand is quite a lot and that will prove problematic and we can do a print there like that and this just provides some context uh to create a decorator so what we're going to do is we're going to create a timing decorator this is quite a simple one to create all it does is essentially time how long the function takes to run and then print that to the console and then everything else is completely unmodified so it's a good one to start with so first we need to import time and this will have our actual time utilities and we could do from Funk tools import wraps and we'll talk about what that does in a second but to begin creating our decorator you just need to know that they are normal functions so we could do def timer and then we pass a function through so our decorator takes a function and then we Define another function inside that takes args and quags so in this instance the function will be our factorial function and our args and quags will be the args and quags of the factorial function in this case there's only the N so the N will get past ARs and quags will be empty but that's the general idea uh so we can do start equals time uh do perf counter NS perf counter NS just gets the number of nanocs since the start of the program's execution outside of time it it's the best thing to use use uh and then result equals Funk uh ARS quags so we're now calling the function with inside our wrapper we then end uh we basically just get the same again uh and then we can do uh actually probably do no we'll do Delta equal time. per count NS minus start that seems a bit cleaner read to me and then we can simply uh print that our function do name there we go uh took uh Delta and then bam bam bam bam bam just some string formatting Nan because this is Nan and then we can return the result of the function so this result will be the same as this result down here and then from the timer we can return our wrapper and then from there we can simply just decorate our factorial function with the timer decorator and we are good to go if I run this ignore that that was previous I'm abandoned in this video and we can see that our factorial took 7,875 NS and that the factorial of 100 is this so a quick recap of what's going on when we decorate this uh function uh when it's called the timer function is executed and the factorial function is passed in as this which we've called funk you can call that whatever you want we then Define a rapper in here and again you can call this whatever you want I just always saw this as rapper when I was learning about decorators I think that's the most commonly used you could use inner if that makes most sense to you or you could completely troll everyone and call it something crazy um it's your prerogative it's up to you inside this rapper we simply just um you know do some time stuffs we also run the function within it and then get the result out of it we then just print the amount of time it took and we return the result and then this return wrapper sets our factorial function to the wrapper so that's the important thing about decorators you're not actually executing this function you're now executing this function here which then calls our original function internally so you could create a decorator that just didn't call the function if you really wanted to but you could actually prove that it calls the wrapper uh by printing uh oops print factorial do Dunder name and when we do that we can see that it comes out with wrapper so we are actually getting this function's name back out if you don't want that to happen we can use the wraps that I said I'd talk about earlier so we can decorate our wrapper and yes it it does get a bit introspective at this point you can do wraps Funk what this will do is it will um give our wrapper function the name and the doc string and probably various other attributes to the wrapper function so now when we print factorial. name we will print factorial instead and if you were to print factorial do um Dunder doc it would print the factorial doc string and not either none or whatever you set this dock string to If you happen to set it so that's the basics of how decorators work and how to create them I'm now going to to type hint this if you don't want to see type hinting and you just want to move on to the parameterized decorators I have left time stamps in the description for you to skip forward and backwards uh but time painting decorators is kind of an art in of itself so I thought I'd cover it and make this a you know a comprehensive video of sorts um we are not going to be using python 3.12 generics one because I think they're harder to pause um especially when you're trying to learn something new and two because myi doesn't support them so we're going to be doing it the old way yay uh so we can do from typing uh import callable param speec and then typ VAR and then we can create P which is a param speec name P and R sorry which is a type VAR of Type R um so our P or our param speec will represent the args and the quags and then our R will represent the return value for the function so actually typing decorators I tend to type them inside out so I start with the inner function and then go out because I find that a bit easier but for our augs we could do p doogs and then uh p. quags and then we can return out R and what doing this allows us to do is it allows us to essentially inherit the type signature from or uh inherit the function signature from the original function so much like wraps allows us to use the original function name pram speec and then typ bars allow us to use the original function signatures so it will now realize um or statically typed it will realize that we are passing an integer and we're returning an integer as you can see from this typeint it still understands that actually typin in this function we can simply just use what we have here uh so we could do callable and then we take a pram speec and then we return a return value and then we return a call that takes the same pram spec and Returns the same return value because we're simply just running the function with the same inputs and we're returning the same output we're just doing stuff around it so we can share a function signature here and now this is all fully typed so if I do my pi- strict uh simple. Pi we will see that we have no issues in one source file so that's a simple decorator now moving on to the parameterized one I don't know what I've done there uh we can just copy this and paste this over to here so what I mean by a parameterized decorator is a decorator that you can pass arguments to so if you wanted to set the units um to something different so say if you wanted to have it um emit uh milliseconds instead of nanc and what if we wanted to set the Precision of our output we can do that to three for example and uh uh a parameterized decorator also known as a decorator Factory will allow us to do that so to actually do that we need to First rename this to decorator or you can uh rename this anything you want again this is a sort of pseudo standard I'll call it we need to indent this over we need to WRA the whole thing in another function called timer and we want to if I bring my notes up we want to set uh unit here string and then we're going to set that as a default to nanocs and we also want to set our precision as a keyword only argument to an integer and we'll default that to zero uh like that and then in our Delta what we want to do we actually want to define a series of units first up here so we set units here and then we set in a very specific order Nan seconds micros milliseconds and then seconds and we can use that order to our advantage later we can uh in our Delta we can change this so we can divide by a00 uh to the power of units dot index unit and what this will do so if we uh pass nanocs it will divide it by one so you get the same amount if we want to pass um microc seconds it will divide it by th because there are a th000 NCS in a microsc etc etc etc and we can use the units. index to you know come up with a smarter way of doing that and then we can simply just pass the unit here and then we can also pass the Precision here so that's a funky thing you can do in F strings you can put an expression within the format expression or a variable within the format expression or however you want to talk about that and then actually within our timer deck decorator we then need to return or our time my function sorry we need to return the decorator so if we would to run that if I would have run this without these keyword arguments actually we would get the exact same result as we did before where it does it in Nan seconds if we were to say we want it in in in milliseconds and we want the Precision to be three we now get it in the form of 0.007 milliseconds so we can see that our arguments have taken effect and what's happening here is that we pass the timer up and then we give it these arguments so we're actually calling this function as soon as it's evaluated so unit and precision are set internally and then we have our decorator here um and this decorator is then returned out the function immediately so our our factorial function is actually in a very similar state to it was here where you have a decorated actual function and then when it's run the the exact same process as before takes place where the function is you replaced with this wrapper and that's the only real difference that you know something is executed immediately and then this decorator just returns this essentially and then you can track the logic back from there if you wanted to type this it's really kind of annoying to do uh cuz it looks very weird so I'm actually going to do this no we'll do it on a same line for now I let the auto format sort out so going from inside out so we have this callable PR that is our wrapper and callable PR sorry our callable PR as our function and the same thing for the rapper so this timer is returning a callable that takes a callable and returns a callable so we can do that by doing callable and then within our brackets it's say it's taking a callable of P R and then it the return type is a callable of p and this looks awful but it is how you type parameterized decorators unfortunately an right code recently made a good video talking about an easier way of doing this or slightly less messy way of doing this um that I watched I was like w that's mental so I'll link that somewhere in the cards or whatever but this is how you would do it in its raw form and that is is pretty much the ins and outs of decorators let me know in the comments if this helped you out at all and also let me know what sort of things you're plan to use decorators for I would like to say a huge thank you to my amazing patrons and members on screen now especially Mazar rushman I thir for being so generous if you want to know how to implement o 2 from scratch in Python and go and watch last week's video where I covered that I'll see you in the next one for whatever we do next
Info
Channel: Carberra
Views: 3,686
Rating: undefined out of 5
Keywords: pyfhon, pytho, pytbon, pytjon, ptyhon, pytyon, ptthon, pyyhon, pythn, pythoh, pythpn, ython, pytgon, pyhon, pytohn, phthon, oython, pthon, pyghon, pythoj, pythno, pythkn, ypthon, pytuon, lython, pyrhon, pythom, pythob, puthon, pgthon, python, pyhton, pythln, pythin, pytnon, pyton
Id: cG451ZXWYC4
Channel Id: undefined
Length: 13min 56sec (836 seconds)
Published: Mon May 27 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.