Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Adding Parameters to Decorators

00:00 In the previous lesson, you created the decorator @limit_uses. limit_uses is an outer function and it accepts a function as an argument.

00:10 Within limit_uses, you define the inner function called wrapper(), and this is the function that will replace your original function, the one you want to decorate.

00:20 So the wrapper() function increments the value of counter by one, and then it checks whether this counter is still within the limit.

00:27 If it is, it calls the original function with the same arguments, *args and **kwargs, you pass the wrapper and whatever value the original function returns, the wrapper() function returns it.

00:39 However, if the counter is beyond the limit, you get a warning saying you’ve run out of tries. And since wrapper is local to limit_uses, you need to return it from limit_uses so that it’s available in your global scope, wherever you call the @limit_uses decorator.

00:56 And when you decorate any function with @limit_uses, the function is being replaced by the wrapper, which performs the same task as the function, but adds something else to it, adds the decoration.

01:09 Now, so far, this decorator only allows you to limit the number of tries to three. What if you wanted the decorator to be more flexible? And you want to be able to pass a parameter to the decorator to decide whether you want to use 2, 3, 5, or any number as the limit for the number of times you can use a function.

01:30 And the way to do this is to add yet another function. Let’s start by changing the name of the decorator @limit_uses to decorator.

01:40 This is not very descriptive, but it also tells us that this is the decorator function.

01:46 And you can take the whole decorator with its inner wrapper() function, indent everything by one, so that you can add yet another outer function.

01:56 So this is now the outermost function, and this is the function you are going to call limit_uses.

02:03 So now you have three layers of nesting. You have the outermost function limit_uses(). Within it, there is decorator, and within decorator, you have the wrapper.

02:12 However, limit_uses is not a decorator itself, so it does not accept a function as an argument. Instead, it can accept any other parameter. In this case, we can say limit, which will be an integer showing how many times you’re allowed to use the decorated function.

02:29 Therefore, the decorator() function now has access to the variable name limit.

02:35 So instead of hard coding the number 3, when you check whether the counter is less than or equal to three, you can now use limit.

02:44 But there’s one more thing we need to do. The decorator() function returns wrapper, but now the decorator is itself a local name within @limit_uses. You would like @limit_uses to return the decorator() function.

03:00 Therefore, @limit_uses is a decorator factory similar to the function factories you saw earlier in the course. But now @limit_uses accepts an argument.

03:11 This is the value you want to pass to the parameter limit. You can pass the value 3, which would make this equivalent to what we had before.

03:18 Let’s try that. And once again, the function greet_person() worked three times, but not the fourth time. You got the warning saying, You've run out of tries. Sorry!

03:30 But now you have the flexibility to change the argument you pass the limit_uses to any value you want. For example, you can now limit the function to only two uses.

03:42 And now you can see that James says hello to Mary, Keith says hello to Diane, but then you have the warning that you’ve run out of tries twice because you’re only allowed to use the function twice in this case.

03:54 So in this case, you can notice how wrapper, which is the closure, is referencing counter, which was defined in the scope just outside of it, but also limit, which was defined in the outermost function.

04:07 The closure has access to both counter and limit.

04:13 So let’s briefly summarize what the decorators are and how we use closures within them. So a decorator is a function that accepts another function as an argument and returns yet another function.

04:24 Lots of functions moving around. You pass the function you want to decorate to the decorator, and the decorator then returns the decorated function.

04:33 So a decorated function performs the same operations as the original function, but it can also include additional operations. For example, in this lesson, you are checking how many times you’ve already called the function, and if you’ve gone beyond the limit, you show a warning sign saying, I’m sorry, you can’t run this function again.

04:52 If you want to find out more about decorators, we have a Real Python video course for you: Python Decorators 101.

Become a Member to join the conversation.