Unleash the Power of Python Decorators: A Beginner’s Guide

Jonathan Hazeley
Data Science with Jonathan Hazeley
3 min readJan 11, 2023
Realistic rendering of aquatic utopian cityscape — DALLE-E 2

Are you ready to spice up your Python code with some sizzling decorators?

Look no further because you’ve come to the right place!

First things first, let’s define what a decorator is. In the world of Python, a decorator is a particular type of function that takes in another function and extends the behavior of that function without actually modifying its code.

Confused? Don’t worry. We’ll break it down with a simple example. Let’s say we have a function that displays a message to the user. We’ll call it “greet.”

def greet(name):
print("Hello, " + name)

name = input("Enter your name: ")
greet(name)

Let’s add some extra flair to this function by displaying the current time and the greeting. Of course, we could modify the code of the greet function to do this, but that would involve changing the original code.

Enter decorators! We can create a decorator function called “greet_with_time” that takes in the greet function and adds the current time to the greeting.

import datetime

def greet_with_time(func):
def wrapper(name):
current_time = str(datetime.datetime.now().time())
func(name + "! The time is currently " + current_time)
return wrapper

Now we can use the “@” symbol to “decorate” the greet function with the greet_with_time decorator.

@greet_with_time
def greet(name):
print("Hello, " + name)

greet("Jonathan")

This will output: “Hello, Jonathan! The time is currently [current time].”

See how the decorator function extended the behavior of the greet function without actually modifying its code? But decorators can do much more than add the current time to a greeting. They can be used to add authentication to a function, log the arguments passed to a function, and even cache the results of a function, so it doesn’t have to be recalculated every time it’s called.

Now that you understand decorators, let’s take things up a notch with some advanced decorator techniques. One way to make decorators more powerful is by allowing them to accept arguments. This can be done by adding additional wrapper functions within the decorator.

import datetime

def greet_with_time(format_string):
def actual_decorator(func):
def wrapper(name):
current_time = datetime.datetime.now().time()
formatted_time = current_time.strftime(format_string)
func(name + "! The time is currently " + formatted_time)
return wrapper
return actual_decorator

@greet_with_time("%I:%M %p")
def greet(name):
print("Hello, " + name)

greet("Jonathan")

This will output the current time in the specified format (e.g., “03:15 PM”).

Another technique is to use multiple decorators on a single function. This is done by “stacking” the decorators on top of each other using the “@” symbol.

import datetime

def authenticate(func):
def wrapper(name):
if name == "John":
func(name)
else:
print("Access denied.")
return wrapper

def greet_with_time(format_string):
def actual_decorator(func):
def wrapper(name):
current_time = datetime.datetime.now().time()
formatted_time = current_time.strftime(format_string)
func(name + "! The time is currently " + formatted_time)
return wrapper
return actual_decorator

@authenticate
@greet_with_time("%I:%M %p")
def greet(name):
print("Hello, " + name)

greet("John")
greet("Jane")

This will output the current time in the specified format (e.g., “03:15 PM”).

This will output the greeting and current time for “John,” but will only display “Access denied.” for “Jane.” Now that you’re a decorator expert, go out there and start spicing up your Python code with these handy functions! Just don’t forget to use them wisely, because with great power comes great responsibility.

--

--

Jonathan Hazeley
Data Science with Jonathan Hazeley

An internet-educated Data Enthusiast teaching what I have learned throughout my journey.