From the course: Python: Decorators

What are decorators? - Python Tutorial

From the course: Python: Decorators

Start my 1-month free trial

What are decorators?

- [Instructor] Now that we've reviewed functions in general let's look at decorators. A decorator is a callable that takes another function as an argument, extending the behavior of that function without explicitly modifying that function. So a decorator has the ability to run additional code before and after each call to a function that it wraps. This means that decorators can access and modify input arguments and return values. So why do we use decorators with functions? I mean if I want to change a function why don't I just go ahead edit the function? Well let me give you an example to illustrate. Now let's say I have a project. And say I want to do the same operation to all of the functions like adding log into the function. Now this is a big project, so I've got something like 50 different functions. I could go ahead and edit each of the functions. So I go into each function, paste some code around logging that function, and then move on to the next function. Alternatively, I could use decorators. The advantage of a decorator is that it will change the behavior of that function without permanently modifying it. So let's say later on I decide that I don't want to be logging the functions it's easier to remove this than going into each function and removing some lines of code. Let's go back to our simple print Fib example. So go ahead and open the file my decorator.py. As you can see this already has the function pfib that we created earlier. Now let's create another function that we'll call my decorator above it. So, def my_decorator, and we'll take in as an argumentative function. And so this is our decorator function. The original pfib function only returns Fibonacci in low case. This time round, we'll return Fibonacci but in capitals with a dash or a hyphen between each letter. So I'm going to create my wrapper function, so wrapper. And we say this returns a string. So I'm going to type FIBONACCI, and I'm going to put the hyphen between each of the letters. And let me copy that string and let's return Fibonacci that way. So return, and our string F-I-B-O-N-A-C-C-I. And at the end of this, we're going to return a wrapper function. So return wrapper. Now let's print out the pfib function so that we can see the output. So print pfib. Now let's confirm that if you call pfib you'll just get the output Fibonacci. So python, and my file, just my decorator.py and you can see we've got the output Fibonacci. Now if we go ahead and define the following, so we say, pfib = my_decorator. And we provide as an argument pfib. What do you think the output will be? Well let's run the function and take a look. Pfib now points to the inner function called wrapper within my_decorator. Now you may think, "wow, when did we do that?" When you call the my_decorator function with pfib as an argument, what's being returned is the wrapper. And this assigned to pfib. Now Python allows you to use decorators with the simplest syntax using the add symbol. So adding a my_decorator before the pfib function definition is just another way of applying a decorator to a function. So let's go ahead and replace our current definition with the @my_decorator syntax before the function pfib. So I'm going to remove that and use the alternate syntax @my_decorator, and let's confirm that we get the same output. So decorators are powerful because they can replace the decorated function with a different one. But let's confirm this by printing out the reference to pfib. So I'm going to replace my call to the pfib function with just printing out pfib. And you can see that it has a reference to the the wrapper function in my_decorator. So let's complete this section with a summary of what a decorators typically look like. So on the first line we've got the function definition called my_decorator, taking in as an argument the function func. We then an inner function which I've called wrapper. Now in wrapper you normally do something before calling the function. Whatever is returned from calling the function func is stored in result. And you might want to do something after calling the function. And finally we return the inner function, wrapper. In the Fibonacci example we looked at it just so happened that we didn't have to do anything before or after calling the function.

Contents