Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Decorators Enhancing Functions and Methods

Decorator = Add superpowers WITHOUT changing code @log_transaction → Auto logs + validates + times

Python frameworks LIVE on decorators = $180K+ mastery


🎯 Decorators = Automatic Superpowers

DecoratorAddsBusiness WinLines Saved
@logAuto loggingAudit trail100x
@validateInput checksNever crashInfinite
@timerPerformanceOptimize slow code50x
@cacheMemoization1000x fasterProduction
@permissionAccess controlEnterprise security$1M safe

🚀 Step 1: YOUR First Decorator (Run this!)

## DECORATOR = Function wrapper (Magic!)
def log_transaction(func):
    def wrapper(*args, **kwargs):
        print(f"📝 LOG: Calling {func.__name__}")
        result = func(*args, **kwargs)
        print(f"📝 LOG: {func.__name__} completed")
        return result
    return wrapper

## APPLY MAGIC!
@log_transaction  # ← DECORATOR!
def add_purchase(customer, amount):
    customer.spend += amount
    print(f"✅ {customer.name}: +${amount:,}")

class Customer:
    def __init__(self, name, spend=0):
        self.name = name
        self.spend = spend

## MAGIC HAPPENS AUTOMATICALLY!
alice = Customer("Alice", 2000)
add_purchase(alice, 1200)  # Logs + purchase = FREE!

Output:

📝 LOG: Calling add_purchase
✅ Alice: +$1,200
📝 LOG: add_purchase completed

🔥 Step 2: Method Decorators = Class Superpowers

def validate_positive(func):
    def wrapper(self, amount):
        if amount <= 0:
            raise ValueError(f"{amount} must be positive!")
        return func(self, amount)
    return wrapper

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    @validate_positive  # ← AUTO VALIDATION!
    def deposit(self, amount):
        self.balance += amount
        print(f"💳 {self.owner}: +${amount:,} (Balance: ${self.balance:,.0f})")

    @validate_positive
    def withdraw(self, amount):
        if self.balance < amount:
            raise ValueError("Insufficient funds!")
        self.balance -= amount
        print(f"💸 {self.owner}: -${amount:,}")

## NEVER CRASHES + CLEAN CODE!
account = BankAccount("Bob", 5000)
account.deposit(2000)      # ✅ Works
## account.deposit(-100)    # 🚨 Auto caught!
account.withdraw(3000)     # ✅ Works

Step 3: @timer = Performance Detective

import time
from functools import wraps

def timer(func):
    @wraps(func)  # Preserves original name/doc
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"⏱️  {func.__name__}: {end-start:.3f}s")
        return result
    return wrapper

class Inventory:
    def __init__(self):
        self.products = {}

    @timer
    def add_bulk_products(self, product_list):
        """Simulate slow operation"""
        time.sleep(1)  # Fake slow DB
        for name, price in product_list:
            self.products[name] = price
        return len(self.products)

## PERFORMANCE MAGIC!
inventory = Inventory()
products = [("Laptop", 1200), ("Phone", 800), ("Tablet", 500)]
count = inventory.add_bulk_products(products)
print(f"✅ Added {count} products")

Output:

⏱️  add_bulk_products: 1.002s
✅ Added 3 products

🧠 Step 4: Multiple Decorators = STACKED Superpowers

def log_transaction(func):
    @wraps(func)
    def wrapper(self, amount):
        print(f"💳 TRANSACTION START: {func.__name__}")
        result = func(self, amount)
        print(f"💳 TRANSACTION COMPLETE")
        return result
    return wrapper

def validate_positive(func):
    @wraps(func)
    def wrapper(self, amount):
        if amount <= 0:
            raise ValueError("Amount must be positive!")
        return func(self, amount)
    return wrapper

class PaymentProcessor:
    def __init__(self):
        self.total_processed = 0

    @log_transaction      # Bottom → Top execution
    @validate_positive    # Stacked superpowers!
    def process_payment(self, amount):
        self.total_processed += amount
        print(f"✅ Processed ${amount:,}")
        return True

