在VS Code中进行Python调试

Python 扩展支持通过 Python Debugger 扩展 对多种类型的 Python 应用程序进行调试。有关基本调试的简短教程,请参阅 教程 - 配置并运行调试器。另请参阅 Flask 教程。这两个教程都展示了设置断点和逐步执行代码等核心技能。

对于一般的调试功能,如检查变量、设置断点以及其他不依赖于语言的活动,请查看VS Code 调试

本文主要讨论Python特定的调试配置,包括特定应用程序类型和远程调试的必要步骤。

Python 调试器扩展

Python Debugger 扩展 会随着 Python 扩展 自动安装到 VS Code 中。它提供了使用 debugpy 的调试功能,适用于多种类型的 Python 应用程序,包括脚本、Web 应用、远程进程等。

要验证是否已安装,请打开扩展视图(⇧⌘X (Windows, Linux Ctrl+Shift+X))并搜索@installed python debugger。您应该在结果中看到列出的Python调试器扩展。

在VS Code的已安装扩展视图中显示的Python调试器扩展。

您可以参考扩展的README页面以获取有关支持的Python版本的信息。

初始化配置

配置驱动了VS Code在调试会话期间的行为。配置定义在launch.json文件中,该文件存储在工作区的.vscode文件夹中。

注意: 要更改调试配置,您的代码必须存储在一个文件夹中。

要初始化调试配置,首先在侧边栏中选择运行视图:

运行图标

如果您尚未定义任何配置,您将看到一个运行和调试按钮和一个用于创建配置(launch.json)文件的链接:

调试工具栏设置命令

要生成带有Python配置的launch.json文件,请按照以下步骤操作:

  1. 选择创建一个launch.json文件链接(如上图所示)或使用运行 > 打开配置菜单命令。

  2. 从调试器选项列表中选择Python 调试器

  3. 配置菜单将从命令面板中打开,允许您选择要用于我们的Python项目文件的调试配置类型。如果您想调试单个Python脚本,请在出现的选择调试配置菜单中选择Python文件

    Python调试器配置选项列表

    注意: 当没有配置存在时,通过调试面板、F5运行 > 开始调试 启动调试会话也会弹出调试配置菜单,但不会创建 launch.json 文件。

  4. Python 调试器扩展随后会创建并打开一个 launch.json 文件,该文件包含基于您之前选择内容的预定义配置,在本例中为 Python 文件。您可以修改配置(例如添加参数),还可以添加自定义配置。

    配置json

配置属性的详细信息将在本文后面的标准配置和选项部分进行介绍。其他配置也将在本文的调试特定应用类型部分进行描述。

额外配置

默认情况下,VS Code 仅显示由 Python 调试器扩展提供的最常见配置。您可以通过使用列表中显示的添加配置命令和launch.json编辑器来选择要包含在launch.json中的其他配置。当您使用该命令时,VS Code 会提示您所有可用配置的列表(请确保选择Python选项):

添加新的Python调试配置

选择使用进程ID附加会产生以下结果: 添加了一个配置

有关所有这些配置的详细信息,请参见调试特定应用程序类型

在调试过程中,状态栏显示当前配置和当前调试解释器。选择配置会弹出一个列表,您可以从列表中选择不同的配置:

调试状态栏

默认情况下,调试器使用为工作区选择的相同解释器,就像VS Code的Python扩展的其他功能一样。要专门为调试使用不同的解释器,请在launch.json中为适用的调试器配置设置python的值。或者,使用状态栏上的Python解释器指示器选择不同的解释器。

基本调试

如果您只对调试Python脚本感兴趣,最简单的方法是选择编辑器上运行按钮旁边的向下箭头,然后选择Python调试器:调试Python文件

编辑器右上角的调试按钮

如果你想使用Flask、Django或FastAPI调试一个Web应用程序,Python调试器扩展通过运行和调试视图下的显示所有自动调试配置选项,根据你的项目结构提供动态创建的调试配置。

在运行视图中显示所有自动调试配置选项

但如果你想调试其他类型的应用程序,你可以通过点击运行和调试按钮在运行视图中启动调试器。

运行调试器

当没有设置配置时,您将看到一个调试选项列表。在这里,您可以选择适当的选项来快速调试您的代码。

