Python Debugging


Python Debugging Interview with follow-up questions

1. What is debugging in Python and why is it important?

Debugging is the process of finding and fixing bugs — places where a program behaves differently from what's intended. It matters because real code has logic errors, bad assumptions, and edge cases that don't show up until something breaks, and systematic debugging is how you locate the cause, not just the symptom.

The error categories you'll address:

  • Syntax errors — caught at parse time, before the program runs.
  • Runtime errors / exceptionsZeroDivisionError, KeyError, etc., surfacing during execution.
  • Logic errors — the program runs but produces wrong results; the hardest kind, since nothing crashes.

What a 2026 interviewer wants you to mention:

  • Read the traceback first — it pinpoints the failing line and the call chain; traceback and faulthandler help with crashes and hangs.
  • breakpoint() (3.7+) drops into the debugger to inspect state interactively — far better than scattering print().
  • Prefer logging over print for anything beyond a quick check: levels, structured context, and you can leave it in production.
  • Debugging vs. testing are complementary: tests (pytest) catch regressions and reproduce bugs; debugging diagnoses them. A failing test plus a debugger is the fast path. Reproduce reliably, isolate, fix, then add a test so it can't recur.
↑ Back to top

Follow-up 1

Can you name some Python debugging tools?

Yes, there are several Python debugging tools available. Some popular ones include:

  1. pdb: The Python debugger (pdb) is a built-in module that provides a command-line interface for debugging Python programs.

  2. PyCharm: PyCharm is a popular integrated development environment (IDE) for Python that offers powerful debugging features, including breakpoints, step-by-step execution, and variable inspection.

  3. VS Code: Visual Studio Code (VS Code) is a lightweight and versatile code editor that supports Python debugging through its built-in debugger or extensions like Python for Visual Studio Code.

  4. PyDev: PyDev is a Python IDE for Eclipse that provides debugging capabilities, including breakpoints, step-by-step execution, and variable inspection.

These tools help developers to identify and fix issues in their Python code efficiently.

Follow-up 2

What is the use of breakpoints in debugging?

Breakpoints are markers or points in the code where the debugger pauses the program's execution. They allow developers to stop the program at specific locations and inspect the program's state, variables, and data at that point. Breakpoints are useful for analyzing the program's behavior, identifying the cause of errors, and stepping through the code to understand how it executes. By setting breakpoints strategically, developers can narrow down the scope of debugging and focus on specific sections of code.

Follow-up 3

How does the step over function work in debugging?

The step over function in debugging allows developers to execute the current line of code and move to the next line without stepping into any function calls. It is useful when you want to skip the detailed execution of a function and focus on the high-level flow of the program. When the step over function is used, the debugger will execute the current line and move to the next line in the same scope, without diving into any function calls that may be present on that line. This helps in quickly navigating through the code and understanding the program's flow without getting into the implementation details of each function.

2. How do you use the Python debugger (PDB)?

pdb is Python's built-in interactive debugger. The modern entry point is the breakpoint() builtin (3.7+), which drops you into pdb at that line — no import needed:

def add(a: int, b: int) -> int:
    breakpoint()        # pauses here, opens the pdb prompt
    return a + b

print(add(2, 3))

You can also launch a whole script under the debugger with python -m pdb script.py, or do post-mortem debugging after a crash with pdb.pm().

Core commands at the (Pdb) prompt:

  • n (next) — run the next line, stepping over calls
  • s (step) — step into a function call
  • c (continue) — run until the next breakpoint or exit
  • l (list) / ll — show surrounding / full source
  • p expr / pp expr — print / pretty-print a value; whatis x shows its type
  • b file:line — set a breakpoint; w (where) shows the stack
  • u / d — move up/down the call stack
  • q (quit) — abort

What interviewers expect you to add:

  • breakpoint() respects PYTHONBREAKPOINT — set it to 0 to disable all breakpoints in production, or point it at an IDE/pdb++ hook.
  • For real apps, you'll often reach for IDE debuggers or debugpy (VS Code, remote attach) rather than the bare prompt, but knowing pdb is the universal fallback that's always available.
↑ Back to top

Follow-up 1

What is the role of the 'next' command in PDB?

The 'next' command in PDB is used to execute the next line of code and move the debugger to the next line. It allows you to step over function calls and continue the execution of the program until the next line is reached. If the next line contains a function call, the 'next' command will execute the entire function without stepping into it. This can be useful when you want to quickly move through the code and skip over function details.

Follow-up 2

How do you set breakpoints in PDB?

To set breakpoints in PDB, you can use the pdb.set_trace() function. This function can be placed at any point in your code where you want the debugger to pause and enter the PDB interactive mode. When the program reaches the pdb.set_trace() line, it will pause and allow you to interact with the debugger. You can then use the PDB commands to debug the code and inspect variables.

Follow-up 3

Can you explain the 'step' command in PDB?

