Understanding Python: Decorators

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
the way that this works is each decorator decorates what's below it so change default is decorating very decorated return type is decorating change default and finally add attributes is decorating return type welcome back to understanding Python my name is Jake and today I'll be talking about decorators decorators are powerful tools that allows you to modify the characteristics or behavior of a function understanding in mastering decorators unlocks a new world of function design and will put you further down the path of becoming an advanced Python programmer select jump right in so at the top here you can see I put a little bit more into the doc string than usual that's because decorators can seem intimidating at first but if you've been following this series you've met all the prerequisites to follow along if not then at a minimum go watch my video on functions and come back so the basics of decorators are that they are functions that accept other functions as an argument and from there they can either modify the original function or completely replace them and I like to consider decorators as falling into four basic patterns the first pattern the first pattern is a decorator that returns the original function and the way we do this is to make a new function called change default this is going to accept a function as an argument it's only argument and at the end it's going to return the function now that's not very exciting so let's add a little bit more behavior in here and in order to determine what kind of behavior we want to add let's look at functions in ipython so we'll make a simple function here called test func that has an argument a with the default value of 5 and all it's going to do is return a okay so we have this test bunk object and one thing we can do to look at this is we can call the directory method on this test function and let's give ourselves a bit room so we can look at this we say there are a number of dunder attributes in this function the one that we're interested today is called defaults so let's look at this defaults test func dot dunder defaults and we see we have a tuple with the value 5 in it and that corresponds to a equals 5 so the default value for a is shown in this defaults here so what if what our decorator does is it modifies the value of that default well we can simply do this we have the function object so just like we did an eye Python we can access its default attribute and set that equal to a new tuple and instead of saying 5 will have changed we'll add a quick dock string and the doctrine explained in the decorator says this decorator changes the default value of a single argument function so now let's recreate our test function in code okay now we have our test function so let's call it in a new print statement we'll save it and run it and now we see down here calling test bunk and it gives us the value five perfect so test func is working exactly as expected that's because we haven't applied the decorator yet now Python didn't have a really nice decorator syntax the way that we would apply this decorator to test func would be to use this notation test func is equal to change default and we're going to pass in test func so what happens here is we're overriding test function with the output of change default and of course change default except a function to which we're passing in test trunk and as change default goes through we hit its second line where it changes the default value to changed and then simply returns the function now of course this works perfectly fine so we save and run this we'll see calling test func and now the new value prints out is changed but this on line 16 is pretty ugly luckily python has a better syntax for this so we'll get rid of that version and instead we're going to use the @ symbol change default right at the top here right above the function that we want to decorate so now if we save and run it again we'll see we have the exact same output calling test func and it prints out the value changed and now you know how to make a basic decorator or decorator that meets pattern one in prep for pattern two I added old funk in here which simply returns a string that says I'm an old function that shouldn't be used this would simulate a function that you don't want anyone else to use anymore and the way we can convey this point is that we can use the second pattern which is a decorator that returns a new function so we'll call this decorator deprecated of course it takes a function and we know that it's going to return a new function which we can define within the scope of deprecated so we'll just call this new function nothing since we want this to be pretty general instead of being specific to old funk we're gonna have it except star args and star star keyword args if you remember back to my video on functions you know just how flexible this pattern is now it function nothing is going to do is simply print an F string that has func dot dunder name which is the actual name of the function that's being passed in which we saw when we use the derp method on a function earlier and we can put a message app there saying has been deprecated now here we can either return a particular value or just nothing this is we don't really want to return anything we can just get rid of return altogether moving out to the level of deprecated and what deprecated is going to return is the function nothing so let's call this how it is right now we'll save it and run it and we say calling old funk I'm an old function that shouldn't be used now if we use the deprecated decorator save it and run it we see old funk has been deprecated and also the message calling old funk none so what's happening here well instead of actually running old funk down here in our print statement were really running nothing because the deprecated decorator actually switched the two functions out so this old function is never actually ran anymore and now you're starting to see the power of decorators is that you can take in a function and do just about anything you want with it including not running the function at all or swapping out for an entire function altogether so I'll add a quick little doc string to deprecate now doctoring being this decorator stops a function from running and prints a message I did a little bit more prep for pattern three which we just added a really basic function which simply returns as well as the print statement associated with it now pattern three is where we can really add in a lot of customization and make our decorators pretty flexible that's because pattern three is a decorator that accept arguments and returns the original function in order to do this we'll make a new function called add attributes we're just going to take in star star attributes we'll call it attributes in this case instead of keyword harms because it's a bit more clear what it actually is now you may be asking yourself why didn't accept a function that's because this pattern is a bit different than we saw in the previous two patterns what's actually going to accept the function as the function we're going to write under the scope of add attributes and we'll call this decorator because this is what's going to do the actual traditional decorating work and this is what accepts the function so it's in this decorator we're going to iterate over the key value pairs in attributes items and for each of those we're going to use the built-in function set adder passing in the function that our decorator receives and then the key and value this is what's going to add each attribute to our function then our decorator is going to return the function and add attributes is going to return the decorator the way that we apply this is using ad attributes and since it accepts keyword arguments we're gonna toss in something give it the value of else throw in another and set that equal to true and to demonstrate where she had two more print statements and we'll change this to basic funk dot notation and here put something down here else and then use the dot notation on basic funk to access those values and of course else should actually be another let's save it run it make sure that works and we see that does the last three lines calling basic funk returns none as expected because we didn't change any of the behavior of basic funk instead we added the attributes something with a value of else and another with the value of true how exactly is this working let's quickly show the longer notation and see if that helps so we're overriding basic funk with the result of calling add attributes with something and another passed in and that is returning the decorator which were passing in basic funk so add attributes is returning another function which then we're calling that function with an argument of basic funk and get the end result which is basic funk with a couple more actuates added and then pass that back along to the original basic funk I hope that clears that up understanding this part of decorator syntax isn't the most intuitive so if you have any questions about this or need additional clarification let me know down in the comments and I'll be more than happy to assist so a helpful doc string to add attributes this decorator adds specified hatching buttes to a function in preparation for pattern for I added a new function called loose return which simply returns any object has passed into it and tells you the type of the object that's passed in and then for our print examples we're passing in both a string and an integer so we'll save that print it and see what that looks like and we see that loose return says I'm returning an object of type string because we passed it in with a string that string being test next I'm returning it objective type class int because we passed in an integer 15 now if we wanted to make sure their functions aren't returning different values and we wanted to stay away from type notation we can make a decorator using the fourth pattern which is decorated accepts arguments and returns a new function so our outer function is going to be called return type and that's going to accept an argument called ret type standing for return type then we're going to write our decorator which accepts the function and then a new function here which are going to be swapping out for loose return called runner you could also call this wrapper or something else it doesn't really matter too much as this won't be presented to the user which accepts star args and star star keyword args and while runners gonna do is is actually going to run the original function passing in those args and keyword args and storing the result so result is equal to func unpack the args unpack the keyword args and now we can assert that we get back as result is the same instance as a return type that the decorator accepts so we use the is in built-in checking that result is an instance of red tape and then finally we'll return the original result that we got from the function so runners returning result the decorators function is returning Runner and then a return type function is returning decorator and to apply this we'll use at return type and then we'll pass in the type string so anytime loose return is called if it's returning a string perfectly fine if it returns anything else then it's going to give us an assertion error so we'll save it and run it oh and there we go if we look at that last few lines we see I'm returning an object of type string con loose return with our string test then it says I'm returning an object of type class int and then we get the assertion error and we see that assert is instance result and return type was not true so in this way we're explicitly checking to make sure that loose return is returning a string and nothing else and you can swap this of course out for an integer if you want save it and run that and you see you get the same error now a final thing before we go is that you can apply multiple decorators to a single function so if we wanted to add change default to this we can if we wanted to also add in return type put in that it should return a string because if you remember change default changes that default argument to a string we can do that as well and we can also add attributes to this again we'll add the attribute something but the value of else let's add one additional print statement down here just to prove that something did apply and before we save and run we'll come and out this line up here so we don't get our assertion error now if we see the last two lines we see calling very decorated now has a default value of changed and very decorated that something is equal to else and the way that this works is each decorator decorates what's below it so change default is decorating very decorated return type is decorating change default and finally add attributes is decorating return type so you can think as the top is being the outermost layer with the bottom being the innermost layer and that wraps up this video now that you understand decorators experiment with them in your code base and see what you can come up with what is your favorite trick with decorators or is it something I showed today 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 be like me to cover leave a comment for me to keep up with this series please consider subscribing thanks for watching [Music]
Info
Channel: Jake Callahan
Views: 174
Rating: undefined out of 5
Keywords: understanding python, python decorators, decorators, python, decorators in python, python decorators tutorial, python tutorial, python decorator, decorators python, decorator, python decorators explained, python functions, python tutorial for beginners, decorators python 3, python 3, decorators python tutorial, learn python, decorators tutorial, python for beginners, python programming, python basics, python - decorators, python 3 decorators, intro to python decorators
Id: BQ-l_tAMsb4
Channel Id: undefined
Length: 18min 19sec (1099 seconds)
Published: Tue May 12 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.