What Are Decorators in Python? Understanding with Examples

Updated on September 5, 2024

Article Outline

Imagine Python decorators as the magical touch-up artists of your code, the secret sauce that transforms it from a mere script to a masterpiece. These nifty tools don’t just add flair; they seriously amp up the functionality. Imagine having a function that you can tweak without committing to a full-blown rewrite. That’s where decorators shine, allowing you to sprinkle enhancements without diving into a coding saga. They’re like the superheroes of code optimisation, making your scripts more readable, reusable, and easier to maintain. Debugging becomes a breeze and logging? Well, let’s just say decorators turn it into a walk in the code park. So, if you want your Python script to not just run but to dance elegantly through the digital realm, embrace decorators; they’re your code’s best friends, adding that extra touch of brilliance.

What are Decorators in Python?

Decorators in Python are a formidable and versatile feature, providing programmers with a potent tool to alter the behaviour of functions or classes. Essentially, decorators enable the encapsulation of one function within another, thereby extending or enhancing the functionality of the wrapped function without making permanent modifications. This ability to augment the behaviour of functions without directly altering their code promotes code reusability and maintainability. Before delving into the intricacies of decorators, it’s essential to grasp certain foundational concepts that pave the way for a more comprehensive understanding of this powerful Python feature. This knowledge serves as a crucial precursor, laying the groundwork for harnessing the full potential of decorators in Python programming.

*Image
Get curriculum highlights, career paths, industry insights and accelerate your technology journey.
Download brochure

Types of Python Decorators

Function Decorator

Python Function decorators serve as a valuable tool for extending the functionality of a specific function without directly modifying its code. These decorators operate as higher-order functions, meaning they take a function as input and return a new function that incorporates the desired modifications. By encapsulating the original function within a decorator, developers can dynamically enhance its behaviour without altering the source code. This approach facilitates code reuse, readability, and maintainability, as decorators allow for the addition of new features or modifications to existing functions without the need for extensive changes.

 

For example:

def simple_decorator(func): def wrapper(): print("Before function execution") func() print("After function execution") return wrapper @simple_decorator def greet(): print("Hello, world!") greet()

Class Decorator

Class decorators in Python provide a mechanism for enhancing a class’s behaviour without the need to modify its original source code. Much like function decorators, class decorators operate on classes instead of functions. They take a class as input and return a new class with modified or extended functionality. This powerful feature enables developers to dynamically alter class attributes, methods, or properties, fostering code flexibility and maintainability. By employing class decorators, programmers can seamlessly integrate additional functionality into existing classes, promoting a modular and extensible design approach in Python programming.

 

For example:

def class_decorator(cls): class NewClass(cls): def new_method(self): print("This is a new method added by the decorator") return NewClass @class_decorator class MyClass: def original_method(self): print("This is the original method") obj = MyClass() obj.original_method() obj.new_method()

When to use Python Decorators?

A decorator becomes essential when you wish to alter a function’s behaviour without directly modifying the function. Instances where this proves beneficial include scenarios like incorporating logging, testing performance, implementing caching, validating permissions, and more.

 

Furthermore, decorators are valuable when the same block of code needs to be executed across multiple functions. This helps in preventing the need for redundant code and promotes a more efficient and maintainable programming approach.

How to Create a Python Decorator?

Creating a Python decorator involves a straightforward step-by-step process. Once you grasp the fundamentals of decorators, the task becomes more accessible. Here’s a concise guide:

 

  • Define a Higher-Order Function:
    Begin by defining a higher-order function. This function should take another function as its input. In Python, functions are first-class citizens, allowing them to be passed as arguments to other functions.

 

  • Define a Nested Function (Wrapper):
    Within the higher-order function, create a nested function, often referred to as a wrapper. This inner function will serve as the modification point for the input function. It is within this wrapper that you can extend or modify the behaviour of the original function.

 

  • Modify or Extend Behavior:
    Inside the wrapper function, call the input function (the one passed as an argument) and perform any additional functionality you desire. This is the stage where you customise the behaviour of the original function. You have the flexibility to add new features or modify the existing ones.

 

  • Return the Wrapper Function:
    Crucially, ensure that the higher-order function returns the wrapper function. This step is pivotal as it replaces the original function with the wrapper, effectively incorporating the desired modifications.

 

By following these steps, you can effectively create a Python decorator. This process not only enhances the modularity and reusability of your code but also demonstrates the elegance of Python’s functional programming features. Decorators are powerful tools, and mastering their creation allows for more flexible and maintainable code in Python.

 

In the following example, we are crafting a basic decorator designed to gauge the execution time of a function.

import time def timer_decorator(func): def wrapper( * args, ** kwargs): start_time = time.time() result = func( * args, ** kwargs) end_time = time.time() print(f "{func.__name__} executed in {end_time - start_time:.5f} seconds") return result return wrapper @timer_decorator def slow_function(): time.sleep(2) print("Slow function executed") slow_function()

Within this illustration, the ‘@’ symbol serves as syntactic sugar, streamlining the application of the decorator to a function. Positioned above a function definition, this symbol signifies that the function is intended to be passed as an argument to the decorator.

 

Python Decorator Example

