debug

A Complete Guide to Python Debugging Techniques: From Print to Professional Tools

Writing code rarely works perfectly the first time - in Python development, the probability of running it right the first time and being completely bug-free is probably less than 1%. Some bugs are very friendly, and the error message will directly tell you the line number and reason, such asIndexError: list index out of range. But more bugs are hidden very deep, and you have to sneak into the running status of the program to see the specific changes in variables and the logical direction of the call chain. Therefore, mastering a systematic debugging method is a required course for every Python developer.


Overview of debugging methods

We start with the most basic and versatile methods and gradually transition to production-level and professional tool-level solutions.

1. print() printing debugging method: entry-level but irreplaceable

Applicable scenarios: small snippets of code that have just been written, temporarily verifying the value of a variable, and quickly locating logical breakpoints (such as which iteration of a loop causes problems).

Code Example:

def calculate_div(s: str) -> float:
    n = int(s)
    print(f'[DEBUG] 当前计算的n值: {n}')  # f-string 一目了然
    return 10 / n

def main():
    calculate_div('0')

if __name__ == '__main__':
    main()

Execution results:

[DEBUG] 当前计算的n值: 0
Traceback (most recent call last):
  ...
ZeroDivisionError: integer division or modulo by zero

Summary of advantages and disadvantages:

  • Advantages: Zero learning cost, can be used in any environment (even just terminal + notepad).
  • Disadvantages: It will pollute the business code, leaving a lot of useless output, and it is easy to forget to delete it, affecting the readability and performance of the official version of the program.

2. assert assertion debugging method: lightweight constraint checking

Applicable scenarios: Add "implied premise" verification to the code - for example, what conditions must be met for the parameters passed in by the function, and the results of intermediate calculations must not be unexpected. If the assertion fails, the program will directly terminate and report an error instead of continuing to run with the error, causing problems that are more difficult to locate.

Code Example:

def calculate_div(s: str) -> float:
    n = int(s)
    # 断言:n 不能为 0,否则抛出带自定义信息的 AssertionError
    assert n != 0, f'calculate_div 的参数转换后不能为 0,传入的原始值是: {s}'
    return 10 / n

def main():
    calculate_div('0')

if __name__ == '__main__':
    main()

Execution results:

Traceback (most recent call last):
  ...
AssertionError: calculate_div 的参数转换后不能为 0,传入的原始值是: 0

Production Environment Notes:

Assertions can be turned off globally! use-O(capital letter O, not the number 0) parameter when running a Python script, allassertThe statements will be skipped, will not be executed and no error will be reported:

python -O your_script.py

Summary of advantages and disadvantages:

  • Advantages: Vs.print()It is more standardized, does not require manual deletion, and does not pollute the output of production code.
  • Disadvantages: Extensive use will still occupy lines of business code; after it is turned off, if you rely on assertion constraints, there will be problems, so try not to use it in the production environment.

3. Logging log debugging method: the first choice for production-level debugging

Applicable scenarios: A universal solution for the entire process from the development stage to testing to the production environment - it can not only view debugging information, but also record key data in testing and production, without polluting business logic, and can flexibly control output.

Basic configuration (output to terminal)

import logging

# 一次性配置(建议放在程序入口文件,只配置一次)
logging.basicConfig(
    level=logging.INFO,                            # 设置最低输出级别:INFO 及以上才会打印
    format='%(asctime)s - %(levelname)s - %(message)s'  # 自定义输出格式
)

def calculate_div(s: str) -> float:
    n = int(s)
    logging.info(f'当前计算的n值: {n}')   # INFO 级别记录常规信息
    return 10 / n

if __name__ == '__main__':
    s = input('请输入一个数字字符串: ')
    try:
        result = calculate_div(s)
        logging.info(f'计算结果: {result}')
    except ZeroDivisionError:
        logging.error('除数不能为 0!')         # ERROR 级别记录严重问题
    except ValueError:
        logging.warning('请输入有效的数字字符串!')  # WARNING 级别记录意外但不致命的情况

Advanced configuration (output to file)

If you want to save the log for subsequent analysis, you can addfilenameandfilemodeparameter:

import logging