The 'step' command in PDB is used to step into the next function call. When you encounter a function call in your code and you want to dive into the details of that function, you can use the 'step' command. It will execute the function call and pause at the first line of the called function, allowing you to debug the function's code. This command is useful when you want to trace the execution flow and understand how a specific function is working.

3. What is the difference between debugging and testing in Python?

Testing and debugging are distinct, complementary activities.

Testing verifies that code does what it's supposed to. You write checks — unit, integration, end-to-end — that assert expected outputs for given inputs, and run them automatically. In Python that's usually pytest (or the stdlib unittest). Testing is proactive: it catches regressions and proves behavior across many cases, ideally in CI before code ships.

def test_add():
    assert add(2, 3) == 5

Debugging is what you do after you know something is wrong — locating and fixing the cause. You inspect state with breakpoint()/pdb, read tracebacks, add logging, and step through execution to understand why the behavior diverges from intent. Debugging is reactive and investigative.

How interviewers like you to tie them together:

  • A failing test is the best start for debugging — it reproduces the bug deterministically so you can attack it under a debugger.
  • They feed each other: once you debug and fix a defect, write a regression test so it can never silently return.
  • Testing answers "does it work?" across cases; debugging answers "why doesn't it?" for a specific failure. Mature workflows lean on tests to catch bugs and the debugger to diagnose them.
↑ Back to top

Follow-up 1

Can you explain the concept of unit testing in Python?

Unit testing is a type of testing in which individual units or components of a software are tested. In Python, unit testing is commonly done using the unittest module, which provides a framework for writing and running tests.

A unit test is typically written as a separate function or method that tests a specific functionality or behavior of a code unit, such as a function, class, or module. The test function asserts the expected output or behavior of the code unit and compares it with the actual output or behavior.

Here's an example of a simple unit test in Python using the unittest module:

import unittest

# Code unit to be tested
def add_numbers(a, b):
    return a + b

# Unit test
class TestAddNumbers(unittest.TestCase):
    def test_add_numbers(self):
        result = add_numbers(2, 3)
        self.assertEqual(result, 5)

if __name__ == '__main__':
    unittest.main()

In this example, the test_add_numbers method tests the add_numbers function by asserting that the result of adding 2 and 3 is equal to 5. Running this test will verify if the add_numbers function is working correctly.

Follow-up 2

How does debugging help in the development process?

Debugging plays a crucial role in the development process in Python. Here are some ways in which debugging helps:

  1. Identifying and fixing errors: Debugging allows developers to identify and fix errors or bugs in the code. By stepping through the code, inspecting variables, and tracking the flow of execution, developers can pinpoint the cause of the error and make necessary changes to fix it.

  2. Understanding code behavior: Debugging helps in understanding how the code behaves during execution. By observing the values of variables and the flow of execution, developers can gain insights into the inner workings of the code and identify any unexpected behavior.

  3. Optimizing performance: Debugging can also be used to optimize the performance of the code. By profiling the code and analyzing its execution, developers can identify bottlenecks and areas for improvement, leading to faster and more efficient code.

In summary, debugging is an essential tool for developers to identify and fix errors, understand code behavior, and optimize performance during the development process.

Follow-up 3

What are some common Python errors that you often encounter during debugging?

During debugging in Python, developers often encounter various types of errors. Some common Python errors include:

  1. SyntaxError: This error occurs when the code violates the syntax rules of Python. It can be caused by missing or misplaced parentheses, brackets, or quotes, or incorrect indentation.

  2. NameError: This error occurs when a variable or name is used before it is defined or assigned a value.

  3. TypeError: This error occurs when an operation or function is applied to an object of an inappropriate type. For example, trying to concatenate a string and an integer.

  4. IndexError: This error occurs when trying to access an element in a sequence using an invalid index.

  5. KeyError: This error occurs when trying to access a dictionary using a key that does not exist.

These are just a few examples of common Python errors. Debugging helps in identifying and fixing these errors by providing insights into the cause and location of the error.

4. What is exception handling in Python and how does it relate to debugging?

Exception handling is Python's mechanism for catching and responding to runtime errors so the program can recover or fail cleanly instead of crashing. You wrap risky code in try/except, catching specific exception types and reacting appropriately.

try:
    config = load(path)
except FileNotFoundError:
    log.error("config missing at %s", path)
    config = DEFAULTS

How it relates to debugging — the point of the question:

  • Tracebacks are your first debugging signal. An unhandled exception prints exactly where and why it failed; you read it top-down to the failing frame. Don't suppress that signal too early.
  • Don't over-catch. A bare except: or broad except Exception that swallows errors hides bugs and makes debugging far harder — catch the narrowest type you can actually handle.
  • Log, don't silence. log.exception("...") inside an except records the full traceback so you can debug a failure that happened in production after the fact.
  • Chaining preserves contextraise NewError(...) from exc keeps the original cause visible in the traceback, which is invaluable when debugging layered failures.
  • pdb.pm() does post-mortem debugging, dropping you into the debugger at the point an exception was raised.

