What is a Decorator?
A decorator is a structural design pattern that lets you attach new behaviors to objects or functions by wrapping them in special wrapper objects or functions. This is a form of metaprogramming where code modifies or extends other code at runtime.
How Decorators Work
Decorators work by:
- Taking a function/class as input
- Adding functionality around or within it
- Returning a modified version
The original function remains unchanged, but its behavior is extended.
Python Decorators
Python has first-class support for decorators using the @ syntax:
def log_calls(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"Finished {func.__name__}")
return result
return wrapper
@log_calls
def greet(name):
return f"Hello, {name}!"
# Equivalent to: greet = log_calls(greet)
Common Python Decorators
| Decorator | Purpose |
|---|---|
@property |
Define getter/setter methods |
@staticmethod |
Method without self |
@classmethod |
Method with cls instead of self |
@functools.lru_cache |
Memoization/caching |
@dataclass |
Auto-generate class boilerplate |
@abstractmethod |
Define abstract methods |
TypeScript/JavaScript Decorators
TypeScript supports decorators (stage 3 proposal in JS):
function log(target: any, key: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${key} with`, args);
return original.apply(this, args);
};
}
class Calculator {
@log
add(a: number, b: number): number {
return a + b;
}
}
Decorator vs Inheritance
| Aspect | Decorator | Inheritance |
|---|---|---|
| Flexibility | Add/remove at runtime | Fixed at compile time |
| Composition | Can stack multiple | Single inheritance limit |
| Coupling | Loose | Tight |
| Use case | Cross-cutting concerns | IS-A relationships |
Real-World Uses
- Web frameworks: Route handling (
@app.route("/")in Flask/FastAPI) - Authentication:
@login_requiredfor protected endpoints - Caching:
@cachefor expensive computations - Validation:
@validatefor input checking - Logging:
@logfor debugging - Timing:
@timerfor performance measurement
The Decorator Pattern (Gang of Four)
The classic OOP decorator pattern uses composition:
Component (interface)
├── ConcreteComponent
└── Decorator (wraps Component)
├── ConcreteDecoratorA
└── ConcreteDecoratorB
This allows stacking decorators: new BorderDecorator(new ScrollDecorator(new TextView()))