Question29
Remaining:

What are decorators and how do they work?

Sample Answer

Show Answer by Default

A decorator is a function that takes another function and returns a new one, extending its behavior without modifying the original code.

A simple decorator:

def log_call(func):
    def wrapper(*args, **kwargs):
        print(f"Calling function: {func.__name__}")
        result = func(*args, **kwargs)
        print(f"Result: {result}")
        return result
    return wrapper

@log_call
def add(a, b):
    return a + b

add(3, 5)
# Calling function: add
# Result: 8

How it works under the hood:

# Using @decorator syntax
@log_call
def add(a, b):
    return a + b

# Is equivalent to:
def add(a, b):
    return a + b
add = log_call(add)

Preserving metadata (@wraps):

from functools import wraps

def log_call(func):
    @wraps(func)  # Keeps the original name and docstring
    def wrapper(*args, **kwargs):
        print(f"Calling: {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@log_call
def add(a, b):
    """Adds two numbers."""
    return a + b

print(add.__name__)  # add (without @wraps it would be 'wrapper')
print(add.__doc__)   # Adds two numbers.

Practical examples of decorators:

  • Logging function calls
  • Measuring execution time
  • Caching results
  • Access control/authentication
  • Input validation