So exception handling and debugging are intertwined: good handling surfaces clear, well-contextualized errors; bad handling buries them and turns a five-minute fix into an hour of guessing.

↑ Back to top

Follow-up 1

Can you explain the use of try, except blocks in Python?

In Python, the try-except block is used for exception handling. The code that may raise an exception is placed inside the try block. If an exception occurs within the try block, it is caught by the except block. The except block specifies the type of exception to catch and the code to be executed when that exception occurs. By using try-except blocks, you can handle specific exceptions and prevent the program from crashing.

Follow-up 2

How do you handle multiple exceptions in Python?

In Python, you can handle multiple exceptions by using multiple except blocks. Each except block can handle a specific type of exception. The except blocks are evaluated in the order they appear, and the first matching except block is executed. If none of the except blocks match the raised exception, the exception is propagated to the outer try-except blocks or to the default exception handler. Here's an example:

try:
    # code that may raise exceptions
except ExceptionType1:
    # code to handle ExceptionType1
except ExceptionType2:
    # code to handle ExceptionType2
except:
    # code to handle any other exception

Follow-up 3

What is the role of the 'finally' block in exception handling?

The 'finally' block in exception handling is used to specify a block of code that will be executed regardless of whether an exception occurs or not. The code inside the 'finally' block will always be executed, even if an exception is raised and caught. This is useful for performing cleanup operations or releasing resources that need to be done regardless of the outcome of the try block. Here's an example:

try:
    # code that may raise exceptions
except ExceptionType:
    # code to handle ExceptionType
finally:
    # code that will always be executed

5. How do you debug a Python script that is running on a remote server?

To debug a script running on a remote server, you attach a debugger over the network or rely on rich logging — you rarely have an interactive terminal there.

Remote debugger (attach). The standard tool is debugpy (what VS Code uses). Start the script listening, then attach your local IDE:

import debugpy
debugpy.listen(("0.0.0.0", 5678))   # bind a port
debugpy.wait_for_client()            # pause until your IDE attaches
breakpoint()                         # or set breakpoints in the IDE

You then connect from your laptop (often through an SSH tunnel, ssh -L 5678:localhost:5678 user@host, so the port isn't exposed publicly). PyCharm offers an equivalent remote-debug server.

Logging-first approach. For production, attaching a live debugger is often impractical or unsafe, so you instrument with the logging module (structured logs, correlation IDs, appropriate levels) and ship logs to a central system (ELK, CloudWatch, Grafana/Loki) to reconstruct what happened.

What interviewers want you to add:

  • Don't pause a live production process with wait_for_client() — it blocks the service. Reserve interactive remote debugging for staging or a reproduced instance.
  • faulthandler dumps tracebacks on crashes/hangs; post-mortem (pdb.pm()) and core-dump analysis help when you can't reproduce locally.
  • The pragmatic order: reproduce locally if you can; if not, lean on logging and metrics; attach debugpy only when you must inspect live state.
↑ Back to top

Follow-up 1

What are the challenges in remote debugging?

Remote debugging can have some challenges. One challenge is the network latency, which can slow down the debugging process. Another challenge is the limited access to the remote server, as you may not have full control over the environment or the ability to install additional debugging tools. Additionally, debugging a script on a remote server requires a secure connection to protect sensitive data and prevent unauthorized access.

Follow-up 2

Can you explain how to use SSH for remote debugging?

Yes, you can use SSH (Secure Shell) for remote debugging. Here are the steps to follow:

  1. Ensure that the remote server has SSH enabled and you have the necessary credentials to connect to it.
  2. Open a terminal or command prompt on your local machine.
  3. Use the ssh command followed by the IP address or hostname of the remote server to establish an SSH connection.
  4. Once connected, navigate to the directory where the Python script is located.
  5. Start the Python script with the necessary debugging options, such as enabling breakpoints or setting the remote debugger to listen for connections.
  6. On your local machine, use a remote debugging tool, such as pdb or pydevd, to connect to the remote server and attach to the running script.
  7. You can now debug the Python script remotely as if it were running locally.

Follow-up 3

What tools or techniques do you use for remote debugging?

There are several tools and techniques available for remote debugging of Python scripts. Some popular options include:

  1. pdb: The Python debugger, which provides a command-line interface for debugging Python scripts.
  2. pydevd: A remote debugger specifically designed for Python, which allows you to connect to a running script and debug it remotely.
  3. logging: Using logging statements in your code and retrieving the logs from the remote server can help analyze the behavior of the script.
  4. IDEs with built-in remote debugging support, such as PyCharm or Visual Studio Code, which provide a more integrated debugging experience.

The choice of tool or technique depends on your specific requirements and the available resources on the remote server.

Live mock interview

Mock interview: Python Debugging

Intermediate ~5 min Your own free AI key

Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.