两种常见的选项是使用Python 文件配置来运行当前打开的 Python 文件,或者使用使用进程 ID 附加配置将调试器附加到已经运行的进程。

有关创建和使用调试配置的信息,请参阅初始化配置附加配置部分。一旦添加了配置,可以从下拉列表中选择并使用开始调试按钮(F5)启动。

运行和调试视图中的开始调试按钮

命令行调试

如果debugpy已安装在您的Python环境中,调试器也可以从命令行运行。

安装 debugpy

您可以在您的Python环境中使用python -m pip install --upgrade debugpy安装debugpy

提示:虽然使用虚拟环境不是必需的,但它是一个推荐的最佳实践。您可以通过打开命令面板(⇧⌘P (Windows, Linux Ctrl+Shift+P))并运行Python: 创建虚拟环境命令()在VS Code中创建虚拟环境。

命令行语法

调试器命令行语法如下:

python -m debugpy
    --listen | --connect
    [<host>:]<port>
    [--wait-for-client]
    [--configure-<name> <value>]...
    [--log-to <path>] [--log-to-stderr]
    <filename> | -m <module> | -c <code> | --pid <pid>
    [<arg>]...

示例

从命令行中,您可以使用指定的端口(5678)和脚本来启动调试器,使用以下语法。此示例假设脚本是长时间运行的,并且省略了--wait-for-client标志,这意味着脚本不会等待客户端连接。

python -m debugpy --listen 5678 ./myscript.py

然后,您将使用以下配置从VS Code Python调试器扩展进行附加。

{
  "name": "Python Debugger: Attach",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": 5678
  }
}

注意: 对于listen,指定主机是可选的,默认情况下使用127.0.0.1。

如果你想调试远程代码或在docker容器中运行的代码,在远程机器或容器上,你需要修改之前的CLI命令以指定主机。

python -m debugpy --listen 0.0.0.0:5678 ./myscript.py

相关的配置文件将如下所示。

{
  "name": "Attach",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "remote-machine-name", // replace this with remote machine name
    "port": 5678
  }
}

注意: 请注意,当您指定一个不同于127.0.0.1localhost的主机值时,您正在打开一个端口以允许来自任何机器的访问,这会带来安全风险。在进行远程调试时,您应确保采取适当的安全预防措施,例如使用SSH隧道。

命令行选项

Flag Options Description
--listen or --connect [<host>:]<port> Required. Specifies the host address and port for the debug adapter server to wait for incoming connections (--listen) or to connect with a client that is waiting for an incoming connection (--connect). This is the same address that is used in the VS Code debug configuration. By default, the host address is localhost (127.0.0.1).
--wait-for-client none Optional. Specifies that the code should not run until there's a connection from the debug server. This setting allows you to debug from the first line of your code.
--log-to <path> Optional. Specifies a path to an existing directory for saving logs.
--log-to-stderr none Optional. Enables debugpy to write logs directly to stderr.
--pid <pid> Optional. Specifies a process that is already running to inject the debug server into.
--configure-<name> <value> Optional. Sets a debug property that must be known to the debug server before the client connects. Such properties can be used directly in launch configuration, but must be set in this manner for attach configurations. For example, if you don't want the debug server to automatically inject itself into subprocesses created by the process you're attaching to, use --configure-subProcess false.

注意: [] 可以用来传递命令行参数给正在启动的应用程序。

通过网络连接进行调试

本地脚本调试

在某些情况下,您可能需要调试一个由另一个进程在本地调用的Python脚本。例如,您可能正在调试一个为特定处理任务运行不同Python脚本的Web服务器。在这种情况下,您需要在脚本启动后将VS Code调试器附加到该脚本:

  1. 运行 VS Code,打开包含脚本的文件夹或工作区,如果尚不存在,则为该工作区创建一个 launch.json

  2. 在脚本代码中,添加以下内容并保存文件:

    import debugpy
    
    # 5678 is the default attach port in the VS Code debug configurations. Unless a host and port are specified, host defaults to 127.0.0.1
    debugpy.listen(5678)
    print("Waiting for debugger attach")
    debugpy.wait_for_client()
    debugpy.breakpoint()
    print('break on this line')
    
  3. 使用终端:创建新终端打开终端,这将激活脚本选择的环境。

  4. 在终端中,安装 debugpy 包

  5. 在终端中,使用脚本启动Python,例如,python3 myscript.py。你应该会看到代码中包含的“等待调试器连接”消息,并且脚本会在debugpy.wait_for_client()调用处暂停。

  6. 切换到运行和调试视图(⇧⌘D (Windows, Linux Ctrl+Shift+D)),从调试器下拉列表中选择适当的配置,然后启动调试器。

  7. 调试器应该在debugpy.breakpoint()调用处停止,从这一点开始你可以正常使用调试器。你也可以选择使用UI在脚本代码中设置其他断点,而不是使用debugpy.breakpoint()

