So let's talk about some of the practical applications of decorators.
I mean, we've already seen them in classes, right?
We saw how class method and static method, we're able to create class methods and static methods on
the class that the direct class can use.
And if you don't remember these, just go back to those videos.
But I want to show you one of my favorite examples of a decorator.
We're going to create our own.
What we're going to do is I want to have a performance.
Decorator.
And by the way, this decorator doesn't exist in Python.
We're going to build it from scratch.
What I want to do is be able to have a performance decorator that I can use during testing my code to
see how fast my code runs.
For example, if I had a function, let's say long time that takes.
Well, a long time to complete.
So I'm going to do a really long loop and say for I in range of let's say.
All these numbers and I'm just going to do a random calculation I times five.
This function.
I want to know how well it performs, how many milliseconds it takes to complete this.
So how can we belt that?
First I'm going to do something that we haven't talked about yet, that we will something about modules
and built in modules.
So for now, we're not going to talk about this too much, but we're going to import from the time module
something called well time.
Again, something that we'll talk about in the module section of the course.
I'm essentially saying, hey, when I installed Python or in my case when I'm using this ripple, it
has access to this time if I ask for it.
And in this case, I'm saying, hey, I want to use this time object or module that I get from Python.
And in here we're going to create our decorator following the pattern that we've learned.
I'm going to say define performance.
And performance is going to accept a function just like we've seen before.
And in here, we'll have our wrapper.
So let's say wrapper function and wrapper function.
If you remember, it's going to be flexible by taking in star arcs and star star keyword arcs.
So that we can pass it however many parameters we want, because we don't know how this function, how
many parameters it's going to have.
And I want to be able to use performance on all my functions.
Now in here first, what we're going to do is we're going to have the result of the function.
Be the.
Function that we receive right here and then simply say.
Run the function with star args and star star keyword arcs.
And finally, at the end of this, I want to return the results.
And then finally we're going to return the rapper.
So nothing we haven't seen before.
I could have just done return here or just ran the function, but I'll show you why I did it this way
in a second.
Right now, our function doesn't really do anything.
If I click Run.
Well, nothing happens if I do long time and I run this function.
It just took a long time to run.
But that's it.
Nothing happens.
This is when we make things interesting.
We want to calculate from the beginning of running this function to the end of running this function,
and we can use time module to do this.
I can create a variable time one for the start and simply say time.
So I'm running this time function that's going to start.
A time and say, hey, this initial time is going to be PT one.
And after this function, our main function, longtime, gets run.
I'm going to say t two and say, Hey, what's the time?
Right now.
So this time we'll check what time it's now.
And then we're going to run this function and then this time it's going to check the time.
And however much difference there is between these two is how long this part took.
Right.
So all we do is say print an F string and say it took T one minus t two.
Right.
And this actually returns in milliseconds.
So I'll just say GMs for milliseconds.
And that's it.
I've wrapped my function with just this extra time piece and then I'm printing as soon as we run the
function, how long it took.
So let's check it out.
If I now run my long time function right here and I click Run.
All right, I get a minus number because I messed up here.
This should be t two minus rt one because the time on RT one some time passes and then TT two.
So TT two is always going to be larger than TW one.
If I run this.
All right.
It took 0.16 milliseconds.
I think this is actually seconds.
Now let's make this long fonction even longer if I go like this and click Run.
Oh, boy.
That took 1.9 seconds.
What if I make it even longer if I click Run?
And this is the part where I keep talking until the function runs, because there's going to be an awkward
silence.
Otherwise, hopefully this ends soon because I have nothing else to talk about.
Come on.
This is getting awkward.
All right, come on.
Oh, boy.
Hmm.
I'm going to fast forward through here.
Oh, boy.
It took 19 seconds.
That's.
That's pretty bad.
But I now have this decorator that I can give to pretty much any function in my program and actually
measure the performance of my function.
Pretty useful, right?
I could have this piece of code and before let's say I deploy my code or put my code out into the world.
I can test how performant my functions are and maybe I can optimize things in different ways.
Very, very useful.
And I did that in just just a few lines of code.
Nine lines of code.
Now, mind you, this performance decorator depends on the machine and how fast your CPU and memory
are on your computer.
So for what took me 19 seconds might take you a lot more or a lot less depending on your machine.
But this is a nice way to compare functions relatively so, I hope after this you see the power of decorators.
Decorators are used a lot in Python libraries and frameworks.
We're frameworks that we're going to talk about, like Django and Flask use decorators.
Maybe you want to have some authentication decorator, so you do authenticate it where each function
can only be run if the user is authenticated, maybe they are.
They have the privilege to run a function such as logging in to a website.
Or maybe you just need a login or logging.
Decorator that just logs and lets your database know that, hey, somebody has logged into your system
or Hey, somebody has purchased something from Amazon.
Or Hey, somebody just requested a friend request.
There's so many uses for decorators and decorator is a hard topic.
You're not going to see them all over python code.
They're just an extra feature that you can use as you become more and more comfortable with Python.
But I hope by the end of this all, you will least understand them to maybe one day build your own or
use prebuilt ones by libraries and frameworks.
I'll see you in the next one.
Bye bye.