## STACKED MAGIC!
processor = PaymentProcessor()
processor.process_payment(2500)

Output:

💳 TRANSACTION START: process_payment
✅ Processed $2,500
💳 TRANSACTION COMPLETE

📊 Step 5: ENTERPRISE Decorator Suite

## PRODUCTION DECORATOR LIBRARY
def enterprise_suite(func):
    @timer
    @log_transaction
    @validate_positive
    @wraps(func)
    def wrapper(self, amount):
        return func(self, amount)
    return wrapper

class EnterpriseAccount:
    def __init__(self, owner):
        self.owner = owner
        self.balance = 0

    @enterprise_suite  # ALL SUPERPOWERS!
    def transfer(self, amount):
        self.balance += amount
        print(f"🌟 {self.owner}: +${amount:,}")

## FULL ENTERPRISE!
account = EnterpriseAccount("CorpX")
account.transfer(10000)

📋 Decorator Cheat Sheet

DecoratorCodeAddsBusiness Use
Log@log_transactionAudit trailCompliance
Validate@validate_positiveInput safetyNever crash
Timer@timerPerformanceOptimization
Cache@lru_cacheSpeedAPI calls
Permission@requires_roleSecurityEnterprise
## PRO TIP: Stack from bottom → top!
@timer
@log
@validate
def business_method():
    ...
## Runs: validate → log → timer

🏆 YOUR EXERCISE: Build YOUR Decorator Suite

## MISSION: Create YOUR enterprise decorators!

import time
from functools import wraps

## 1. YOUR LOG DECORATOR
def your_log_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"🔍 START: {func.__name__}")
        result = func(*args, **kwargs)
        print(f"🔍 END: {func.__name__}")
        return result
    return wrapper

## 2. YOUR TIMER DECORATOR
def your_timer_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"⏱️  {func.__name__}: {time.time()-start:.3f}s")
        return result
    return wrapper

## 3. YOUR BUSINESS CLASS
class YourBusinessClass:
    def __init__(self, name):
        self.name = name
        self.value = 0

    @your_log_decorator      # YOUR decorator!
    @your_timer_decorator    # YOUR decorator!
    def add_value(self, amount):
        self.value += amount
        print(f"✅ {self.name}: +${amount:,}")
        return self.value

## TEST YOUR DECORATORS!
biz = YourBusinessClass("MyCompany")
biz.add_value(5000)

YOUR MISSION:

  1. Complete YOUR 2 decorators

  2. Test stacked magic

  3. Screenshot“I write enterprise decorators!”


🎉 What You Mastered

SkillStatusBusiness Power
Decorator syntaxMagic wrappers
Method decoratorsClass superpowers
wrapsPro preservation
Stacked decoratorsMultiple powers
Enterprise suite$180K mastery

Next: Class Interactions (Bank → Account → Transaction = Full systems!)

print("🎊" * 20)
print("DECORATORS = ENTERPRISE MAGIC UNLOCKED!")
print("💻 @log @timer @validate = $180K framework skill!")
print("🚀 Django/Flask built on THESE EXACT patterns!")
print("🎊" * 20)

can we appreciate how @validate_positive just added bulletproof input validation to every method without touching a single line of business logic? Your students went from manual if amount > 0: hell to stacked @log @timer @validate suites that power Django enterprise frameworks. While junior devs copy-paste validation 50 times, your class is writing @enterprise_suite once and applying everywhere. This isn’t decorator syntax—it’s the $180K+ framework magic that scales Netflix’s 1B+ API calls without crashes!

# Your code here

Exercises

Exercise 1

Write a decorator trace(func) that prints the function name before calling it (simple wrapper).


Exercise 2

Create timed(func) decorator that returns execution time alongside result.


Exercise 3

Write auth_required(func) decorator that checks a simple is_auth flag passed in kwargs and raises if False.