使用SSH进行远程脚本调试

远程调试允许您在VS Code中本地逐步执行程序,而该程序在远程计算机上运行。无需在远程计算机上安装VS Code。为了增加安全性,您可能希望或需要在调试时使用安全连接(如SSH)连接到远程计算机。

注意: 在Windows电脑上,你可能需要安装Windows 10 OpenSSH来使用ssh命令。

以下步骤概述了设置SSH隧道的一般过程。SSH隧道允许您在本地机器上工作,就像您直接在远程机器上工作一样,这种方式比开放端口供公共访问更安全。

在远程计算机上:

  1. 通过打开sshd_config配置文件(在Linux下位于/etc/ssh/,在Windows下位于%programfiles(x86)%/openssh/etc)并添加或修改以下设置来启用端口转发:

    AllowTcpForwarding yes
    

    注意: AllowTcpForwarding 的默认值是 yes,因此您可能不需要进行更改。

  2. 如果您需要添加或修改AllowTcpForwarding,请重新启动SSH服务器。在Linux/macOS上,运行sudo service ssh restart;在Windows上,运行services.msc,在服务列表中选择OpenSSH或sshd,然后选择重新启动

在本地计算机上:

  1. 通过运行ssh -2 -L sourceport:localhost:destinationport -i identityfile user@remoteaddress创建一个SSH隧道,使用选定的端口作为destinationport,并在user@remoteaddress中使用适当的用户名和远程计算机的IP地址。例如,要在IP地址1.2.3.4上使用端口5678,命令将是ssh -2 -L 5678:localhost:5678 -i identityfile user@1.2.3.4。您可以使用-i标志指定身份文件的路径。

  2. 验证您是否可以在SSH会话中看到提示。

  3. 在你的VS Code工作区中,为远程调试在launch.json文件中创建一个配置,将端口设置为与ssh命令中使用的端口匹配,并将主机设置为localhost。你在这里使用localhost是因为你已经设置了SSH隧道。

    {
      "name": "Python Debugger: Attach",
      "type": "debugpy",
      "request": "attach",
      "port": 5678,
      "host": "localhost",
      "pathMappings": [
        {
          "localRoot": "${workspaceFolder}", // Maps C:\Users\user1\project1
          "remoteRoot": "." // To current working directory ~/project1
        }
      ]
    }
    

开始调试

