Explore programming tutorials, exercises, quizzes, and solutions!
Python Decorators Exercises
1/17
In Python, decorators are a powerful and expressive tool that allows you to modify or extend the behavior of functions or methods without changing their source code. They are often used in logging, access control, timing functions, memoization, and frameworks like Flask or Django.
A decorator is typically a function that takes another function as an argument, adds some functionality to it, and returns a new function. You apply decorators using the @decorator_name syntax just above a function definition.
This code shows how decorators work in Python by wrapping additional logic around an existing function. Here’s what happens:
The function greet() simply returns the string "hello, world".
The uppercase_decorator wraps greet() with a wrapper() function that modifies its output by converting it to uppercase.
The @uppercase_decorator syntax is equivalent to:
greet = uppercase_decorator(greet)
So when greet() is called, you're actually calling the wrapper() function, which internally calls the original greet() and then transforms its output.
Decorators are often used to add cross-cutting concerns (like logging, authorization checks, etc.) without cluttering your core business logic.
What will be the output of the following code?
def decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@decorator
def my_function():
print("Inside function")
my_function()
Option 1 is correct because the @decorator syntax applies the decorator to my_function. The decorator wraps the function with the wrapper function, which prints before and after the function call.
Which of the following code snippets correctly applies a decorator to a function that takes parameters?
Option 4 correctly applies a decorator to a function that takes parameters. It uses *args and **kwargs in the wrapper function to pass the arguments to my_function.
Option 2 alters the arguments before passing them to the original function, which is a valid use case but doesn't directly match the question.
Option 3 does not handle parameters, making it incorrect. Option 1 unnecessarily includes extra parameters.
What does the @ symbol before a function mean in Python?
In Python, placing @decorator_name above a function is syntactic sugar for passing that function to the decorator.
For example, @decorator above def func() is equivalent to func = decorator(func).
It is not related to lambda functions, static methods, or function initialization.
Which built-in Python decorator is used to define a method that doesn’t access the class or instance?
@staticmethod is used to define methods that do not access the instance (self) or class (cls) within the method body.
Such methods behave like regular functions but belong to the class's namespace. @classmethod uses cls, @property is for creating managed attributes, and @abstractmethod is used in abstract base classes.
Which of the following decorators allows a method to access the class it belongs to rather than the instance?
@classmethod passes the class (cls) as the first argument to the method instead of the instance (self).
It allows you to access and modify class-level data. @staticmethod does not get class or instance, @property is for getter access, and @abstractmethod is for abstract base class enforcement.
The uppercase_decorator takes the result of greet() and converts it to uppercase using result.upper().
So, instead of returning "hello world", the decorator transforms it to "HELLO WORLD". The function still returns a string, not the function name or wrapper.
Which of the following correctly defines a decorator that logs the execution time of a function?
Option 1 is the correct implementation of a timing decorator. It uses time.time() to calculate the duration of the function execution and prints it.
Option 2 mistakenly returns the original function instead of the wrapper. Option 3 lacks the necessary logic to wrap a function. Option 4 returns a timestamp, not a decorator.
Which of the following decorators would allow a method to be accessed like an attribute?
@property allows a method to be accessed like an attribute—without parentheses—while still running code behind the scenes.
This is useful for computed attributes. Other decorators like @staticmethod, @classmethod, and @abstractmethod still require parentheses when invoked.
What is the main difference between a regular function and a decorated function in Python?
A decorator is a function that takes another function as input and returns a new function, usually a wrapper that extends or alters its behavior.
This allows behavior to be added without changing the original function's code. Decorated functions can return values and accept parameters like normal functions.
Which of the following decorators would correctly preserve the metadata (like __name__ and __doc__) of the original function?
Only option 2 uses functools.wraps, which is the correct way to preserve the original function’s metadata when writing decorators.
Without it, the decorated function may lose its name, docstring, and other important attributes, which can break tools like documentation generators and debuggers.
The @repeat(3) applies a decorator that repeats the say_hello function three times using a for loop.
So the function say_hello() is called three times, resulting in "Hello" being printed on three separate lines.
The loop ensures the repetition without modifying the core logic of the decorated function.
Which of the following code snippets demonstrates nesting multiple decorators correctly?
In Python, when multiple decorators are stacked, they’re applied from bottom to top.
So @decorator2 wraps func first, and then @decorator1 wraps the result. This is the standard and clean syntax for nesting decorators.
Option 2 is incorrect usage, Option 3 applies only one decorator, and Option 4 is a syntax error.
The decorator checks if the first argument args[0] is negative. If it is, it returns "Negative number".
For square(-3), the decorator returns "Negative number" because -3 is negative. For square(4), the decorator allows the function to execute normally, returning 16.
So, the output is as shown in option 1.
What is the effect of using the @lru_cache decorator in Python?
@lru_cache is a built-in decorator in Python that caches the results of function calls, storing them in a cache for quicker lookups when the same arguments are used again.
This is especially useful for functions with expensive computations or repeated calls with the same inputs.
Options 2, 3, and 1 are incorrect as they describe different behaviors.
What will be the output of the following code?
def decorator(func):
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
@decorator
def add(a, b):
return a + b
result = add(3, 5)
print("Result:", result)
The decorator @decorator wraps the add function and adds print statements before and after the function call.
The function add(3, 5) correctly returns 8, which is then printed as Result: 8.
So the output is:
The decorator checks if the keyword argument 'greet' is set to True. If so, it prints "Greeting enabled".
For the first call welcome("Alice", greet=True), the decorator prints the greeting message, then the function returns "Welcome, Alice!".
For the second call welcome("Bob"), the decorator doesn't print anything since greet is not passed, but it still executes the function and prints "Welcome, Bob!".
Practicing Python Decorators? Don’t forget to test yourself later in
our
Python Quiz.
About This Exercise: Python – Decorators
Welcome to the Python Decorators exercises — a carefully crafted set of challenges designed to help you master one of Python’s most powerful and elegant features. Decorators provide a clean and expressive way to modify or enhance the behavior of functions and methods without changing their actual code. Whether you’re a beginner or an experienced developer, these exercises will guide you through understanding and applying decorators effectively in your Python projects.
In this section, you will learn how decorators work by wrapping functions, enabling you to add functionality such as logging, access control, memoization, and timing without cluttering your main logic. You’ll start with simple decorator functions and progress to more advanced uses involving arguments, nesting, and class-based decorators. These exercises will help you grasp how decorators improve code reuse, readability, and maintainability.
Decorators are widely used in web frameworks, testing libraries, and APIs to extend functionality cleanly and consistently. Mastering decorators is essential for writing idiomatic Python code and building scalable applications. Through these exercises, you will practice writing your own decorators and applying built-in decorators like @staticmethod, @classmethod, and @property.
The exercises also emphasize best practices such as preserving function metadata using the functools.wraps decorator, designing clear and reusable decorator interfaces, and avoiding overly complex decorator chains that can reduce code clarity. These insights will help you write robust, professional-grade Python code.
We recommend complementing your practice with related topics such as higher-order functions, closures, and context managers to deepen your understanding of advanced Python features. Quizzes and multiple-choice questions on decorators are also available to reinforce your learning.
Start practicing the Python Decorators exercises today to enhance your ability to write flexible, reusable, and clean Python code. With consistent practice, you’ll gain confidence in using decorators to simplify complex programming tasks and improve your software design.