Python Decorators Guide (the easy way)
Let's face it: without decorators, you can code just fine. Indeed, you can write acceptable code without them. However, decorators are a very useful feature of all current languages — and for good reason. They enable you to build more readable and maintainable code. Perhaps you've heard of them or perhaps worked with some current decorators without fully comprehending them. You've come to the right spot, as our Python Decorators Tutorial will cover all you need to know! We'll look at what Python decorators are, how to construct them, and how to utilize them. You will soon become a master of them!
This will alter our function, without messing with its internal code. Later in this Python Decorators Tutorial, we will see many applications of decorators.
This function is altering the number x. For a decorator,
Your decorator can accept parameters as well! Generally, you provide it with static info, as you want to alter this specific function always in the same way. By providing parameters statically for the decorator, you can do more than that. You also write such parameters close to the method, so you can see the whole picture in the same piece of code. Simply provide parameters as you would for a normal function.
In this example,
Now we can apply this decorator to everything, from standalone functions to class methods.
Now, you can call this decorator in the following way.
What is a Python Decorator?
Believe it or not, a decorator's main responsibility is to decorate an occasion. In other words, it augments that function with additional functionality, so modifying its behavior. The amusing aspect is that you just apply the decorator on the function, not its internal code. A decorator modifies the behavior of a function. If you program with classes in Python (as you should), you know about the decoratorstatic method
. You apply it to a method of your class, and it does not require the self
parameter anymore.
@staticmethod
def do_something_statically(a, b)
pass
What is a Python Decorator, exactly?
Okay, now we know what a decorator does, yet we have no definition for it. The truth is, a decorator is nothing more than a function.A decorator is a function.Specifically, a decorator is a function that, as a parameter, wants a function to modify. Imagine you have a function that receives a number and returns its double, like the one below.
def double(x)
return x*2
x
will be a function – not a number. Like this function is returning another number, the decorator will return another function. If you think this is messy, as soon as you will see you will understand the beauty of decorators.
How to apply decorators
Before we dive into our Python Decorators Tutorial, we may want to know how to decorate a function. Well, you saw that from the first example: you write the decorator name above the function, after a@
sign.
@decorator
def function_to_decorate(a)
pass
@decorator('parameter')
def function_to_decorate(a)
pass
Order matters
Python applied decorators bottom up. In other words, it applies the decorator closest to the function first. Imagine you have three decorators as in the example below.@a
@b
@c
def func(something):
pass
c
will decorate the function as usual. Then, b
will decorate the function as c
decorated it. And finally, a
will take the function as it comes out b
‘s manipulations and alter that as well.
Writing decorators in Python
Read More: A Beginner’s Guide to File Management in Python
Our first, simple, python decorator
Our first decorator is pretty useful: it publishes the duration of a function's execution on the screen using the time library. To do this, our decorator must modify the target function and construct a new one that performs the following functions.- Determines the current time.
- Executes the original function's code and records the result.
- Calculate the current time and subtract it from the previous measurement, getting and publishing the difference.
- Returns the previously stored result.
import time
def measure(func):
def func_wrapper():
start = time.time()
result = func()
print(time.time()-start)
return result
return func_wrapper
The explanation
As you can see, we define a function inside the decorator. This function,func_wrapper
, is the altered function after the decoration. As you can see from the last line, we are returning this function from the measure
decorator. Note that in the return statement we didn’t use the brackets, and for a reason. By using the brackets, you would call the function and return what that function returns. Instead, we want to return the function itself.
The func_wrapper
function is way more simple. It measures the start time, runs the original function func
, and prints the time elapsed before returning the results.
From problem to solution…
If you look closely at the script above you will see a major problem. We call the original function with no parameter at all. This means that we can only decorate functions that do not accept parameters, which is useless. Our Python Decorators Tutorial wants to get you up and running with the real stuff, so we have two options. The first thing you may think about is adding the exact parameters of the function you want to decorate. This will work, perfectly. However, you will be able to decorate only that function. Furthermore, if the function changes its parameters you will have to change the decorator as well. Not the way to go. A much better option is usingargs
and kwargs
. They represent positionally and named parameters. Not only do we need to call the original function with them, but we also want our wrapper to accept them. After all, the manipulation of the function must return a function that accepts those parameters! So here you are.
def measure(func):
def func_wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(time.time()-start)
return result
return func_wrapper
Decorators with Parameters
As we saw at the beginning of the article, we can pass some parameters to the decorator itself. There are several reasons you may need to do that, and a common example is wrappers. Imagine you want to enclose the output of your function between something, like HTML tags. You may want to have a decorator “tag” which applies a tag of your choice. This is the point where you realize you are in Inception, the 2010 movie. You can’t add the parameters to your decorator unless you wrap it in another function that accepts the parameter. Let me state this in another way: your decorator now returns another decorator, which returns an altered function. That’s what I call nesting!def tag(tag_name):
def tag_decorator(func):
def func_wrapper(*args, **kwargs):
return "<0>1".format(text, func(*args, **kwargs))
return func_wrapper
return tag_decorator
@tag('h1')
def func(something):
pass
Getting creative with Decorators
After completing this Python Decorators lesson, you will be fully prepared to deal with decorators. However, tackle them creatively. Decorators enable you to extend the functionality of your function without modifying the function itself. This may seem childish at first, but it is not. It enables you to keep each function focused on its intended purpose while adding more functionality. You are not need to invoke the original function many times in the decorator. You may refer to it twice, or even more than once – or you may not refer to it at all. For instance, you might construct a decorator that attempts a function until anything occurs in a while True loop. Even better, you could develop a decorator that automatically generates a thread or process consumer to asynchronously execute your function. Whatever your objective, only be imaginative and decorators will assist you!Summing it up (TL;DR)
We discussed the beauty of decorators in our Python Decorators Tutorial. You may now utilize them to make your code more readable and maintainable. For those of you who are pressed for time, here are the essential elements. Add a decorator by including the following syntax immediately above the function you wish to decorate:- @decorator: If this is the case, the decorator may take arguments. Simply use @decorator('1', 'blah').
- Multiple decorators may be applied per line. Python, on the other hand, will apply them in reverse order.
- To create a decorator, you must construct a function that takes just one parameter: a function. Create another function inside that one: this will be the revised function, and your decorator should return it. This internal
- function, referred to as the "wrapper," may invoke the original function and carry out additional actions.
Comments
Post a Comment