They ask: "What is a decorator? Why do you need a decorator if you can consistently describe the logic in a function without using a decorator?"
A decorator is just a higher-order function applied at definition time instead of call time: @log above def f is sugar for f = log(f). The reason it exists isn't power — you could always wrap a call manually — it's that decoration keeps cross-cutting concerns (logging, timing, auth, retries, caching) out of the function body and applies them declaratively, once, at the definition site, instead of every caller remembering to wrap the call.
def log(fn):
def wrapper(*args, **kwargs):
print(f"calling {fn.__name__}")
return fn(*args, **kwargs)
return wrapper
@log
def add(a, b):
return a + b
Say it: "A decorator is a higher-order function invoked at def time — @log is f = log(f) — and I reach for it to keep cross-cutting concerns like logging or auth out of every call site."
Red flag: Describing a decorator as "special syntax." It's plain functions and closures; the @ is sugar, nothing magic happens at the interpreter level.