Decorators in Python offer a powerful way to modify or extend the behaviour of functions. Here are a few practical examples showcasing the versatility of decorators:

1. Timing Function Execution:

Measuring the execution time of a function is crucial for code optimisation and identifying performance bottlenecks. The following timing decorator accomplishes this without altering the original function’s code:

import time def timer_decorator(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"{func.__name__} executed in {end_time - start_time:.5f} seconds") return result return wrapper @timer_decorator def slow_function(): time.sleep(2) print("Slow function executed") slow_function()

2. Authorization and Authentication:

Decorators can enforce access control for functions or methods by verifying user authentication or authorisation. This maintains a clear separation between security concerns and the core functionality of the function:

def is_authenticated(user): return user == "authenticated_user" def authentication_decorator(func): def wrapper(*args, **kwargs): user = kwargs.get("user") if is_authenticated(user): return func(*args, **kwargs) else: raise PermissionError("User is not authenticated") return wrapper @authentication_decorator def restricted_function(user=None): print("Access granted to the restricted function") restricted_function(user="authenticated_user")

3. Logging and Error Handling:

Decorators can be employed for consistent logging of function calls or handling errors and exceptions across multiple functions without modifying their individual codes:

import logging def logging_decorator(func): def wrapper(*args, **kwargs): try: logging.info(f”Calling {func.__name__} with arguments {args} and keyword arguments {kwargs}”) result = func(*args, **kwargs) logging.info(f”Function {func.__name__} executed successfully”) return result except Exception as e: logging.error(f”An error occurred while executing {func.__name__}: {e}”) raise return wrapper @logging_decorator def example_function(a, b): return a / b example_function(10, 5) example_function(10, 0)

These examples demonstrate the practical use of decorators in Python, showcasing their utility in various scenarios such as performance measurement, access control, and error handling. Decorators contribute to cleaner, more modular, and maintainable code.

Long Story Short:

Python decorators stand as a testament to the language’s flexibility and power, offering a concise and elegant solution for modifying or extending the behaviour of functions. With types ranging from timing decorators for performance optimisation to those handling authentication and error logging, decorators significantly enhance code readability, reusability, and maintainability.

 

As industries increasingly adopt Python for various applications, the demand for proficient decorators and decorators-based solutions is on the rise. To stay ahead in the dynamic field of technology, it becomes imperative to continually enhance one’s skills.

 

If you are eager to delve deeper into Python, consider exploring an Accelerator Program in Artificial Intelligence and Machine Learning at Hero Vired. Equip yourself with cutting-edge knowledge and practical skills, ensuring you are well-positioned to navigate the evolving landscape of technology and make a significant impact in the world of AI and ML. Take the first step toward your transformative journey today!

FAQs
The @ symbol instructs Python to apply the decorator from the app. route() definition to the function index(). Essentially, a decorator functions as a method that alters the behaviour of another function.
Within Python, a decorator stands out as a distinct type of function, accepting another function as input and yielding a new function as output. These decorators prove instrumental in appending fresh functionality to pre-existing functions or adjusting their behaviour. On a related note, a generator, also a function, functions by providing a sequence of values one at a time. While generators share similarities with iterators, their efficiency surpasses that of iterators, especially when tasked with producing sequences of values that exceed memory storage capacities.
Within the Python programming language, the property() function is an inherent feature designed to generate and yield a property object. The function's syntax is defined as follows: property(fget=None, fset=None, fdel=None, doc=None). In this context, fget represents the function responsible for retrieving the attribute's value, while fset is the function designated for setting the attribute's value.
Decorators empower you to adjust the functionality of functions without making direct changes to their source code, offering a succinct and adaptable approach to augment and broaden their capabilities. This article will delve into the nuances of employing decorators in Python, elucidating their utilisation and presenting instances where their utility proves invaluable.
Employing Python decorators can significantly enhance your coding practices by improving code readability, reusability, and maintainability. These decorators enable you to modify functions without making permanent alterations, offering flexibility in code adjustments. Additionally, they streamline the processes of debugging and logging, making these tasks much more straightforward and efficient.

Updated on September 5, 2024

Link

Upskill with expert articles

View all
Free courses curated for you
Basics of Python
icon
5 Hrs. duration
icon
Beginner level
icon
9 Modules
icon
Certification included
avatar
1800+ Learners
View
Essentials of Excel
icon
4 Hrs. duration
icon
Beginner level
icon
12 Modules
icon
Certification included
avatar
2200+ Learners
View
Basics of SQL
icon
12 Hrs. duration
icon
Beginner level
icon
12 Modules
icon
Certification included
avatar
2600+ Learners
View
next_arrow
Hero Vired logo
Hero Vired is a leading LearnTech company dedicated to offering cutting-edge programs in collaboration with top-tier global institutions. As part of the esteemed Hero Group, we are committed to revolutionizing the skill development landscape in India. Our programs, delivered by industry experts, are designed to empower professionals and students with the skills they need to thrive in today’s competitive job market.
Blogs
Reviews
Events
In the News
About Us
Contact us
Learning Hub
18003093939     ·     hello@herovired.com     ·    Whatsapp
Privacy policy and Terms of use

|

Sitemap

© 2024 Hero Vired. All rights reserved