现在,已经设置了到远程计算机的SSH隧道,您可以开始调试了。

  1. 两台计算机:确保有相同的源代码可用。

  2. 两台计算机:安装 debugpy

  3. 远程计算机:有两种方法可以指定如何附加到远程进程。

    1. 在源代码中,添加以下行,将address替换为远程计算机的IP地址和端口号(此处仅以IP地址1.2.3.4为例)。

      import debugpy
      
      # Allow other computers to attach to debugpy at this IP address and port.
      debugpy.listen(('1.2.3.4', 5678))
      
      # Pause the program until a remote debugger is attached
      debugpy.wait_for_client()
      

      listen中使用的IP地址应该是远程计算机的私有IP地址。然后您可以正常启动程序,使其暂停直到调试器附加。

    2. 通过debugpy启动远程进程,例如:

      python3 -m debugpy --listen 1.2.3.4:5678 --wait-for-client -m myproject
      

      这将启动包myproject使用python3,远程计算机的私有IP地址为1.2.3.4并监听端口5678(你也可以通过指定文件路径而不是使用-m来启动远程Python进程,例如./hello.py)。

  4. 本地计算机:仅当您按照上述说明修改了远程计算机上的源代码,然后在源代码中添加远程计算机上添加的相同代码的注释副本。添加这些行可以确保两台计算机上的源代码逐行匹配。

    #import debugpy
    
    # Allow other computers to attach to debugpy at this IP address and port.
    #debugpy.listen(('1.2.3.4', 5678))
    
    # Pause the program until a remote debugger is attached
    #debugpy.wait_for_client()
    
  5. 本地计算机:切换到运行和调试视图(⇧⌘D(Windows,Linux Ctrl+Shift+D)在VS Code中,选择Python调试器:附加配置

  6. 本地计算机:在您想要开始调试的代码中设置一个断点。

  7. 本地计算机:使用修改后的Python Debugger: Attach配置和启动调试按钮启动VS Code调试器。VS Code应在您本地设置的断点处停止,允许您逐步执行代码、检查变量并执行所有其他调试操作。您在调试控制台中输入的表达式也会在远程计算机上运行。

    输出到stdout的文本,如print语句,会显示在两台计算机上。然而,其他输出,如来自matplotlib等包的图形绘图,仅显示在远程计算机上。

  8. 在远程调试期间,调试工具栏显示如下:

    远程调试期间的调试工具栏

    在此工具栏上,断开按钮(⇧F5 (Windows, Linux Shift+F5))停止调试器并允许远程程序运行至完成。重启按钮(⇧⌘F5 (Windows, Linux Ctrl+Shift+F5))在本地计算机上重启调试器,但不会重启远程程序。仅当您已经重启了远程程序并需要重新附加调试器时,才使用重启按钮。

设置配置选项

当你首次创建launch.json时,有两种标准配置可以在集成终端(在VS Code内部)或外部终端(在VS Code外部)中运行编辑器中的活动文件:

{
  "configurations": [
    {
      "name": "Python Debugger: Current File (Integrated Terminal)",
      "type": "debugpy",
      "request": "launch",
      "program": "${file}",
      "console": "integratedTerminal"
    },
    {
      "name": "Python Debugger: Current File (External Terminal)",
      "type": "debugpy",
      "request": "launch",
      "program": "${file}",
      "console": "externalTerminal"
    }
  ]
}

具体设置将在以下部分进行描述。您还可以添加其他设置,例如args,这些设置未包含在标准配置中。

提示: 在项目中创建一个运行特定启动文件的配置通常很有帮助。例如,如果您希望在启动调试器时始终使用参数 --port 1593 启动 startup.py,可以创建一个如下所示的配置项:

 {
     "name": "Python Debugger: startup.py",
     "type": "debugpy",
     "request": "launch",
     "program": "${workspaceFolder}/startup.py",
     "args" : ["--port", "1593"]
 },

name

提供出现在VS Code下拉列表中的调试配置的名称。

type

标识要使用的调试器类型;对于调试Python代码,请将此设置为debugpy

request

指定启动调试的模式:

  • launch: 在program中指定的文件上启动调试器
  • attach: 将调试器附加到已经运行的进程。有关示例,请参见远程调试

program

提供Python程序入口模块(启动文件)的完全限定路径。值${file},通常在默认配置中使用,使用编辑器中当前活动的文件。通过指定特定的启动文件,您可以始终确保无论打开哪些文件,都能以相同的入口点启动您的程序。例如:

"program": "/Users/Me/Projects/MyProject/src/event_handlers/__init__.py",

你也可以依赖于工作区根目录的相对路径。例如,如果根目录是 /Users/Me/Projects/MyProject,那么你可以使用以下示例:

"program": "${workspaceFolder}/src/event_handlers/__init__.py",

module

提供指定要调试模块名称的能力,类似于在命令行运行时使用的-m参数。更多信息,请参见Python.org

python

指向用于调试的Python解释器的完整路径。

如果未指定,此设置默认为为工作区选择的解释器,这相当于使用值 ${command:python.interpreterPath}。要使用不同的解释器,请在调试配置的 python 属性中指定其路径。

或者,您可以使用在每个平台上定义的自定义环境变量来包含要使用的Python解释器的完整路径,这样就不需要其他文件夹路径。

如果您需要向Python解释器传递参数,您可以使用pythonArgs属性。

pythonArgs

指定要传递给Python解释器的参数,使用语法 "pythonArgs": ["", "",...]

args

指定传递给Python程序的参数。由空格分隔的参数字符串的每个元素应包含在引号内,例如:

"args": ["--quiet", "--norepeat", "--port", "1593"],

如果你想为每次调试运行提供不同的参数,你可以将args设置为"${command:pickArgs}"。这将在每次启动调试会话时提示你输入参数。

注意: "${command:pickArgs}"["${command:pickArgs}"] 在解析方式上有所不同,特别是关于 [] 的使用。作为一个数组,所有参数都作为一个字符串传递,而没有括号时,每个参数都作为自己的字符串传递。

stopOnEntry

当设置为true时,调试器会在被调试程序的第一行中断。如果省略(默认)或设置为false,调试器将运行程序到第一个断点。

console

指定程序输出的显示方式,前提是未修改redirectOutput的默认设置。

Value Where output is displayed
"internalConsole" VS Code debug console. If redirectOutput is set to False, no output is displayed.
"integratedTerminal" (default) VS Code Integrated Terminal. If redirectOutput is set to True, output is also displayed in the debug console.
"externalTerminal" Separate console window. If redirectOutput is set to True, output is also displayed in the debug console.

purpose

有多种方法可以配置运行按钮,使用purpose选项。将该选项设置为debug-test,表示该配置应在VS Code中调试测试时使用。 然而,将该选项设置为debug-in-terminal,表示该配置应仅在访问编辑器右上角的运行Python文件按钮时使用(无论该按钮提供的是运行Python文件还是调试Python文件选项)。 注意purpose选项不能用于通过F5运行 > 启动调试启动调试器。

autoReload

允许在调试器执行遇到断点后对代码进行更改时自动重新加载调试器。要启用此功能,请设置{"enable": true},如下面的代码所示。

{
  "name": "Python Debugger: Current File",
  "type": "debugpy",
  "request": "launch",
  "program": "${file}",
  "console": "integratedTerminal",
  "autoReload": {
    "enable": true
  }
}

注意: 当调试器执行重新加载时,导入时运行的代码可能会再次执行。为了避免这种情况,尝试仅在模块中使用导入、常量和定义,将所有代码放入函数中。或者,你也可以使用 if __name__=="__main__" 检查。

subProcess

指定是否启用子进程调试。默认为false,设置为true以启用。更多信息,请参见多目标调试

cwd

指定调试器的当前工作目录,这是代码中使用的任何相对路径的基础文件夹。如果省略,默认为${workspaceFolder}(在VS Code中打开的文件夹)。

举个例子,假设 ${workspaceFolder} 包含一个 py_code 文件夹,里面有一个 app.py 文件,以及一个 data 文件夹,里面有一个 salaries.csv 文件。如果你在 py_code/app.py 上启动调试器,那么数据文件的相对路径会根据 cwd 的值而变化:

cwd Relative path to data file
Omitted or ${workspaceFolder} data/salaries.csv
${workspaceFolder}/py_code ../data/salaries.csv
${workspaceFolder}/data salaries.csv

redirectOutput

当设置为true(internalConsole的默认值)时,会导致调试器将程序的所有输出打印到VS Code调试输出窗口中。如果设置为false(integratedTerminal和externalTerminal的默认值),程序输出将不会显示在调试器输出窗口中。

当使用"console": "integratedTerminal""console": "externalTerminal"时,通常禁用此选项,因为不需要在调试控制台中重复输出。

justMyCode

当省略或设置为true(默认值)时,仅限制调试用户编写的代码。设置为false以同时启用标准库函数的调试。

django

当设置为true时,激活特定于Django网络框架的调试功能。

sudo

当设置为true并与"console": "externalTerminal"一起使用时,允许调试需要提升权限的应用程序。使用外部控制台是捕获密码的必要条件。

pyramid

当设置为true时,确保使用必要的pserve命令启动Pyramid应用程序。

env

为调试器进程设置除系统环境变量之外的可选环境变量,调试器始终会继承这些变量。这些变量的值必须以字符串形式输入。

envFile

可选路径,指向包含环境变量定义的文件。请参阅配置Python环境 - 环境变量定义文件

gevent

如果设置为true,则启用对gevent monkey-patched代码的调试。

jinja

当设置为true时,激活特定于Jinja模板框架的调试功能。

断点和日志点

Python 调试器扩展支持断点日志点用于调试代码。有关基本调试和使用断点的简短教程,请参阅教程 - 配置并运行调试器

条件断点

断点也可以根据表达式、命中次数或两者的组合来触发。Python 调试器扩展支持整数形式的命中次数,以及前面带有 ==、>、>=、<、<= 和 % 运算符的整数。例如,您可以通过设置命中次数为 >5 来设置一个断点,在五次出现后触发。有关更多信息,请参阅主 VS Code 调试文章中的条件断点

在代码中调用断点

在你的Python代码中,你可以在调试会话期间想要暂停调试器的任何位置调用debugpy.breakpoint()

断点验证

Python 调试器扩展会自动检测设置在非可执行行的断点,例如 pass 语句或多行语句的中间部分。在这种情况下,运行调试器会将断点移动到最近的有效行,以确保代码执行在该点停止。

调试特定应用类型

配置下拉菜单为一般应用程序类型提供了各种不同的选项:

Configuration Description
Attach See Remote debugging in the previous section.
Django Specifies "program": "${workspaceFolder}/manage.py", "args": ["runserver"]. Also adds "django": true to enable debugging of Django HTML templates.
Flask See Flask debugging below.
Gevent Adds "gevent": true to the standard integrated terminal configuration.
Pyramid Removes program, adds "args": ["${workspaceFolder}/development.ini"], adds "jinja": true for enabling template debugging, and adds "pyramid": true to ensure that the program is launched with the necessary pserve command.

远程调试和Google App Engine也需要特定的步骤。有关调试测试的详细信息,请参阅测试

要调试需要管理员权限的应用程序,请使用 "console": "externalTerminal""sudo": "True"

Flask 调试

{
    "name": "Python Debugger: Flask",
    "type": "debugpy",
    "request": "launch",
    "module": "flask",
    "env": {
        "FLASK_APP": "app.py"
    },
    "args": [
        "run",
        "--no-debugger"
    ],
    "jinja": true
},

如你所见,此配置指定了"env": {"FLASK_APP": "app.py"}"args": ["run", "--no-debugger"]。使用了"module": "flask"属性而不是program。(你可能会在env属性中看到"FLASK_APP": "${workspaceFolder}/app.py",在这种情况下,修改配置以仅引用文件名。否则,你可能会看到“无法导入模块C”的错误,其中C是驱动器号。)

"jinja": true 设置还启用了 Flask 默认的 Jinja 模板引擎的调试功能。

如果你想在开发模式下运行Flask的开发服务器,请使用以下配置:

{
    "name": "Python Debugger: Flask (development mode)",
    "type": "debugpy",
    "request": "launch",
    "module": "flask",
    "env": {
        "FLASK_APP": "app.py",
        "FLASK_ENV": "development"
    },
    "args": [
        "run"
    ],
    "jinja": true
},

故障排除

调试器可能无法工作的原因有很多。有时调试控制台会显示具体原因,但主要原因如下:

  • 确保在VS Code中安装并启用了Python调试器扩展,方法是打开扩展视图(⇧⌘X (Windows, Linux Ctrl+Shift+X))并搜索@installed python debugger

  • Python可执行文件的路径不正确:通过运行Python: 选择解释器命令并查看当前值来检查您选择的解释器的路径:

    调试时错误的Python解释器问题排查

  • 你在launch.json文件中将"type"设置为已弃用的值"python":请将"python"替换为"debugpy",以便与Python调试器扩展一起使用。

  • 监视窗口中有无效的表达式:请清除监视窗口中的所有表达式并重新启动调试器。

  • 如果你正在使用一个多线程应用程序,该应用程序使用本地线程API(例如Win32的CreateThread函数而不是Python的线程API),目前有必要在你想要调试的文件的顶部包含以下源代码:

    import debugpy
    debugpy.debug_this_thread()
    
  • 如果您正在使用Linux系统,当尝试将调试器应用于任何正在运行的进程时,您可能会收到“超时”错误消息。为了防止这种情况,您可以暂时运行以下命令:

    echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
    

下一步