The command-line debugger pdb is powerful, but remembering commands while you are trying to understand a bug adds cognitive load. VS Code's Python debugger gives you the same capabilities with a visual interface. You click to set breakpoints, hover over variables to see their values, and step through code with keyboard shortcuts you already know.
This article assumes you have VS Code and the Python extension installed. If you have not set those up yet, the article on setting up your Python workspace walks through the installation. The skills here build on debugging Python code with pdb; the concepts are the same, and the interface is the difference.
Setting a breakpoint
A breakpoint tells the debugger to pause execution at a specific line. In VS Code, click in the left margin next to the line number where you want execution to stop. A red dot appears. That is your breakpoint.
TIER_DISCOUNTS = {"gold": 0.8, "silver": 0.9}
def calculate_discount(price, customer_tier):
multiplier = TIER_DISCOUNTS.get(customer_tier, 1.0)
discounted = price * multiplier # Click in the margin next to this line
return round(discounted, 2)When the debugger reaches that line, it pauses before executing it. The line is highlighted in yellow. At this moment, multiplier has been assigned but discounted has not. You can inspect the value of multiplier before the multiplication happens.
You can set as many breakpoints as you need. Click an existing red dot to remove it. Right-click a breakpoint to add a condition, so it only triggers when a variable has a specific value. Right-click and choose Edit Breakpoint to set a hit count, so it triggers only on every Nth pass through a loop.
Starting the debugger
The simplest way to start debugging is to open the Python file you want to debug and press F5. VS Code runs the file with the debugger attached and pauses at the first breakpoint it encounters.
If you need to pass arguments or set environment variables, create a launch configuration. Open the Run and Debug view from the left sidebar (Ctrl+Shift+D), click "create a launch.json file", and select Python File. VS Code generates a configuration you can customize:
{
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"args": ["--verbose"],
"env": {"DEBUG": "true"}
}The program field is set to ${file}, which means it debugs whichever file you have open. Add arguments in the args list and environment variables in the env object. Save the file and press F5 to debug with this configuration.
Stepping through code
Once execution is paused at a breakpoint, a toolbar appears at the top of the editor with step controls. You can also use keyboard shortcuts.
Press F10 to Step Over. The debugger executes the current line and pauses at the next line in the same function. If the current line calls another function, that function runs completely and the debugger pauses after it returns. Use Step Over when you trust the function being called and only care about the result.
Press F11 to Step Into. If the current line calls a function, the debugger moves inside that function and pauses at its first line. Use Step Into when you suspect the bug is inside the called function and you need to follow the execution path.
Press Shift+F11 to Step Out. The debugger runs the rest of the current function and pauses at the line that called it. Use Step Out when you stepped into a function but realized the bug is not there and you want to return to the caller.
Press F5 to Continue. The debugger runs until the next breakpoint or until the program ends. Use Continue when you have seen enough of the current section.
Inspecting variables
While execution is paused, the Variables panel on the left shows every local and global variable in the current scope. Each variable is listed with its name, type, and current value. Complex objects like lists and dictionaries can be expanded to see their contents.
Hover over any variable in the editor to see its value in a popup. This is faster than scanning the Variables panel when you only need to check one or two values.
The Watch panel lets you track specific expressions across steps. Type an expression like len(results) or user.name into the Watch panel, and VS Code evaluates it at every step. This is useful when the value you care about is computed from multiple variables rather than stored in a single one.
The Debug Console at the bottom of the screen lets you type arbitrary Python expressions and see the results evaluated in the current stack frame. Type type(variable) to check its type, dir(object) to list its attributes, or call a helper function to test a hypothesis:
# Type this in the Debug Console while paused
>>> sum(data) / len(data)The expression runs in the context of the paused program, so it has access to all the variables currently in scope.
Debugging tests
You can debug a failing test the same way you debug any Python code. Open the test file, set a breakpoint inside the test method or in the code the test calls, and start the debugger.
VS Code also shows Debug icons above each test function when you have the Python extension's testing feature enabled. Click the Debug icon next to a specific test to run only that test under the debugger with your breakpoints active. This is faster than running the entire suite when you are diagnosing a single failure.
To debug tests from the command line, create a launch configuration that runs pytest or unittest:
{
"name": "Debug Tests",
"type": "debugpy",
"request": "launch",
"module": "pytest",
"args": ["tests/", "-x", "-k", "test_login"]
}The module field tells VS Code to run python -m pytest instead of a script file. The args field passes arguments to pytest: run tests in the tests directory, stop after the first failure, and only run tests whose names contain "test_login".
Debugging a running process
If a program is stuck or behaving strangely and you did not start it with the debugger, you can attach to it. In the Run and Debug view, select "Python: Attach using Process ID" from the dropdown and enter the process ID. VS Code attaches the debugger and pauses the program at its current point.
This is an advanced feature that requires the program to have been started with debugpy enabled or to have the debugpy package importable. For scripts you write, it is usually simpler to restart them under the debugger. For long-running services where restart is not practical, process attachment is the right tool.
From debugging to fixing
The debugger tells you what is wrong. Fixing it is still your job. After you identify the bug, stop the debugger (Shift+F5), edit the code, set a breakpoint one line before the fix to verify it, and run the debugger again. This feedback loop of "find the bug, fix it, verify the fix" is the core debugging workflow.
The next article covers reading and understanding Python tracebacks, which is what you use to start diagnosing a crash before you even open the debugger.
Rune AI
Key Insights
- Click in the left gutter next to a line number to set a breakpoint; a red dot appears, and execution pauses there.
- Press F5 to start debugging the current file; press Shift+F5 to stop the debugger.
- F10 steps over the current line; F11 steps into function calls; Shift+F11 steps out of the current function.
- The Variables panel shows all local and global variables with their current values, updated at each step.
- The Debug Console at the bottom lets you type Python expressions and see results in the current stack frame context.
Frequently Asked Questions
Do I need to install anything to debug Python in VS Code?
How do I debug a Python script that requires command-line arguments?
Can I debug unit tests in VS Code?
Conclusion
VS Code's Python debugger gives you the same control as pdb with a visual interface that removes the memorization burden. Click to set breakpoints, hover to see variable values, and step through code with keyboard shortcuts. Once you debug visually, you will not go back to print statements.
More in this topic
How to Test Python Code
Learn what testing means in Python, the core ideas behind automated tests, and the built-in and third-party tools that make testing practical.
Write Your First Python Unit Test
Write and run your first Python unit test step by step, using unittest to check a small function and understand the test output.
The Factory Pattern in Python
Learn how to use the factory pattern in Python to encapsulate object creation, making your code more flexible and easier to extend.