How to use Python decorators
Python decorators extend the behaviour of a function’s basic functionality without modifying its underlying source code.
What are function decorators and what are they used for?
Most Python tutorials don’t go into detail about Python decorators. This is because in order to understand how function decorators work, you need to have a deep understanding of what functions are and how they work. Python decorators have their own Python operator. This is distinguished by an ‘@’ sign followed by the name of the function decorator in the code.
Check out our articles on other advanced programming constructs in Python, such as:
The following code example shows the basic syntax of a Python decorator call. However, this code does not implement any functionality:
@decorator
def function():
pass
PythonIn this example, the code stored in ‘decorator’ is executed when the function named ‘function’ is called.
Function decorators are often used in object-oriented programming in Python. For example, the decorator Python property is used as an equivalent to the getter and setter methods in other programming languages.
Practical constructs like function decorators make Python an ideal programming language for web projects. With IONOS Deploy Now, you can easily build your project and keep track of everything using GitHub.
How to use Python decorators
How to extend core functionality using Python decorators
Python decorators are mostly used to extend a function’s core functionality. This is useful if you want to use the same function for multiple use cases and extend its functionality individually. The following code example illustrates how Python decorators can extend functionality:
def dec(function):
def foo(x):
print("Before the function call of " + function.__name__)
function(x)
print("After the function call of " + function.__name__)
return foo
@dec
def bar(y):
print("Function call of bar with the value " + str(y))
bar("Test")
PythonThis code example begins by creating a decorator called ‘dec’. As you can see, the function decorator is basically just a standalone wrapper function, which contains another function called ‘foo’. ‘Foo’ outputs that we are before the function call of the function passed to the decorator in the ‘function’ parameter. The function from the parameter is then executed. After this, there is another Python print call. This shows that we are after the function call of the function passed as a parameter.
The second part of the code includes a function definition of a function called ‘bar’. This has a passing parameter called ‘y’. The functionality of bar is simple. It prints the sentence ‘Function call of bar with the value y’ on the screen, whereby y is the value passed as a parameter. The bar function has been decorated, which can be seen in the ‘@dec’ line before the function definition.
But what does decorating a function mean? If we left out the Python decorator, which is the ‘@dec’ line of code, the ‘bar’ function call from the example would return the following output:
Function call of bar with the value test
The Python string ‘test’ that was passed for the parameter y is inserted into the print statement.
Now let’s look at the output from the same ‘bar’ call. However, this time we are going to decorate the ‘bar’ function with a Python decorator:
Before the function call of bar
Function call of bar with the value Test
After the function call of bar
This result may be somewhat surprising. After our function has been decorated, it doesn’t just print the output from its own print statement on the screen, rather the function decorator’s output has been encapsulated. This includes two print statements from the helper function ‘foo’. The core functionality of ‘bar’ has been extended by adding two more print outputs using the Python decorator.
Of course, this is just an example, and it does not follow any deeper programming logic. However, it does give a good overview of how Python decorators work. You can include any Python functionality in the decorator function.
How to query recurring conditions with Python decorators
You may want to put conditions on a certain function’s execution. You’re probably already familiar with python if-else statements. However, if these conditions need to be checked in different places, you can createclarity in the code by offloading the condition into a Python decorator.
It may be helpful to illustrate how this works with an example. Some mathematical operators are only defined for natural numbers. In these cases, it’s helpful to have a function decorator that checks whether the function’s argument is a natural number.
def natural_number(function):
def test(x):
if type(x) == int and x > 0:
return function(x)
else:
raise Exception("The argument is not a natural number")
@natural_number
def fak(n):
if n == 1:
return 1
else:
return n * fak(n-1)
print(fak(5))
print(fak(-1))
PythonThe code above shows the Python decorator named ‘natural_number’ being defined. This tests if the function’s argument is a natural number. The if condition checks the argument type. It also tests if the argument is a positive number greater than 0. If this is true, the function passed to the decorator as an argument is executed. Otherwise, an exception is thrown stating that the function’s argument is not a natural number.
You can see how the Python decorator works by examining the decorated function called ‘fac’. This is defined in the code and called first with the value ‘5’ and then with the value ‘-1’. The output looks like this:
120
Traceback (most recent call last):
File "<pyshell#17>", line 1, in <module>
fak(-1)
File "<pyshell#11>", line 6, in test
raise Exception("The argument is not a natural number")
Exception: The argument is not a natural number
You can see the number ‘120’. This corresponds to the factorial of 5. The factorial function works for natural numbers. However, calling the factorial function with a negative number will result in an error due to the Python decorator. The factorial function is not executed, because a negative number is not a natural number.