logging.basicConfig(
    level=logging.DEBUG,                # 开发阶段可以设为 DEBUG,查看最详细的信息
    filename='app_debug.log',           # 日志文件名
    filemode='w',                       # w 是覆盖写,a 是追加写
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

Common log levels (from low to high)

LevelMeaningApplicable scenarios
DEBUGThe most detailed diagnostic informationLocating complex problems during the development stage
INFOInformation that confirms a program is running as expectedNodes that record key business processes
WARNINGUnexpected but not affecting program operationIrregular user input, temporary network fluctuations
ERRORProblems that cause a certain function to fail to be completedInterface call failure, file read and write errors
CRITICALA problem that caused the entire program to crashThe database connection was completely disconnected

Summary of advantages and disadvantages:

  • Advantages: The whole process is universal, durable, flexibly configurable (level, format, output location), and production environment-friendly.
  • Disadvantages: A little more configuration than the first two methods, but the configuration is well worth it.

4. pdb command line debugger: a hard-core tool without an IDE

Applicable scenarios: There is no IDE/editor on the server and can only be debugged through the terminal; or you want to experience the lowest level of Python debugging logic.

Method 1: Run the script directly in pdb mode

When running the script add-m pdbparameters, the program will pause at the first line of code, waiting for your command:

python -m pdb your_script.py

Method 2: Embed breakpoints in the code

More commonly used is to insert the line before the one where you suspect there is a problempdb.set_trace(), the program will automatically pause when it runs here:

import pdb

def calculate_div(s: str) -> float:
    n = int(s)
    pdb.set_trace()  # 插入断点
    return 10 / n

if __name__ == '__main__':
    calculate_div('0')

Commonly used pdb commands (just remember these few)

CommandComplete writingFunction
llistView 11 lines of code near the current location
nnextExecute the next line (without entering the function)
sstepExecute the next line (if it is a function, enter)
pprintPrint the value of a variable, such asp n
ccontinueContinue execution until next breakpoint or end
qquitExit debugging and terminate the program

Debug Example:

> /path/to/your_script.py(6)calculate_div()
-> return 10 / n
(Pdb) p n
0
(Pdb) c
Traceback (most recent call last):
  ...
ZeroDivisionError: division by zero

5. IDE integrated debugging: the most convenient daily solution

Applicable scenarios: Daily local development - graphical interface, breakpoint management, variable monitoring, call stack viewing, the combination of these functions is much more efficient than the command line.

  1. Visual Studio Code (VS Code)
  • Free, lightweight, rich plug-in ecosystem
  • Install the official "Python" extension to use it
  • Support conditional breakpoints, data breakpoints, and remote debugging
  • Download address: https://code.visualstudio.com/
  1. PyCharm
  • Professional Python IDE with the best support for large projects
  • There is a free community version and a paid professional version
  • The most comprehensive debugging function, as well as intelligent code prompts
  • Download address: https://www.jetbrains.com/pycharm/

Core functions of IDE debugging

  • Break point: Just click to the left of the code line number. The red dot indicates the break point.
  • Single-step debugging: and pdb'ss / nSimilar, but it is more convenient to click on the button
  • Variable Monitoring: On the right, you can see the variable values ​​​​of all current scopes, or you can add variables to be monitored by yourself.
  • Call stack view: You can see which layer of functions the current code is called by, and quickly trace the source of the problem

Debugging strategy suggestions

Choose the appropriate tool combination according to different development stages and environments:

  1. Local daily development: Give priority to graphical debugging using VS Code/PyCharm
  2. Temporary verification small logic: useprint()Quick trial and error
  3. Before code merge/test environment: useloggingRecord key node information and closeprint()and debuggingassert
  4. Production environment troubleshooting: only uselogging, set the level toWARNINGorERROR, to avoid generating a large amount of junk logs; if you need in-depth debugging, you can temporarily addpdb.set_trace(), but be sure to delete it after use
  5. Emergency troubleshooting of server without IDE: usepdbCommand line debugging

Ultimate Advice

Although various debugging tools have their own advantages, logging is the only solution that can be used from development to production without affecting the official version of the program. It is recommended that in your Python project:

  1. Unified configurationloggingformat and level
  2. Plan the log content reasonably (not too detailed, not too thick)
  3. Establish a simple log analysis mechanism (such as regularly cleaning logs, usinggrepFilter critical errors)

Master these debugging techniques, and you can quickly and efficiently solve most problems in Python programs!