Here are some resources for more information about topics covered in this lesson:
00:00 In the previous lesson, I showed you how to use closures that wrap data functions as decorators. In this lesson, I’ll show you how to pass parameters to decorators. Spoiler alert, you’re going to add inner functions to your inner functions.
Here’s my new decorator called
who_says(). It takes an argument, which will be a name. In the continued tradition of just adding another layer of inner functions, you can get your decorators to take parameters by using an inner function.
As a decorator is a closure generator that takes a data function, the first inner function is exactly that. Inside of that is the
@wraps decorator on the
wrapper() function like I showed you in the previous lesson. The logic in the wrapper checks if the
name argument for the decorator is
'simon' and if it is, it runs the decorated function. If it isn’t, it raises an error.
01:44 I don’t know who Bob is, but evidently he doesn’t have the authority to do subtraction. I do a lot of Django programming. In Django, when you type in a URL in the browser, it gets mapped to a function called a view.
A common chunk of code at the beginning of that kind of view is to check that the
POST data is present. I have an open-source Django utility library called Awl that contains some decorators. There’s links in the notes below if you’re curious.
This decorator is parameterized so that you can specify what
POST variable contains the JSON dictionary. With a decorator like this in place, all I have to do is decorate my view, and ten or so lines of validation code doesn’t have to be written over and over again.
It also acts as a nice piece of documentation. Right at the declaration line of the view, I can see that it takes JSON data and it requires a
POST. Decorators are a pretty powerful tool, and a common pattern in a lot of the web frameworks like Django and Flask for permission mechanisms like this one I just described.
03:10 You’ve now seen decorators with and without arguments. Decorators with arguments require one more layer of inner functions than those without. This would imply that you’re in an either/or situation—you either need them or don’t need them. Well, with a little creative work, you can actually create a decorator that supports argument lists or argument formats. Let me show you how.
03:37 You ready for this? It takes a little bit of mental gymnastics. In the previous example, I showed a decorator that took an argument. It used an inner function that was like the decorators you’ve seen before.
It takes an argument that I’ve called
method_or_options. If you decorate a function with
@gift() and give
method_or_options will be those parameters. If, on the other hand, you decorate something with
@gift and don’t give it parameters, then
method_or_options will contain the function being wrapped.
This is why I called
method_or_options what I did. It either contains a method being wrapped or options for the
@gift decorator. Lines 6 through 8 figure out which is the case and set the
fields variable accordingly. Lines 10 and 11 put you back on familiar territory—the usual wrapper closure. In lines 12 through 15, I use the same
if callable() trick to print out a message that tells you how the decorator was invoked. Lines 17 and 18 are the usual return of the closure.
Skip lines 20 and 21 for a moment. Go straight to line 23. This is what you’re used to—returning the inner function as a closure, the thing that does the work of the decorator. Now consider for a second what happens if there are no parameters to
@gift. In this case, there’s an extra layer of inner functions. You need to short circuit this inner layer. You can’t just return the closure, you have to invoke the closure. Line 20 detects that a function was wrapped and line 21 is the invocation of the closure, or in other words, doing what a decorator without parameters would do by default.
06:11 Think about this again for a second: a decorator is a closure around a data function. Our decorator with optional parameters either uses an inner function to get at those parameters or, if there were no parameters, instantiates the closure inside of the decorator and returns it.
06:29 Don’t feel bad if your brain just melted. Most of the time when I use this trick, I just look up how I did it last time. The first time I came across code like this, I had no idea what it was doing or why. But it worked!
This time, you get the default value of
fields, which is an empty list. If you want an extra little challenge, see if you can modify
gift() so that it can be called not only without options but also with any number of options. The code as it stands only allows a single argument at the moment.
Become a Member to join the conversation.