Python Debugging Cheat Sheet — Quick Reference

Complete Python debugging reference covering print debugging, pdb commands, IPython/ipdb, logging, exception handling, VS Code debugging, memory debugging, performance profiling, and common error quick fixes. With examples for every technique.

Print Debugging

Command / PatternDescriptionExample
print(x)Print value to stdoutprint(result)42
print(f"{x=}")Self-documenting f-string (3.8+)print(f"{name=}")name='Alice'
print(f"{expr=}")Show expression and its valueprint(f"{len(data)=}")len(data)=5
print(repr(x))Show unambiguous representationprint(repr("hi\n"))'hi\n'
print(type(x))Show the type of a variableprint(type([]))<class 'list'>
print(vars(obj))Show instance attributes as dictprint(vars(user)){'name': 'Bob'}
print(dir(obj))List all attributes and methodsdir(str) lists string methods
from pprint import pprint
pprint(data)
Pretty-print nested structurespprint({"a": [1,2,3]})
pprint(data, depth=2)Limit nesting depth in outputTruncates beyond depth 2
print(*lst, sep="\n")Print list items one per lineprint(*[1,2,3], sep="\n")

pdb Commands

Command / PatternDescriptionExample
breakpoint()Set breakpoint (Python 3.7+)Add in code, runs pdb at that line
import pdb; pdb.set_trace()Set breakpoint (older style)Equivalent to breakpoint()
python -m pdb script.pyRun script under pdb from startStops at first line
n (next)Execute next line, skip into functionsStep over function calls
s (step)Step into function callEnter the function body
c (continue)Continue until next breakpointResume normal execution
r (return)Continue until current function returnsFinish current function
p exprPrint expression valuep len(data)5
pp exprPretty-print expression valuepp locals()
l (list)Show 11 lines around current linel 1, 20 shows lines 1-20
ll (longlist)Show entire source of current functionSee full function body
w (where)Print stack traceShows call stack with current position
u (up)Move up one frame in the stackInspect caller's context
d (down)Move down one frame in the stackReturn to callee's context
b 42Set breakpoint at line 42b mymod.py:10 for other files
b func_nameBreak when function is calledb process_data
cl (clear)Clear all breakpointscl 1 clears breakpoint #1
q (quit)Quit the debuggerExits program immediately
h (help)List commands or get helph break shows break usage

IPython / ipdb

Command / PatternDescriptionExample
pip install ipdbInstall ipdb (pdb + IPython)Tab completion, syntax highlighting
import ipdb; ipdb.set_trace()Set ipdb breakpoint explicitlyEnhanced pdb interface
PYTHONBREAKPOINT=ipdb.set_traceUse ipdb for breakpoint()Set env var before running script
%debugPost-mortem debug in IPython/JupyterRun after an exception to inspect
%pdb onAuto-enter debugger on exceptionToggle automatic post-mortem mode
from IPython import embed
embed()
Drop into IPython shell mid-codeFull IPython REPL at that point
python -m pdb -c continue script.pyPost-mortem on unhandled exceptionRuns normally, debugs on crash
PYTHONBREAKPOINT=0Disable all breakpointsSkip breakpoint() calls in prod

Logging

Command / PatternDescriptionExample
import logging
logging.debug("msg")
Log at DEBUG level (lowest)For detailed diagnostic info
logging.info("msg")Log at INFO levelConfirm things work as expected
logging.warning("msg")Log at WARNING level (default)Something unexpected happened
logging.error("msg")Log at ERROR levelA serious problem occurred
logging.critical("msg")Log at CRITICAL level (highest)Program may not continue
logging.basicConfig(level=logging.DEBUG)Set minimum log levelShows DEBUG and above
logging.basicConfig(
  format="%(asctime)s %(levelname)s %(message)s"
)
Custom log format2025-01-15 10:30:00 INFO msg
logging.basicConfig(filename="app.log")Log to file instead of consoleWrites to app.log
logger = logging.getLogger(__name__)Create named loggerBest practice for modules
handler = logging.FileHandler("app.log")
logger.addHandler(handler)
Add file handler to loggerOutput to file + console
logging.exception("msg")Log ERROR with tracebackUse inside except blocks
logger.setLevel(logging.DEBUG)Set level on specific loggerOverride root logger level

Exception Handling

Command / PatternDescriptionExample
try:
  risky()
except Exception as e:
  print(e)
Catch and print exception messageBasic error handling pattern
except (TypeError, ValueError) as e:Catch multiple exception typesHandle related errors together
import traceback
traceback.print_exc()
Print full traceback in except blockShows file, line, and call stack
traceback.format_exc()Get traceback as stringFor logging or custom output
traceback.print_stack()Print current stack (no exception)See how you got to this point
import sys
sys.exc_info()
Get (type, value, traceback) tupleDetailed exception introspection
raise ValueError("msg") from eChain exceptions with causePreserves original traceback
try: ...
except: ...
else:
  on_success()
else runs if no exceptionSeparate success logic
try: ...
finally:
  cleanup()
finally always runsGuaranteed cleanup
import warnings
warnings.warn("deprecation")
Issue a warning (non-fatal)warnings.warn("old API", DeprecationWarning)

VS Code Debugging

