 Welcome back everyone. This is Brian. In this episode, we're going to talk about decorators and no, it's not about making things prettier, although it does look a little better on the screen. So everything in Python is an object that means even functions can be used as objects. And that's really what decorators going to demonstrate. We can do some really cool things at the heart decorator takes a function, add some functionality and returns it keyword returns it. All right, let's dive in and take a look. So I'm going to do a decorator, and I'm going to do it wrong. I'm going to do it intentionally wrong to show you how decorators actually function. So we're going to say def and let's say test deck or radar. And I want to give it a function. Notice how that's just a variable. That's because everything in Python is an object. So say print or then we're going to actually call that function. You're a little confused here, we have a variable called funk. And it is actually a reference to a function. That's because you can pass functions back and forth like variables. So it just simply says before, color function and after. So let's go ahead and say run. And nothing happens because we didn't call this function. Now let's introduce the concept of a decorator. So I'm going to say def do stuff. And let's go ahead and say print doing stuff. Now if you look at these two functions, they're very basic. I mean, this is very easy to understand you have a function that has a function as a parameter, we're going to take that argument and then call it inside. So it's just, you know, calling another function. So we've got our do stuff. Now what a decorator is meant to do is say something like this F equals. So we're going to get some function. And we're going to say test decorator, do stuff. That's really what a decorator is meant to replace. So let's get rid of that. And let's call the decorator. And this is where a lot of newbies really, really stumble. I want to say test decorator. It's really that simple to create a decorator. You just have an at symbol with the name of the function over whatever function you want to decorate. Now there is a sneaky little problem here. This tech test decorator is not returning something. So when I run this, guess what happens. And I'm going to go ahead and clear this out just so you can see it. Did you catch the problem? We never called either of these functions, but yet it executed. And that's because what Python's doing under the hood is it's taking this and saying at test decorator, it's going to take this and put it right here and then just immediately call it. So the code's getting executed even though we did not directly execute the code. That's a fundamental newbie mistake. So be very mindful of that. Let's take a look at an example of a real decorator. We're going to do this the correct way. And it's very, very similar. I'm going to say def and I want to make bold. We're going to follow just kind of the same pattern here. And then I'm going to define an inner function. Now before I do anything, I'm going to immediately return that inner function without calling it. So really what I'm doing is I'm passing a variable back. Very, very, very important. You just kind of understand that concept of what we're doing here. We're making a function. And we have a function inside of a function and we're returning the inter function. So in the inner function here, I'm going to go ahead and just pretty much take the same pattern here. So now we have a before and an after and I'm going to, because we're making this bold, we're just going to say we're working with like some HTML. So we're just going to do the different codes for HTML. If you don't know HTML, basically what we're saying is start making this bold, stop making this bold. It's really all that is. All right. So now we can take that and say death print name, capitalize that just so it looks a little better there. And then we're just going to go ahead and print whatever your name is. Now we've learned from the last segment here that the at symbol with the function name is the actual decorator. So I'm going to just copy that name, go at and then make bold. Now watch what happens when I run this, we're going to see this up here, execute, but we don't actually see the Brian Karens. So really what we're doing here is we're making an equivalent to, and I'm going to copy some stuff on the screen, or just say off the screen. We're saying at make bold is equal to function equals make bold print name, and then calling that function. But that function call is just returning this inner function. If that seems really confusing, think of it this way. At make bold. So we're saying make bold, take this function as the variable. And then we're going to say inner is going to be print, call our function, print, and then return the inner without actually calling it. So now we have this variable we can work with. Man, that seems super, super confusing. But in reality, it's very easy to work with here. Now we can just say something like this, print name and call our function. And under the hood, remember what's going to happen is it's going to go through all of this decorator, return this inner. And when we call print name, it's actually going to call make bold, and then call this code gets kind of confusing, but the results are pretty astounding. Okay, just in case you need a quick, quick recap. At symbol means we're using a decorator, we're calling this function, we're returning this to the function as the parameter. And then the inner function is going to run some code, and we're just going to return that inner function as a variable. So essentially, basically what we're doing here is that we're calling that inner function, but we don't have direct access to it. And that's why people get so hung up on decorators. Once you wrap your head around that, they're actually pretty simple. Okay, if this was not confusing enough, now let's make it even more confusing. What if we wanted to pass parameters to this? How would we go about passing parameters to all these, you know, functions and inner functions and all this fun stuff. So that's what we're really going to look at in this little section here, decorators with parameters. So let's say we want to make some sort of function called divide. And this function should shockingly divide things. So the problem we have with Python is, well, it is very weak typed. And what I mean by that is, what is A and B is an integer? Is it a float? Is it a string? Is it a class? For example, can you divide A by cats? That's a really good question. So what we would need to do is something like that's print, A divided by B. Now if we were to, and I'm going to just put some stuff out here, copy and paste, what do you think's going to happen if we do 100 divided by three? What about 100 divided by zero, you're gonna get division by zero error. What about 100 divided by a string? Well, you're gonna get some really bad results. Let's just run this and see. Yep. Division by zero. Boom. Let's just try to bypass that. And let's do it again. And uh-oh, unsupported operand type in string. Super, super frustrating. So what we want is a decorator that will check to make sure if we can even do the division, and if we can to actually divide and return the result, which means we're now doing type checking, and we're passing parameters. Let's go ahead and make it real quick. So I'm gonna say def and let's call this num check. I almost wanted to call it num chuck, but gotta behave. All right. So num check short for number check. This is going to be our decorator, and we're going to have two functions in here. I'm gonna say def check int. Doesn't necessarily need to be an int, but just as an example, we're going to check to make sure it's an integer. And I'm going to immediately pass. And then let's say def enter. And in our inner, we want an X and a Y. And you notice this has a defined number of parameters. What's going on here is we are matching the function call. See how we have one two and one two. So pretty much we have two parameters. We want to make sure we're lining up with two parameters. We're going to show you how to get around this in the next segment, but I want to show you how to just pass the parameters. And that's why I have this at a specific number, one two and one two. All right. So in our inner, I'm going to say simply if not check int. And I want to check X. And we'll say or not check int. I want to check Y because we're going to check both of those make sure they're both numbers. If they're not, we're going to return. Now notice how we're not returning inner. We're just returning. So it's going to take no action whatsoever. Then we're going to drop out here and say otherwise, we're going to return the function. And if you're confused about where we're getting that is the parameter for our decorator right up here. And we're going to return X comma Y. Now let's go ahead and return our inner. And if this seems confusing, it's because this is bloody confusing. I'm sorry, it just is. I love decorators, but these are so confusing. So once we make this a decorator, and let's actually just do that right now. So Python is going to say num check. And then it's going to say divide past divide to this, which is going to go down into our inner and all this other stuff. And it's going to get passed around like hot potato and try to figure it out. That's confusing. That is so ridiculously confusing. Let's go ahead and do our check int. And then we'll step through this whole thing step by step, make sure we understand the logic here. So we'll say if is instance, zero comma int. So we're just doing some type checking here, some real basic type checking. And then beyond type checking, we had that division by zero. So if it's an integer, we want to make sure if O equals zero, we'll let the user know something happened here, print and not divide by zero. Then we just want to return false. Okay. If we've gotten past all this, let's drop out here, we're going to go to return true because it is not zero and it is an integer. So we should be able to do some sort of division. If we've gotten to this point, and we haven't already returned true or false, I'm just going to say print, this is not a number. That'll get rid of our pesky string problem. Then we're going to go ahead and return false. Okay. So the base logic here, man, fasten your seatbelt for this one. So our decorator is going to be num check some function. Our inner is going to come down here and say, okay, we've got two parameters x and y, if not, and then check in on x and check in on y, check in is going to say, is it an integer? If it is an integer, then we're going to say is it zero? If it's zero, then we're going to return false. However, if it is an integer, we're going to return true. And if we have not returned out of there, we're going to return false and say it's not a number. There's probably a vastly prettier way of doing this. I was just hashing out some code real fast. Once we've said, okay, it is not into integer, or it does not pass this check in, then we're just going to return nothing. However, if we are able to, then we're going to return the function x, y, which means it's going to actually do our division for us. Wow, that's crazy. All right. We've got our decorator in there. Let's just test it with 103 save run. Sure enough, it returns 3.3 repeating. Let's try our division by zero cannot divide by zero. Cannot divide by zero. So it caught that. Now let's try to divide 100 by cat. And cat is not a number. Very cool, very functional design. Without having to do a whole lot of back and forth, we can just simply define a decorator. And then, you guessed it, use it. And we can use this over and over and over again. It makes it so simple once we get to this point. Okay, the last little section there was really, really confusing. But the main takeaway here is that you can get some really complex functionality out of a simple decorator. The big problem was we had two arguments and only two. What if we wanted to have an unknown number of arguments and we want to chain them together? Let's take a look. So I'm going to make two decorators, say death and outline. And initially I'm just going to pass. We can take this copy, paste, let's call this list items. Now we're going to make another function and let's call it display. Display is just going to display a variable called message or MSG. Very simple, just going to print it out. Not sure where copy and paste is betrayed me there. There we go. All right, very simple, very easy to understand structure here. We're going to take these two and chain them together. And when I say chain, what we're talking about is something like this. So we've created a chain and it looks like a chain because you got these little at symbols or links in the chain. And these could just to kind of give you a graphical representation here. It looks like you have a chain going down the screen. Really, it's first come, first served. So outline will get called first and then list items will get called second. And we could just keep adding and adding and adding if we wanted to. But this is the main reason why we have to return our inner function. So let's start fleshing these things out. Now I want to say args, which stands for zero or more arguments or zero or more keyword args. If you skip that video, I highly encourage you to go back through the playlist. Link is down below. Watch the video and understand the difference between args and keyword args. And then print, we're just going to print out tilde times 20. Because outline is going to shockingly just outline whatever we put out here. Now we're going to call our function with our star args in keyword args. Once we've gotten to this point, very simple, just return our inner. We've got our first decorator pretty much done. All it's going to do is outline our function. Very straightforward. Now list items is a little bit more confusing, but not by much. First off, let's go down here and fix this MSG. There we go. Make it a little more apparent what display is actually going to do. So we're going to depth inner and we can just go right up here and grab this. Save us a smidge of typing. There we go. So first thing we're going to do is just, well, I must have clicked something. There we go. First thing we're going to do is just call our function. Then we want to be able to list it out. But before we do that, I'm going to just print f and we're going to say args equals. And I just want to see what Python is actually handing us. That way you can kind of wrap your head around this. We can do the same thing with our keyword args. And let's go ahead and return our inner. So now we have two different decorators that do two totally different things. We can then just call our function and see them in action. So we got hello world args, args, and this should actually be keyword args. Notice what's happening. If you were expecting hello world with a bunch of tildes underneath it, no. So basically list items is being called inside of outline. That's part of the chaining. So outlining is being called first. And because we are now passing this other decorator, it's now forming that chain. See how that works? Here is our end right here. And to just kind of break that up, we could actually turn this into like a plus symbol or something. Just so you can see the start and the finish. Till now plus symbols start, finish. Very, very interesting the way that works. I absolutely love it. But notice right off the bat here, args is a tuple. Keyword args is a dictionary. Okay, so that tells us exactly how we need to iterate through these things. So I'm going to say for X in args, let's go ahead and print. And we're going to format that format that. And I want arg equals and then X. And we can do something very, very similar for our keyword args, except for that's a dictionary. So we're going to do a key value pair. What I just did on the screen looks like black magic, go back in the playlist, link is down below and watch the video on the for loop on dictionaries. And we're going to do the keyword args dot items. And then we're going to say key equals X. And value equals actually not X. Sorry about that. He is K and value is V. There we go. Save run. And sure enough, our hello world. Notice how it's not got anything in this dictionary here is because we have no keyword args. See, we're just adding a normal argument. So let's go ahead and do something a little different here. We're say that birthday, and I want some keyword args name equals whatever, and age equals zero. And I'm going to say print, format, happy birthday, whatever their name is. You are whatever their age is years old. Now let's go ahead and call our function with the keyword arguments. And we can go ahead and just reuse these decorators. I'm just going to literally copy and paste. Notice how they're two different functions to two totally different things. And they even have different parameter types. But we can use the same decorators. Let's see it in action. Happy birthday, Brian. You are 46 years old. And now we have no args, but we have this nice dictionary. And we get the key and value out of that. And if I just go up, you can see how it fired off both of them. And everything's working as expected. So decorators main takeaway here is, well, they're complex. And they get really confusing really, really fast. But the biggest takeaway you should really understand from a decorator going all the way back to the very beginning is it's going to call this function right here. And if you don't return your inner function, it's just going to execute the code. So a real decorator looks something like this, you have your function, you've got your decorator, the decorator is going to have an inner function, and you're going to return a variable that points to that inner function. From there, really, the imagination you have is your limit, you can do just about anything you want. And these become highly, highly reusable, and you can make them as simple or as complex as you want. And you can reuse them across many different types of functions. I hope you enjoyed this video, you can find the source code out on github.com. If you need additional help, myself and thousands of other developers are hanging out in the void realms Facebook group. This is a large group with lots of developers and we talk about everything technology related, not just the technology that you just watched. And if you want official training, I do develop courses out on udemy.com. This is official classroom style training. If you go out there and the course you're looking for is just simply not there, drop me a note, I'm either working on it or I will actually develop it. I will put a link down below for all three of those. And as always, help me help you smash that like and subscribe button. The more popular these videos become, the more I'll create and publish out on YouTube. Thank you for watching.