Advanced Decorators
Decorator stacking, class decorators, and decorator patterns.
Overview
Master advanced decorator techniques.
Decorator Stacking
def bold(func):
def wrapper(*args, **kwargs):
return f"<b>{func(*args, **kwargs)}</b>"
return wrapper
def italic(func):
def wrapper(*args, **kwargs):
return f"<i>{func(*args, **kwargs)}</i>"
return wrapper
@bold
@italic
def greet(name):
return f"Hello, {name}!"
print(greet("Alice")) # <b><i>Hello, Alice!</i></b>
Class Decorators
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class Config:
def __init__(self):
self.debug = True
c1 = Config()
c2 = Config()
print(c1 is c2) # True
# Dataclass-like decorator
def add_repr(cls):
def __repr__(self):
attrs = ', '.join(f'{k}={v!r}' for k, v in self.__dict__.items())
return f'{cls.__name__}({attrs})'
cls.__repr__ = __repr__
return cls
@add_repr
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p) # Point(x=1, y=2)
Decorator with Arguments
def validate_types(*types):
def decorator(func):
def wrapper(*args, **kwargs):
for arg, expected_type in zip(args, types):
if not isinstance(arg, expected_type):
raise TypeError(f"Expected {expected_type}, got {type(arg)}")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_types(int, int)
def add(a, b):
return a + b
print(add(1, 2)) # 3
# add(1, "2") # TypeError
Practice
Create a caching decorator that works with any function.