PyCodeItPython trace & interview prep
DashboardMastery MapSQL PracticeDailyInterviewCompaniesBlogLeaderboardCommunity
← Education Hub|python Guide

Python Decorators Deep Dive: Syntax, Stacking, and Interview Patterns

Understand what decorators really do under the hood, how stacking multiple decorators works, and how to trace through decorated function calls in interviews.

AA

Ameer Abdullah

Data Science Graduate · AI/ML & Data Science

June 28, 2026·10 min read

A decorator is syntactic sugar for passing a function as an argument to another function and replacing the original with the result. The @ syntax is a convenience - it does nothing you couldn't do with an explicit assignment. Understanding decorators requires understanding that functions in Python are first-class objects that can be passed, returned, and stored like any other value.

Desugaring the @ Syntax

Interactive Trace Block
# These two are exactly equivalent:

@my_decorator
def greet():
    print('Hello')

# Equivalent to:
def greet():
    print('Hello')
greet = my_decorator(greet)

When Python encounters @my_decorator above a def statement, it calls my_decorator(greet) and binds the result back to the name 'greet'. If my_decorator returns a different function (the wrapper), then greet now refers to that wrapper. Calling greet() calls the wrapper, not the original function body - unless the wrapper explicitly calls the original.

Writing a Decorator from Scratch

Interactive Trace Block
import functools

def log_calls(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f'Calling {func.__name__}')
        result = func(*args, **kwargs)
        print(f'{func.__name__} returned {result}')
        return result
    return wrapper

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

add(3, 4)

Output: 'Calling add', then 'add returned 7'. The wrapper uses *args and **kwargs to accept any arguments and forward them to the original function. functools.wraps(func) copies the original function's __name__, __doc__, and other metadata to the wrapper, so decorated functions look like the original when inspected.

Stacking Decorators: Order Matters

Interactive Trace Block
@decorator_A
@decorator_B
def func():
    pass

# Equivalent to:
func = decorator_A(decorator_B(func))

Decorators are applied bottom-up (inner to outer), but called top-down (outer to inner). decorator_B is applied first (wrapping the original func), then decorator_A wraps the result. When func() is called, decorator_A's wrapper runs first, which calls decorator_B's wrapper, which calls the original function. Many interview questions test this ordering with print statements in each decorator.

Parameterized Decorators

Interactive Trace Block
def repeat(n):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hi():
    print('Hi')

say_hi()  # prints Hi three times

A parameterized decorator is a function that returns a decorator (which itself returns a wrapper). There are three layers of nesting. @repeat(3) first calls repeat(3), which returns decorator. That decorator is then applied to say_hi: say_hi = decorator(say_hi). The resulting wrapper calls the original say_hi n times. Interview questions often ask you to trace through all three layers of nesting.

Quick Concept Quiz

If you stack @A and @B decorators (with @A on top), in what order are they applied and called?

Ready to test your execution tracing skills?

Hop directly into the Python trace map to start coding, grading queries, and logging XP metrics to your workspace profile.

Continue learning

python

The Complete Guide to Tracing Python Code (With Examples)

Read guide →

python

10 Python Output Questions for Interview Preparation

Read guide →

python

How to Dry Run Python Code: Step-by-Step Method

Read guide →

Guide Contents

  • Desugaring the @ Syntax
  • Writing a Decorator from Scratch
  • Stacking Decorators: Order Matters
  • Parameterized Decorators
PyCodeIt

Free interactive learning platform for Python code tracing, SQL queries, and technical interviews. Built for bootcamp grads, computer science students, and engineers.

Python Practice

  • Learning Center
  • For loop tracing
  • List tracing
  • Dictionary tracing
  • Decorators practice
  • Python Tracing Guide
  • Python Output Questions

SQL Practice

  • SQL Fundamentals
  • Relational JOINs
  • Window Functions
  • CTEs & Set Operators
  • SQL JOINs Guide
  • Window Functions Guide

Legal

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 PyCodeIt. Sandbox keys are processed strictly client-side.