Command / PatternDescriptionExample
F5Start / continue debuggingLaunches debug session
F9Toggle breakpoint on current lineClick gutter to set visually
F10Step over (next line)Skip into function calls
F11Step into functionEnter function body
Shift+F11Step out of functionReturn to caller
Shift+F5Stop debuggingTerminate debug session
Conditional breakpointRight-click gutter → Expressioni == 50 breaks when true
LogpointRight-click gutter → Log Message{x} prints x without stopping
Watch panelAdd expressions to monitorWatch len(data) live
Debug ConsoleEvaluate expressions at breakpointRun any Python expression
launch.json"args"Pass CLI arguments to script"args": ["--verbose", "input.txt"]
launch.json"env"Set environment variables"env": {"DEBUG": "1"}

Memory Debugging

Command / PatternDescriptionExample
import tracemalloc
tracemalloc.start()
Start tracking memory allocationsBuilt-in, no install needed
snap = tracemalloc.take_snapshot()
snap.statistics("lineno")
Show memory usage per lineFind top memory consumers
snap.statistics("traceback")Show memory by full tracebackTrace allocation origin
tracemalloc.get_traced_memory()Get (current, peak) memory usageReturns bytes tuple
import sys
sys.getsizeof(obj)
Size of single object in bytessys.getsizeof([1,2,3])88
import objgraph
objgraph.show_most_common_types()
List most common object typesFind object accumulation
objgraph.show_growth()Show new objects since last callDetect memory leaks over time
import gc
gc.collect()
Force garbage collectionReturns number of collected objects
gc.get_objects()List all tracked objectsInspect what GC is tracking
gc.set_debug(gc.DEBUG_LEAK)Enable GC debug outputPrints uncollectable objects

Performance Profiling

Command / PatternDescriptionExample
python -m cProfile script.pyProfile entire scriptShows time per function
python -m cProfile -s cumtime script.pySort by cumulative timeFind slowest code paths
import cProfile
cProfile.run("func()")
Profile a specific function callInline profiling
cProfile.run("func()", "output.prof")Save profile data to fileAnalyze with snakeviz or pstats
python -m timeit "expr"Time a small code snippetpython -m timeit "''.join(lst)"
from timeit import timeit
timeit("sum(range(100))", number=10000)
Time expression programmaticallyReturns total seconds
import time
t0 = time.perf_counter()
Manual timing with high precisionelapsed = time.perf_counter() - t0
pip install line_profiler
@profile
def func(): ...
Line-by-line time profilingkernprof -l -v script.py
pip install memory_profiler
@profile
def func(): ...
Line-by-line memory profilingpython -m memory_profiler script.py
pip install snakeviz
snakeviz output.prof
Visualize cProfile outputOpens interactive browser chart

Common Errors Quick Fix

ErrorCommon CauseFix
TypeError: unsupported operandMixing incompatible typesCheck types with type(x); cast if needed
TypeError: 'NoneType' not subscriptableFunction returned NoneEnsure function has return; check for None
TypeError: missing argumentWrong number of argumentsCheck function signature; use help(func)
ValueError: invalid literalBad string-to-number conversionint("abc") fails; validate input first
ValueError: too many values to unpackMismatched unpackingUse a, *rest = iterable for variable length
KeyError: 'key'Key not in dictionaryUse d.get("key", default) or "key" in d
AttributeError: no attribute 'x'Wrong type or misspelled attrCheck type(obj) and dir(obj)
ImportError / ModuleNotFoundErrorModule not installed or wrong envpip install module; check sys.path
IndentationErrorMixed tabs and spacesUse 4 spaces; configure editor to show whitespace
IndexError: list index out of rangeAccessing beyond list lengthCheck len(lst); use if i < len(lst)
RecursionError: maximum depthInfinite recursion, no base caseAdd base case; use sys.setrecursionlimit()
FileNotFoundErrorWrong path or missing fileUse Path.exists(); check os.getcwd()
UnicodeDecodeErrorWrong file encodingUse open(f, encoding="utf-8") or "latin-1"
NameError: name 'x' not definedVariable not assigned or typoCheck spelling; ensure variable is in scope

Frequently Asked Questions

What is the difference between pdb and ipdb in Python?

pdb is Python's built-in debugger included in the standard library. ipdb is a third-party package that wraps pdb with IPython features like syntax highlighting, tab completion, and better introspection. You can use breakpoint() to invoke pdb, or set PYTHONBREAKPOINT=ipdb.set_trace to use ipdb instead. Both support the same core commands (n, s, c, p, etc.), but ipdb provides a more user-friendly interactive experience.

How do I debug Python code in VS Code?

To debug Python in VS Code: 1) Install the Python extension, 2) Set breakpoints by clicking the gutter next to line numbers, 3) Press F5 or use Run > Start Debugging, 4) Use the debug toolbar to step over (F10), step into (F11), step out (Shift+F11), or continue (F5). You can also add a launch.json configuration for custom settings like command-line arguments, environment variables, or Django/Flask debugging.

How do I find memory leaks in Python?

Use tracemalloc (built-in) to track memory allocations: call tracemalloc.start() at the beginning, then tracemalloc.take_snapshot() and snapshot.statistics('lineno') to see which lines allocate the most memory. For object-level analysis, use objgraph.show_most_common_types() to find objects accumulating in memory. The gc module can also help: gc.get_objects() lists all tracked objects, and gc.collect() forces garbage collection to reveal uncollectable cycles.

What is the best way to profile Python code performance?

For function-level profiling, use cProfile: run python -m cProfile -s cumtime script.py to see time spent in each function. For line-by-line profiling, use line_profiler with the @profile decorator and run kernprof -l -v script.py. For quick timing, use timeit: python -m timeit 'expression'. For memory profiling, use memory_profiler with @profile to see memory usage per line.