For working professionals
For fresh graduates
More
13. Print In Python
15. Python for Loop
19. Break in Python
23. Float in Python
25. List in Python
27. Tuples in Python
29. Set in Python
53. Python Modules
57. Python Packages
59. Class in Python
61. Object in Python
73. JSON Python
79. Python Threading
84. Map in Python
85. Filter in Python
86. Eval in Python
96. Sort in Python
101. Datetime Python
103. 2D Array in Python
104. Abs in Python
105. Advantages of Python
107. Append in Python
110. Assert in Python
113. Bool in Python
115. chr in Python
118. Count in python
119. Counter in Python
121. Datetime in Python
122. Extend in Python
123. F-string in Python
125. Format in Python
131. Index in Python
132. Interface in Python
134. Isalpha in Python
136. Iterator in Python
137. Join in Python
140. Literals in Python
141. Matplotlib
144. Modulus in Python
147. OpenCV Python
149. ord in Python
150. Palindrome in Python
151. Pass in Python
156. Python Arrays
158. Python Frameworks
160. Python IDE
164. Python PIP
165. Python Seaborn
166. Python Slicing
168. Queue in Python
169. Replace in Python
173. Stack in Python
174. scikit-learn
175. Selenium with Python
176. Self in Python
177. Sleep in Python
179. Split in Python
184. Strip in Python
185. Subprocess in Python
186. Substring in Python
195. What is Pygame
197. XOR in Python
198. Yield in Python
199. Zip in Python
In the world of Python programming, decorators are a bit like the masala in your favorite Maggi - optional at first glance, but once you use them, everything tastes (and works) better. They bring flexibility, elegance, and reusability to your functions without the mess of rewriting code. If you're a student juggling multiple assignments or a budding coder crafting mini projects, Python decorators can be your secret weapon to clean and efficient code.
Now, if the word "decorator" makes you think of Diwali lighting or wedding halls, you're not entirely off track. A Python decorator does something similar—it adds a layer of functionality (like lights) to an existing structure (your function), making it more useful, and sometimes even beautiful.
Pursue Online Software Engineering & Development Courses from top universities!
At its core, a Python decorator is a function that takes another function as an argument, extends its behavior without modifying the original function, and returns a new function. Think of a decorator as a “wrapper” or a “cover” that adds functionality.
Imagine a marriage invitation card. You have a plain card (your function), but adding an elegant envelope with special decorations (your decorator) doesn’t change the card’s content but improves the overall presentation. Similarly, decorators wrap your function with extra behavior. Upgrade your capabilities with the help of these premium programs.
Basic Decorator Structure
def decorator_function(original_function):
def wrapper_function():
print("Before the function call.")
original_function()
print("After the function call.")
return wrapper_function
Using the decorator:
@decorator_function
def greet():
print("Hello!")
Here, @decorator_function is shorthand for:
greet = decorator_function(greet)
Before diving deeper into decorators, ensure you understand functions in Python, since decorators are built on top of them.
Python treats functions as first-class objects, which means you can assign functions to variables, pass them as arguments, and return them from other functions. This flexibility is the foundation of decorators.
Demonstration of Functions as Objects
def hello():
print("Hello, Atul!")
greet = hello
greet()
Output:
Hello, Atul!
This behavior lets us write a function (decorator_function) that accepts another function (hello) and returns a modified function (wrapper_function).
Still new to the concept of functions as first-class objects? You’ll understand it better once you’ve gone through Python Data Types.
We’ll create a simple Python decorator that prints custom messages before and after a function runs—like adding an announcement before and after a performance.
def simple_decorator(func):
def wrapper():
print("Before function execution.")
func()
print("After function execution.")
return wrapper
This decorator wraps another function and adds extra behavior before and after its execution. Let’s break it down step by step to understand how it works.
def simple_decorator(func):
def wrapper():
print("Before function execution.")
func()
print("After function execution.")
return wrapper
Need a refresher on Python indentation rules before building decorators? Check out our beginner-friendly guide on Indentation in Python to get your basics right.
Sometimes, you want your decorators to be more flexible—able to accept arguments themselves. This adds an extra layer of customization, allowing you to pass parameters that control the decorator’s behavior dynamically. For example, you might want a logging decorator that can specify the log level or a retry decorator that defines how many times to retry a failed function.
To achieve this, you wrap your decorator inside another function that takes the decorator arguments, which then returns the actual decorator function. This pattern is sometimes called a "decorator factory."
Using decorators with arguments is like ordering your chai with just the right amount of sugar and ginger—tailored to your taste instead of a one-size-fits-all.
Passing arguments to decorators makes them flexible and context-aware. Instead of a fixed message, your decorator can adapt based on input, like customizing a message for different users in an app.
def log_decorator(message):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[LOG] {message}")
return func(*args, **kwargs)
return wrapper
return decorator
@log_decorator("User logged in.")
def welcome_user():
print("Welcome!")
welcome_user()
Output:
[LOG] User logged in.
Welcome!
Explanation: Here, log_decorator returns a decorator customized with a message. The wrapper adds the log before calling the original function. This is like an auto-generated security stamp on a document—different stamps for different approvals.
Decorators can be stacked or chained to combine multiple behaviors on a single function. Think of it like layering clothes for a cold winter morning—you put on a shirt, then a sweater, then a jacket, each adding a layer of protection. Similarly, each decorator adds a layer of functionality around your original function.
Here’s a simple example:
def bold(func):
def wrapper():
return f"<b>{func()}</b>"
return wrapper
def italic(func):
def wrapper():
return f"<i>{func()}</i>"
return wrapper
@bold
@italic
def greet():
return "Hello"
print(greet())
Output:
<b><i>Hello</i></b>
When you apply multiple decorators stacked on top of a function, like this:
@bold
@italic
def greet():
return "Hello"
The decorators are applied from the bottom up:
Effectively, the function is wrapped twice: first with italics, then with bold. Think of it like wearing socks (italic) before shoes (bold).
Decorators are not just theoretical—they play a vital role in many real-world applications, especially in frameworks and tools used daily by developers in India and globally. Let’s explore practical examples that show how decorators improve code functionality and maintainability.
def login_required(func):
def wrapper(user):
if not user.get("authenticated"):
print("Please login first.")
return
return func(user)
return wrapper
@login_required
def dashboard(user):
print(f"Welcome {user['name']} to your dashboard!")
user1 = {"name": "Priya", "authenticated": True}
dashboard(user1)
Output:
Welcome Priya to your dashboard!
Explanation: In web applications, it’s common to restrict access to certain pages or features only to authenticated users. Instead of embedding authentication checks inside every function, the login_required decorator abstracts this responsibility. When the dashboard is called, the decorator first verifies if the user is authenticated. If not, it blocks access, prompting login.
This pattern saves tons of repetitive code and reduces errors. For Indian students building their own mini web apps or learning frameworks like Flask or Django, understanding this pattern is crucial. It’s like a security guard checking IDs before letting people enter a building—simple and effective.
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"Executed in {end - start:.2f} seconds")
return result
return wrapper
@timer
def slow_task():
time.sleep(2)
print("Task completed")
slow_task()
Output:
Task completed
Executed in 2.00 seconds
Explanation: Sometimes, you need to measure how long a function takes to execute, especially when optimizing code performance. The timer decorator adds this capability by recording time before and after the function runs, then printing the elapsed time.
This is particularly useful for students working on projects involving algorithms or data processing, where performance matters. It’s like timing your run in a cricket match to improve your sprint speed—knowing your current performance helps you get better.
Want to make your decorators even smarter? Combine them with Lambda functions in Python for concise logic in a single line.
Here are some of the common pitfalls:
Mastering Python decorators empowers you to write concise, maintainable, and powerful code. They unlock an advanced level of abstraction, allowing you to inject behavior, log activities, authenticate users, and optimize performance seamlessly. For any student or developer in India (or anywhere else!), decorators are a key skill to boost coding efficiency and elegance.
So, embrace decorators and transform your Python projects from good to great. Remember, decorators are like your favorite chai — a little extra makes everything better.
Functions that can be assigned to variables, passed as arguments, and returned from other functions.
It preserves the original function’s metadata such as name and docstring, improving debugging and introspection.
Examples include @staticmethod, @classmethod, and @property, used to modify methods in classes.
Class-based decorators are useful when you need to maintain state or more complex behavior, but function decorators are simpler and preferred for straightforward cases.
Here are some of the mistakes that beginners should avoid:
Yes, decorators can be applied to class methods. Use @staticmethod, @classmethod, or custom decorators. When decorating methods, ensure the wrapper accepts self or cls to maintain correct behavior.
A decorator is a function that returns a wrapper function. The wrapper wraps the original function to extend its behavior without modifying its code.
Yes, decorators can modify the return value or replace it entirely. This flexibility allows altering function outputs, such as formatting results or handling exceptions.
Decorators can obscure the original function’s metadata and stack traces. Using functools.wraps preserves metadata, making debugging and introspection easier.
Decorators are a Python-specific feature inspired by similar concepts in other languages like Java annotations, but Python’s syntax makes them especially elegant and versatile.
Yes, decorators can intercept and modify arguments before passing them to the original function, enabling validation, transformation, or defaulting values dynamically.
Decorators encapsulate reusable behavior (logging, timing, authentication) separately, allowing multiple functions to share common logic without duplication, enhancing maintainability.
functools.wraps copies the original function’s name, docstring, and other attributes to the wrapper, ensuring better documentation, debugging, and tooling compatibility.
Yes, decorators can wrap generator functions. Ensure the wrapper correctly handles the generator’s yield behavior to avoid breaking iteration.
Yes, Python includes built-in decorators like @staticmethod, @classmethod, and @property, which simplify common patterns in class design and enhance readability.
Take our Free Quiz on Python
Answer quick questions and assess your Python knowledge
Author|900 articles published
Previous
Next
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918068792934
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.