Decorator in Python

Yen
Towards Dev
Published in
3 min readMay 5, 2024

--

A good syntax sugar in python to improve the coding efficiency.

A good source for practicing Python decorator — ReaPython

Decorator

def decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper

def do_twice(func):
def wrapper_do_twice():
func()
func()
return wrapper_do_twice


@do_twice
def say_whee():
print("Whee!")


print(say_whee())

But if we change the decorator

def decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper

def do_twice(func):
def wrapper_do_twice():
func()
func()
return wrapper_do_twice

@decorator
def say_whee():
print("Whee!")

print(say_whee())

With Arguments

def greet(func):
def wrapper_do_twice(*args, **kwargs):
func(*args, **kwargs)
func(*args, **kwargs)
return wrapper_do_twice


@greet
def say_whee(name):
print(f"Hola {name}")

print(say_whee("Python"))

Return values from decorated functions

def do_twice(func):
def wrapper_do_twice(*args, **kwargs):
func(*args, **kwargs)
return func(*args, **kwargs)
return wrapper_do_twice


@do_twice
def return_greeting(name):
print("Creating greeting...")
return f"Hey {name}!"

print(return_greeting("Hobbit"))

This does the same.

def do_twice(func):
def wrapper_do_twice(*args, **kwargs):
func(*args, **kwargs)
return func(*args, **kwargs)
return wrapper_do_twice


@do_twice
def return_greeting(name):
print("Creating greeting...")
return f"Hey {name}!"

hob = return_greeting("Hobbit")
print(hob)

Timing Function

import functools
import time

def decorator(func):
@functools.wraps(func)
def wrapper_decorator(*args, **kwargs):
# Do something before
value = func(*args, **kwargs)
# Do something after
return value
return wrapper_decorator

def timer(func):
# Print the runtime of the decorated function
@functools.wraps(func)
def wrapper_timer(*args, **kwargs):
start_time = time.perf_counter()
value = func(*args, **kwargs)
end_time = time.perf_counter()
run_time = end_time - start_time
print(f"Finished {func.__name__}() in {run_time:.4f} secs")
return value
return wrapper_timer

@timer
def waste_some_time(num_times):
for _ in range(num_times):
sum([number**2 for number in range(10_000)])


waste_some_time(1)
# Finished waste_some_time() in 0.0010 secs

waste_some_time(999)
# Finished waste_some_time() in 0.3260 secs

Debug

import functools


def debug(func):
# """Print the function signature and return value"""
@functools.wraps(func)
def wrapper_debug(*args, **kwargs):
args_repr = [repr(a) for a in args]
kwargs_repr = [f"{k}={repr(v)}" for k, v in kwargs.items()]
signature = ", ".join(args_repr + kwargs_repr)
print(f"Calling {func.__name__}({signature})")
value = func(*args, **kwargs)
print(f"{func.__name__}() returned {repr(value)}")
return value

return wrapper_debug


@debug
def make_greeting(name, age=None):
if age is None:
return f"Howdy {name}!"
else:
return f"Whoa {name}! {age} already, you're growing up!"

print(make_greeting("Benjamin"))
print(make_greeting("Juan", age=114))
print(make_greeting(name="Maria", age=116))

--

--

Programming is a mindset. Cybersecurity is the process. Focus on Python & Rust currently. More about me | https://msha.ke/monles