💻 Programming + 💻 Development intermediate

Decorator

A design pattern that allows behavior to be added to objects or functions dynamically without modifying their source code.

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:

  1. Taking a function/class as input
  2. Adding functionality around or within it
  3. 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_required for protected endpoints
  • Caching: @cache for expensive computations
  • Validation: @validate for input checking
  • Logging: @log for debugging
  • Timing: @timer for 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()))

// Example Usage

In FastAPI, the @app.get("/users") decorator transforms a regular function into an HTTP endpoint handler.