[0:00] What is going on everybody? So today I [0:02] got to talk about decorators in Python. [0:04] A decorator is a function that extends [0:07] the behavior of another function without [0:09] modifying that base function. We pass [0:12] the base function as an argument to the [0:14] decorator function. For example, let's [0:17] say we have a base function of get ice [0:19] cream and you can pass in a flavor of [0:21] ice cream. Well, some people might want [0:23] sprinkles on their ice cream and others [0:25] may not. They might just want plain [0:26] vanilla. Well, we could add sprinkles by [0:29] using a decorator. We're extending the [0:31] behavior of a function where we get ice [0:33] cream where we're adding sprinkles. But [0:35] we may not want to change the base [0:36] function because some people don't like [0:38] sprinkles. Think of decorators that way. [0:41] We're adding something to a base [0:42] function without changing it. Here's how [0:44] to create a decorator. Let's start with [0:47] the base function. We will create a [0:49] function to get ice cream. There will be [0:53] no parameters for now. All we're going [0:55] to do is print the following message. [0:59] Here is your ice cream. And for fun, [1:02] I'll add an emoji. I'll add an ice cream [1:05] emoji. To call this function, all I got [1:08] to do is call the get ice cream [1:09] function. [1:11] Here is your ice cream. Here's how to [1:14] create a decorator. [1:16] A decorator is a function. We'll need to [1:19] define it. define add sprinkles. Our [1:24] decorator function is going to have one [1:26] parameter, a function, but we'll just [1:30] rename it to funk for short. We're going [1:33] to pass a function to our decorator [1:35] function. [1:38] Within our decorator function, we will [1:40] define an inner function of wrapper. [1:44] Currently, there's no parameters. We'll [1:46] set that up later. [1:48] Within this wrapper function, we will [1:50] call the function that we receive this [1:53] parameter. [1:55] Then we will return our wrapper [1:58] function. Up until this point, we've [2:01] been returning values, but now we're [2:03] going to return an entire function. [2:05] Here's the basic formula to create a [2:07] decorator. To apply a decorator to a [2:10] base function, preceding that function, [2:13] you're going to add at the name of the [2:15] decorator. So add sprinkles is a [2:18] decorator. The base function is get ice [2:20] cream within our decorator. How do we [2:24] want to add sprinkles exactly? Currently [2:26] our decorator doesn't do anything. [2:29] Here's what happens. We just print here [2:31] is your ice cream. Let's say that before [2:34] we're given our ice cream, we'll print a [2:36] statement that we add sprinkles [2:39] within our decorator. Imagine that we're [2:41] replacing calling function with this [2:44] print statement. [2:46] Let's create another print statement [2:48] where we add sprinkles before it. [2:52] I will print the following message. [2:57] You add sprinkles. And I'll add an [3:00] emoji. [3:02] How about confetti? That could resemble [3:05] sprinkles. [3:07] Okay, let's see what happens. [3:10] You add sprinkles. Here is your ice [3:12] cream. [3:14] We're decorating our base function of [3:16] get ice cream with a decorator of add [3:19] sprinkles. [3:20] We're not modifying the base function. [3:22] We're extending it. Now, we have a [3:25] nested function of wrapper within our [3:27] decorator. It is necessary to have this. [3:30] Here's why. So, I'm not going to call [3:32] the get ice cream function quite yet. [3:35] So, nothing should happen. [3:38] If I was to remove this wrapper, [3:45] well, we'll end up calling this function [3:47] as soon as we apply the decorator. We're [3:50] not even calling the get ice cream [3:52] function at all. We only want to execute [3:54] this code when we want ice cream, not [3:57] whenever we apply the decorator. [4:00] That's why we need that wrapper [4:01] function. [4:04] We'll get ice cream and add sprinkles. [4:07] Only when we call that function, [4:11] then at any point in my program, if I [4:13] call the get ice cream function, [4:16] then we get ice cream with sprinkles. [4:20] Let's apply more than one decorator. [4:23] We'll create a decorator to add fudge. [4:26] Define add fudge. [4:29] We have one parameter, a function, which [4:32] we will rename as funk. [4:34] We need an inner wrapper function. [4:38] This is so that we don't call this [4:40] function when we apply a decorator. [4:43] I will print [4:47] you add fudge. [4:53] Close enough. We'll add a bar of [4:55] chocolate. [4:58] Then call the base function that we [5:00] receive. [5:01] Then we need to return the wrapper [5:03] function. [5:05] All right. Given our base function, we [5:07] can apply more than one decorator. Let's [5:10] say that after adding sprinkles, [5:13] we will apply the decorator where we add [5:15] fudge. So now [5:19] we have the following output. [5:21] You add sprinkles. You add fudge. Here [5:24] is your ice cream. So with decorators, [5:27] you can apply more than one decorator to [5:29] a base function. [5:31] What if your base function accepts [5:33] arguments? For example, when we get our [5:35] ice cream, we need to pass in a flavor [5:37] like vanilla. [5:40] I will set up one parameter of flavor. I [5:44] will convert our print statement to be [5:46] an fstring. Here is your add a [5:49] placeholder [5:51] flavor of ice cream. Let's run this and [5:54] see what happens. [5:57] All right, we have a type error. Our [6:00] wrapper function isn't set up to accept [6:03] arguments. What you'll see within [6:05] wrapper functions is that they'll have [6:06] parameters of args [6:09] and quarks to accept any number of [6:11] arguments and keyword arguments. [6:14] Then when you call your base function, [6:18] in this case get ice cream, we will also [6:21] set this up to accept any number of [6:22] arguments and keyword arguments. Let's [6:25] do that within our add fudge decorator [6:27] too. Our wrapper function will accept [6:30] any number of arguments and keyword [6:32] arguments. Same thing goes with the base [6:34] function. And now this should work. [6:38] You add sprinkles, you add fudge. Here [6:40] is your vanilla ice cream [6:43] or any other flavor of your choosing [6:46] like chocolate. [6:49] You add sprinkles. You add fudge. Here [6:51] is your chocolate ice cream. All right, [6:54] everybody. So those are decorators. [6:56] They're a function that extend the [6:58] behavior of a base function. In this [7:01] case, get ice cream. Decorators extend a [7:04] function without modifying it. If you [7:06] would like to apply a decorator to a [7:08] function, you preede that function when [7:10] you define it with at the name of the [7:13] decorator. And you can apply more than [7:15] one. And well everybody, that is an [7:17] introduction to decorators in Python.