Decorators in Python
2024, Jan 07
What is Decorator
In Python, a decorator is a design pattern that allows you to modify the functionality of a function by wrapping it in another function.
The outer function is called the decorator, which takes the original function as an argument and returns a modified version of it.
Examples
def make_pretty(func):
# define the inner function
def inner():
# add some additional behavior to decorated function
print("I got decorated")
# call original function
func()
# return the inner function
return inner
# define ordinary function
def ordinary():
print("I am ordinary")
# decorate the ordinary function
decorated_func = make_pretty(ordinary)
# call the decorated function
decorated_func()
# output
# I got decorated
# I am ordinary
or simplify it using @symbol
def make_pretty(func):
def inner():
print("I got decorated")
func()
return inner
@make_pretty
def ordinary():
print("I am ordinary")
ordinary()
Decorating Functions with Parameters
def smart_divide(func):
def inner(a, b):
print("I am going to divide", a, "and", b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a, b)
return inner
@smart_divide
def divide(a, b):
print(a/b)
divide(2,5)
divide(2,0)
5 Useful Decorators
staticmethod
: This decorator is used to define a static method within a class. Static methods don’t depend on the instance state and can be called on the class itself. They are often used to group related utility functions that don’t need access to instance-specific data.
class SampleClass:
@staticmethod
def add(x, y):
return x + y
- classmethod:Similar to @ staticmethod, the @ classmethod decorator defines a method that is bound to the class and not the instance. Class methods take the class itself as the first argument and can be used for factory methods or alternative constructors.
class Date:
def __init__(self, day, month, year):
self.day = day
self.month = month
self.year = year
@classmethod
def from_string(cls, date_string):
day, month, year = map(int, date_string.split('-'))
return cls(day, month, year)
- property:The @ property decorator allows you to define a method as a getter for a class attribute. It’s a way to make attributes appear read-only, and it can be useful for encapsulating the internal state of an object.
class Circle:
def __init(self, radius):
self.radius = radius
@property
def diameter(self):
return self.radius * 2
- staticmethod and property combination:Combining @ staticmethod and @ property, you can create computed properties without the need for explicit getter methods. This reduces code by eliminating the need for separate getter methods.
class Circle:
def __init(self, radius):
self.radius = radius
@staticmethod
def from_diamether(diameter):
return Circle(diameter / 2)
@property
def diameter(self):
return self.radius * 2
- wraps:The @ wraps decorator, from the functools module, is used to preserve the metadata of the original function when creating wrapper functions. It’s often used when creating decorators to ensure that the decorated function maintains its name, docstring, and other attributes.
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper