Decorator in Python
Decorator in Python : Modify or Extend Functionality
Decorators are a powerful feature in Python that allows you to modify or extend the behavior of functions or methods. Decorators are functions that take another function as an argument and return a new function. They are used to add functionality to an existing function without modifying its code. Decorators are commonly used in Python to implement cross-cutting concerns such as logging, authentication, caching, and more.
Working of Decorators
Decorators work by wrapping the original function with another function that adds additional functionality before and after calling the original function. When you apply a decorator to a function, the decorator function is called with the original function as an argument. The decorator function returns a new function that calls the original function and adds additional functionality.
Decorators decorate the original function by adding additional functionality.
graph LR
A[Original Function] --> B[Decorator Function]
B --> C[Wrapper Function]
C --> A
C --> D[Additional Functionality]
D --> A
Working of Decorators
Syntax of Decorators
The syntax of a decorator in Python is as follows:
def decorator_function(func):
def wrapper_function(*args, **kwargs):
# Add functionality before calling the original function
result = func(*args, **kwargs)
# Add functionality after calling the original function
return result
return wrapper_functiondef decorator_function(func):
def wrapper_function(*args, **kwargs):
# Add functionality before calling the original function
result = func(*args, **kwargs)
# Add functionality after calling the original function
return result
return wrapper_functionHere,
decorator_functiondecorator_function: The decorator function that takes another function as an argument.wrapper_functionwrapper_function: The wrapper function that adds functionality before and after calling the original function.*args*argsand**kwargs**kwargs: Arguments and keyword arguments passed to the original function.- The decorator function returns the wrapper function.
- The wrapper function calls the original function and adds additional functionality.
Applying a Decorator
To apply a decorator to a function, you can use the @decorator_function@decorator_function syntax before the function definition. Here is an example of applying a decorator to a function:
def my_decorator(func):
def wrapper():
print("Before calling the function")
func()
print("After calling the function")
return wrapper
@my_decorator
def say_hello():
print("Hello, World!")
say_hello()def my_decorator(func):
def wrapper():
print("Before calling the function")
func()
print("After calling the function")
return wrapper
@my_decorator
def say_hello():
print("Hello, World!")
say_hello()In the above example, we have defined a decorator function my_decoratormy_decorator that adds functionality before and after calling the original function. We have applied the decorator to the say_hellosay_hello function using the @my_decorator@my_decorator syntax.
When we run the above code, it will output:
C:\Users\username\Desktop> python decorator_example.py
Before calling the function
Hello, World!
After calling the functionC:\Users\username\Desktop> python decorator_example.py
Before calling the function
Hello, World!
After calling the functionTypes of Decorators
There are different types of decorators in Python based on their usage and implementation:
- Function Decorators: Function decorators are the most common type of decorators in Python. They are used to modify the behavior of functions.
- Class Decorators: Class decorators are used to modify the behavior of classes. They take a class as an argument and return a new class.
- Method Decorators: Method decorators are used to modify the behavior of methods. They take a method as an argument and return a new method.
- Property Decorators: Property decorators are used to modify the behavior of properties. They take a property as an argument and return a new property.
- Static Method Decorators: Static method decorators are used to modify the behavior of static methods. They take a static method as an argument and return a new static method.
- Class Method Decorators: Class method decorators are used to modify the behavior of class methods. They take a class method as an argument and return a new class method.
- Decorator with Arguments: Decorators can also take arguments to customize their behavior. You can create decorators that accept arguments by defining a decorator function that returns another function.
- Chained Decorators: You can chain multiple decorators on a single function by applying multiple decorators using the
@@syntax.
Function Decorator Example
Here is an example of a function decorator that logs the function name before calling it:
def log_function(func):
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
result = func(*args, **kwargs)
return result
return wrapper
@log_function
def add(a, b):
return a + b
result = add(10, 20)
print("Result:", result)def log_function(func):
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
result = func(*args, **kwargs)
return result
return wrapper
@log_function
def add(a, b):
return a + b
result = add(10, 20)
print("Result:", result)In this example, we have defined a function decorator log_functionlog_function that logs the function name before calling it. We have applied the decorator to the addadd function, which adds two numbers.
When we run the above code, it will output:
C:\Users\username\Desktop> python function_decorator.py
Calling function: add
Result: 30C:\Users\username\Desktop> python function_decorator.py
Calling function: add
Result: 30Decorators are a powerful feature in Python that allows you to modify or extend the behavior of functions or methods. They are widely used in Python libraries and frameworks to implement common functionality such as logging, caching, authentication, and more.
Class Decorator Example
Here is an example of a class decorator that adds a displaydisplay method to a class:
def add_method(cls):
def display(self):
print("Displaying the object")
cls.display = display
return cls
@add_method
class MyClass:
pass
obj = MyClass()
obj.display()def add_method(cls):
def display(self):
print("Displaying the object")
cls.display = display
return cls
@add_method
class MyClass:
pass
obj = MyClass()
obj.display()In this example, we have defined a class decorator add_methodadd_method that adds a displaydisplay method to the class. We have applied the decorator to the MyClassMyClass class, which adds the displaydisplay method to the class.
When we run the above code, it will output:
C:\Users\username\Desktop> python class_decorator.py
Displaying the objectC:\Users\username\Desktop> python class_decorator.py
Displaying the objectMethod Decorator Example
Here is an example of a method decorator that logs the method name before calling it:
def log_method(func):
def wrapper(self, *args, **kwargs):
print(f"Calling method: {func.__name__}")
result = func(self, *args, **kwargs)
return result
return wrapper
class MyClass:
def __init__(self):
self.value = 100
@log_method
def display(self):
print(f"Value: {self.value}")
obj = MyClass()
obj.display()def log_method(func):
def wrapper(self, *args, **kwargs):
print(f"Calling method: {func.__name__}")
result = func(self, *args, **kwargs)
return result
return wrapper
class MyClass:
def __init__(self):
self.value = 100
@log_method
def display(self):
print(f"Value: {self.value}")
obj = MyClass()
obj.display()In this example, we have defined a method decorator log_methodlog_method that logs the method name before calling it. We have applied the decorator to the displaydisplay method of the MyClassMyClass class.
When we run the above code, it will output:
C:\Users\username\Desktop> python method_decorator.py
Calling method: display
Value: 100C:\Users\username\Desktop> python method_decorator.py
Calling method: display
Value: 100Property Decorator Example
Here is an example of a property decorator that logs the property name before accessing it:
def log_property(prop):
def getter(self):
print(f"Accessing property: {prop.__name__}")
return prop.fget(self)
return property(getter)
class MyClass:
def __init__(self):
self._value = 100
@log_property
def value(self):
return self._value
obj = MyClass()
print(obj.value)def log_property(prop):
def getter(self):
print(f"Accessing property: {prop.__name__}")
return prop.fget(self)
return property(getter)
class MyClass:
def __init__(self):
self._value = 100
@log_property
def value(self):
return self._value
obj = MyClass()
print(obj.value)In this example, we have defined a property decorator log_propertylog_property that logs the property name before accessing it. We have applied the decorator to the valuevalue property of the MyClassMyClass class.
When we run the above code, it will output:
C:\Users\username\Desktop> python property_decorator.py
Accessing property: value
100C:\Users\username\Desktop> python property_decorator.py
Accessing property: value
100Static Method Decorator Example
Here is an example of a static method decorator that logs the method name before calling it:
def log_static_method(func):
def wrapper(*args, **kwargs):
print(f"Calling static method: {func.__name__}")
result = func(*args, **kwargs)
return result
return staticmethod(wrapper)
class MyClass:
@log_static_method
def static_method():
print("Static method called")
MyClass.static_method()def log_static_method(func):
def wrapper(*args, **kwargs):
print(f"Calling static method: {func.__name__}")
result = func(*args, **kwargs)
return result
return staticmethod(wrapper)
class MyClass:
@log_static_method
def static_method():
print("Static method called")
MyClass.static_method()In this example, we have defined a static method decorator log_static_methodlog_static_method that logs the method name before calling it. We have applied the decorator to the static_methodstatic_method static method of the MyClassMyClass class.
When we run the above code, it will output:
C:\Users\username\Desktop> python staticmethod_decorator.py
Calling static method: static_method
Static method calledC:\Users\username\Desktop> python staticmethod_decorator.py
Calling static method: static_method
Static method calledClass Method Decorator Example
Here is an example of a class method decorator that logs the method name before calling it:
def log_class_method(func):
def wrapper(cls, *args, **kwargs):
print(f"Calling class method: {func.__name__}")
result = func(cls, *args, **kwargs)
return result
return classmethod(wrapper)
class MyClass:
@log_class_method
def class_method(cls):
print("Class method called")
MyClass.class_method()def log_class_method(func):
def wrapper(cls, *args, **kwargs):
print(f"Calling class method: {func.__name__}")
result = func(cls, *args, **kwargs)
return result
return classmethod(wrapper)
class MyClass:
@log_class_method
def class_method(cls):
print("Class method called")
MyClass.class_method()In this example, we have defined a class method decorator log_class_methodlog_class_method that logs the method name before calling it. We have applied the decorator to the class_methodclass_method class method of the MyClassMyClass class.
When we run the above code, it will output:
C:\Users\username\Desktop> python classmethod_decorator.py
Calling class method: class_method
Class method calledC:\Users\username\Desktop> python classmethod_decorator.py
Calling class method: class_method
Class method calledDecorator with Arguments Example
You can create decorators that accept arguments to customize their behavior. Here is an example of a decorator that logs the function name with a custom message:
def log_message(message):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"{message}: {func.__name__}")
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@log_message("Calling function")
def add(a, b):
return a + b
result = add(10, 20)
print("Result:", result)def log_message(message):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"{message}: {func.__name__}")
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@log_message("Calling function")
def add(a, b):
return a + b
result = add(10, 20)
print("Result:", result)In this example, we have defined a decorator log_messagelog_message that accepts a message as an argument. The decorator returns a decorator function that logs the function name with the custom message. We have applied the decorator to the addadd function with the message "Calling function""Calling function".
When we run the above code, it will output:
C:\Users\username\Desktop> python decorator_with_arguments.py
Calling function: add
Result: 30C:\Users\username\Desktop> python decorator_with_arguments.py
Calling function: add
Result: 30Chained Decorators Example
You can chain multiple decorators on a single function by applying multiple decorators using the @@ syntax. Here is an example of chaining two decorators on a function:
def log_function(func):
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
result = func(*args, **kwargs)
return result
return wrapper
def add_message(func):
def wrapper(*args, **kwargs):
print("Adding two numbers")
result = func(*args, **kwargs)
return result
return wrapper
@log_function
@add_message
def add(a, b):
return a + b
result = add(10, 20)
print("Result:", result)def log_function(func):
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
result = func(*args, **kwargs)
return result
return wrapper
def add_message(func):
def wrapper(*args, **kwargs):
print("Adding two numbers")
result = func(*args, **kwargs)
return result
return wrapper
@log_function
@add_message
def add(a, b):
return a + b
result = add(10, 20)
print("Result:", result)In this example, we have defined two decorators log_functionlog_function and add_messageadd_message. We have applied both decorators to the addadd function using the @@ syntax. The decorators are applied in the order they are listed, so the log_functionlog_function decorator is applied first, followed by the add_messageadd_message decorator.
When we run the above code, it will output:
C:\Users\username\Desktop> python chained_decorators.py
Calling function: wrapper
Adding two numbers
Result: 30C:\Users\username\Desktop> python chained_decorators.py
Calling function: wrapper
Adding two numbers
Result: 30Decorators are a powerful feature in Python that allows you to modify or extend the behavior of functions or methods. They are widely used in Python libraries and frameworks to implement common functionality such as logging, caching, authentication, and more.
Conclusion
In this tutorial, you learned about decorators in Python, how to create and use them, and the different types of decorators in Python. Decorators are a powerful feature that allows you to modify or extend the behavior of functions or methods without modifying their code. Decorators are commonly used in Python to implement cross-cutting concerns such as logging, authentication, caching, and more. You can create function decorators, class decorators, method decorators, property decorators, static method decorators, class method decorators, decorators with arguments, and chained decorators to add functionality to your code. For more information, you can refer to the Python Decorators documentation. For more tutorials, you can visit the Python Central Hub.
Was this page helpful?
Let us know how we did
