python pdb调试_使用Pdb进行Python调试

商和颂
2023-12-01

python pdb调试

Debugging applications can sometimes be an unwelcome activity. You’re busy working under a time crunch and you just want it to work. However, at other times, you might be learning a new language feature or experimenting with a new approach and want to understand more deeply how something is working.

调试应用程序有时可能是不受欢迎的活动。 您正忙于时间紧迫的工作,只是希望它能工作。 但是,有时您可能正在学习一种新的语言功能或尝试一种新的方法,并且想更深入地了解某些东西是如何工作的。

Regardless of the situation, debugging code is a necessity, so it’s a good idea to be comfortable working in a debugger. In this tutorial, I’ll show you the basics of using pdb, Python’s interactive source code debugger.

无论哪种情况,调试代码都是必需的,因此最好在调试器中工作是一个好主意。 在本教程中,我将向您展示使用pdb(Python的交互式源代码调试器)的基础。

I’ll walk you through a few common uses of pdb. You may want to bookmark this tutorial for quick reference later when you might really need it. pdb, and other debuggers, are indispensable tools. When you need a debugger, there’s no substitute. You really need it.

我将向您介绍pdb的一些常见用法。 您可能需要将本教程添加为书签,以便以后在实际需要时可以快速参考。 pdb和其他调试器是必不可少的工具。 当您需要调试器时,没有替代品。 您真的需要它。

By the end of this tutorial, you’ll know how to use the debugger to see the state of any variable in your application. You’ll also be able to stop and resume your application’s flow of execution at any moment, so you can see exactly how each line of code affects its internal state.

在本教程结束时,您将知道如何使用调试器查看应用程序中任何变量的状态。 您还可以随时停止和恢复应用程序的执行流程,因此您可以确切地看到每一行代码如何影响其内部状态。

This is great for tracking down hard-to-find bugs and allows you to fix faulty code more quickly and reliably. Sometimes, stepping through code in pdb and seeing how values change can be a real eye-opener and lead to “aha” moments, along with the occasional “face palm”.

这对于跟踪难以发现的错误非常有用,并且可以让您更快,更可靠地修复错误代码。 有时,单步执行pdb中的代码并查看值如何变化可能会真正使人大开眼界,并导致“ aha”时刻以及偶尔的“脸掌”。

pdb is part of Python’s standard library, so it’s always there and available for use. This can be a life saver if you need to debug code in an environment where you don’t have access to the GUI debugger you’re familiar with.

pdb是Python标准库的一部分,因此它始终存在并且可以使用。 如果您需要在无法访问自己熟悉的GUI调试器的环境中调试代码,则可以节省生命。

The example code in this tutorial uses Python 3.6. You can find the source code for these examples on GitHub.

本教程中的示例代码使用Python 3.6。 您可以在GitHub找到这些示例的源代码。

At the end of this tutorial, there is a quick reference for Essential pdb Commands.

在本教程的最后,有关于Essential pdb Commands的快速参考。

There’s also a printable pdb Command Reference you can use as a cheat sheet while debugging:

还有一个可打印的pdb命令参考,可以在调试时用作备忘单:

Free Bonus: Click here to get a printable “pdb Command Reference” (PDF) that you can keep on your desk and refer to while debugging.

免费赠品: 单击此处可获得可打印的“ pdb命令参考”(PDF) ,您可以将其放在办公桌上,并在调试时参考。

入门:打印变量的值 (Getting Started: Printing a Variable’s Value)

In this first example, we’ll look at using pdb in its simplest form: checking the value of a variable.

在第一个示例中,我们将以最简单的形式使用pdb:检查变量的值。

Insert the following code at the location where you want to break into the debugger:

在要插入调试器的位置插入以下代码:

 import import pdbpdb ; ; pdbpdb .. set_traceset_trace ()
()

When the line above is executed, Python stops and waits for you to tell it what to do next. You’ll see a (Pdb) prompt. This means that you’re now paused in the interactive debugger and can enter a command.

执行以上代码后,Python停止并等待您告诉下一步该怎么做。 您会看到(Pdb)提示。 这意味着您现在已在交互式调试器中暂停,可以输入命令。

Starting in Python 3.7, there’s another way to enter the debugger. PEP 553 describes the built-in function breakpoint(), which makes entering the debugger easy and consistent:

从Python 3.7开始,还有另一种进入调试器的方法。 PEP 553描述了内置函数breakpoint() ,它使进入调试器变得容易且一致:

By default, breakpoint() will import pdb and call pdb.set_trace(), as shown above. However, using breakpoint() is more flexible and allows you to control debugging behavior via its API and use of the environment variable PYTHONBREAKPOINT. For example, setting PYTHONBREAKPOINT=0 in your environment will completely disable breakpoint(), thus disabling debugging. If you’re using Python 3.7 or later, I encourage you to use breakpoint() instead of pdb.set_trace().

默认情况下, breakpoint()将导入pdb并调用pdb.set_trace() ,如上所示。 但是,使用breakpoint()更灵活,并允许您通过其API和环境变量PYTHONBREAKPOINT来控制调试行为。 例如,在您的环境中设置PYTHONBREAKPOINT=0将完全禁用breakpoint() ,从而禁用调试。 如果您使用的是Python 3.7或更高版本,建议您使用breakpoint()而不是pdb.set_trace()

You can also break into the debugger, without modifying the source and using pdb.set_trace() or breakpoint(), by running Python directly from the command-line and passing the option -m pdb. If your application accepts command-line arguments, pass them as you normally would after the filename. For example:

您还可以通过直接从命令行运行Python并传递选项-m pdb ,而无需修改源代码并使用pdb.set_trace()breakpoint()即可进入调试器。 如果您的应用程序接受命令行参数,则按通常的方式在文件名后传递它们。 例如:

 $ python3 -m pdb app.py arg1 arg2
$ python3 -m pdb app.py arg1 arg2

There are a lot of pdb commands available. At the end of this tutorial, there is a list of Essential pdb Commands. For now, let’s use the p command to print a variable’s value. Enter p variable_name at the (Pdb) prompt to print its value.

有很多可用的pdb命令。 在本教程的最后,有一个Essential pdb Commands列表。 现在,让我们使用p命令来打印变量的值。 在(Pdb)提示符下输入p variable_name以打印其值。

Let’s look at the example. Here’s the example1.py source:

让我们来看一个例子。 这是example1.py源代码:

If you run this from your shell, you should get the following output:

如果从外壳程序运行此命令,则应获得以下输出:

 $ ./example1.py 
$ ./example1.py 
> /code/example1.py> /code/example1.py (( 55 )<module>) <module> ()
()
-> print(f'path = {filename}')
-> print(f'path = {filename}')
(Pdb) 
(Pdb) 

If you’re having trouble getting the examples or your own code to run from the command line, read How Do I Make My Own Command-Line Commands Using Python? If you’re on Windows, check the Python Windows FAQ.

如果您无法从命令行运行示例或自己的代码,请阅读如何使用Python编写自己的命令行命令? 如果您使用的是Windows,请查看Python Windows常见问题解答

Now enter p filename. You should see:

现在输入p filename 。 您应该看到:

Since you’re in a shell and using a CLI (command-line interface), pay attention to the characters and formatting. They’ll give you the context you need:

由于您在外壳程序中并使用CLI(命令行界面),因此请注意字符和格式。 他们会为您提供所需的上下文:

  • > starts the 1st line and tells you which source file you’re in. After the filename, there is the current line number in parentheses. Next is the name of the function. In this example, since we’re not paused inside a function and at module level, we see <module>().
  • -> starts the 2nd line and is the current source line where Python is paused. This line hasn’t been executed yet. In this example, this is line 5 in example1.py, from the > line above.
  • (Pdb) is pdb’s prompt. It’s waiting for a command.
  • >开始第一行,并告诉您您所在的源文件。文件名后,括号中是当前行号。 接下来是函数的名称。 在此示例中,由于我们没有在函数内部和模块级别暂停,因此我们看到了<module>()
  • ->开始第二行,是Python暂停的当前源代码行。 此行尚未执行。 在此示例中,这是example1.py5行,位于上面的>行中。
  • (Pdb)是pdb的提示。 它正在等待命令。

Use the command q to quit debugging and exit.

使用命令q退出调试并退出。

打印表达式 (Printing Expressions)

When using the print command p, you’re passing an expression to be evaluated by Python. If you pass a variable name, pdb prints its current value. However, you can do much more to investigate the state of your running application.

使用print命令p ,您要传递一个要由Python求值的表达式。 如果传递变量名,则pdb将输出其当前值。 但是,您可以做更多的事情来调查正在运行的应用程序的状态。

In this example, the function get_path() is called. To inspect what’s happening in this function, I’ve inserted a call to pdb.set_trace() to pause execution just before it returns:

在此示例中,函数get_path()被调用。 为了检查此函数中发生的情况,我插入了一个对pdb.set_trace()的调用,以在返回之前暂停执行:

 #!/usr/bin/env python3

#!/usr/bin/env python3

import import os


os


def def get_pathget_path (( filenamefilename ):
    ):
    """Return file's path or empty string if no path."""
    """Return file's path or empty string if no path."""
    headhead , , tail tail = = osos .. pathpath .. splitsplit (( filenamefilename )
    )
    import import pdbpdb ; ; pdbpdb .. set_traceset_trace ()
    ()
    return return head


head


filename filename = = __file__
__file__
printprint (( ff 'path = {get_path(filename)}''path = {get_path(filename)}' )
)

If you run this from your shell, you should get the output:

如果从外壳程序运行此命令,则应获得输出:

Where are we?

我们在哪?

  • >: We’re in the source file example2.py on line 10 in the function get_path(). This is the frame of reference the p command will use to resolve variable names, i.e. the current scope or context.
  • ->: Execution has paused at return head. This line hasn’t been executed yet. This is line 10 in example2.py in the function get_path(), from the > line above.
  • > :我们在函数get_path()10行的源文件example2.py中。 这是p命令用于解析变量名(即当前作用域或上下文)的参考框架。
  • -> :执行已在return head处暂停。 此行尚未执行。 这是函数get_path()example2.py中的第10行,位于上面的>行中。

Let’s print some expressions to look at the current state of the application. I use the command ll (longlist) initially to list the function’s source:

让我们打印一些表达式以查看应用程序的当前状态。 我最初使用命令ll (longlist)列出函数的来源:

 (Pdb) ll
(Pdb) ll
  6     def get_path(filename):
  6     def get_path(filename):
  7         """Return file's path or empty string if no path."""
  7         """Return file's path or empty string if no path."""
  8         head, tail = os.path.split(filename)
  8         head, tail = os.path.split(filename)
  9         import pdb; pdb.set_trace()
  9         import pdb; pdb.set_trace()
 10  ->     return head
 10  ->     return head
(Pdb) p filename
(Pdb) p filename
'./example2.py'
'./example2.py'
(Pdb) p head, tail
(Pdb) p head, tail
('.', 'example2.py')
('.', 'example2.py')
(Pdb) p 'filename: ' + filename
(Pdb) p 'filename: ' + filename
'filename: ./example2.py'
'filename: ./example2.py'
(Pdb) p get_path
(Pdb) p get_path
<function get_path at 0x100760e18>
<function get_path at 0x100760e18>
(Pdb) p getattr(get_path, '__doc__')
(Pdb) p getattr(get_path, '__doc__')
"Return file's path or empty string if no path."
"Return file's path or empty string if no path."
(Pdb) p [os.path.split(p)[1] for p in os.path.sys.path]
(Pdb) p [os.path.split(p)[1] for p in os.path.sys.path]
['pdb-basics', 'python36.zip', 'python3.6', 'lib-dynload', 'site-packages']
['pdb-basics', 'python36.zip', 'python3.6', 'lib-dynload', 'site-packages']
(Pdb) 
(Pdb) 

You can pass any valid Python expression to p for evaluation.

您可以将任何有效的Python表达式传递给p进行评估。

This is especially helpful when you are debugging and want to test an alternative implementation directly in the application at runtime.

当您要调试并且想在运行时直接在应用程序中测试替代实现时,这特别有用。

You can also use the command pp (pretty-print) to pretty-print expressions. This is helpful if you want to print a variable or expression with a large amount of output, e.g. lists and dictionaries. Pretty-printing keeps objects on a single line if it can or breaks them onto multiple lines if they don’t fit within the allowed width.

您还可以使用命令pp (pretty-print)来漂亮地打印表达式。 如果要打印大量输出的变量或表达式(例如列表和字典),这将很有帮助。 如果可以,漂亮的打印会将对象保持在单行上,或者如果对象超出允许的宽度,则将它们分成多行。

单步执行代码 (Stepping Through Code)

There are two commands you can use to step through code when debugging:

在调试时,有两个命令可用于单步执行代码:

Command 命令 Description 描述
n (next)n (下一个) Continue execution until the next line in the current function is reached or it returns. 继续执行,直到到达当前函数的下一行或它返回为止。
s (step)s (步骤) Execute the current line and stop at the first possible occasion (either in a function that is called or in the current function). 执行当前行并在第一个可能的情况下停止(在被调用的函数中或在当前函数中)。

There’s a 3rd command named unt (until). It is related to n (next). We’ll look at it later in this tutorial in the section Continuing Execution.

有一个名为unt (until)的第三个命令。 与n (下一个)有关。 我们将在本教程后面的“ 继续执行 ”部分中进行介绍。

The difference between n (next) and s (step) is where pdb stops.

n (下一个)和s (步骤)之间的差异是pdb停止的地方。

Use n (next) to continue execution until the next line and stay within the current function, i.e. not stop in a foreign function if one is called. Think of next as “staying local” or “step over”.

使用n (下一个)继续执行直到下一行并停留在当前函数之内,即,如果调用了一个,则不要在外部函数中停止。 将下一个视为“在本地停留”或“越过”。

Use s (step) to execute the current line and stop in a foreign function if one is called. Think of step as “step into”. If execution is stopped in another function, s will print --Call--.

使用s (步骤)执行当前行,并在调用一个外部函数时停止。 将步骤视为“进入”。 如果在另一个函数中停止执行,则s将打印--Call--

Both n and s will stop execution when the end of the current function is reached and print --Return-- along with the return value at the end of the next line after ->.

当到达当前函数的末尾时, ns都将停止执行,并在->之后的下一行末尾显示--Return--以及返回值。

Let’s look at an example using both commands. Here’s the example3.py source:

让我们看一个同时使用这两个命令的示例。 这是example3.py源代码:

If you run this from your shell and enter n, you should get the output:

如果从外壳运行此命令并输入n ,则应获得输出:

 $ ./example3.py 
$ ./example3.py 
> /code/example3.py> /code/example3.py (( 1414 )<module>) <module> ()
()
-> filename_path = get_path(filename)
-> filename_path = get_path(filename)
(Pdb) n
(Pdb) n
> /code/example3.py> /code/example3.py (( 1515 )<module>) <module> ()
()
-> print(f'path = {filename_path}')
-> print(f'path = {filename_path}')
(Pdb) 
(Pdb) 

With n (next), we stopped on line 15, the next line. We “stayed local” in <module>() and “stepped over” the call to get_path(). The function is <module>() since we’re currently at module level and not paused inside another function.

使用n (下一个),我们在下一行的第15行停止。 我们在<module>() “停留在本地”,并“越过”对get_path()的调用。 该函数为<module>()因为我们当前处于模块级别,并且没有在另一个函数中暂停。

Let’s try s:

让我们尝试s

With s (step), we stopped on line 6 in the function get_path() since it was called on line 14. Notice the line --Call-- after the s command.

使用s (步骤),我们在函数get_path()中的第6行停止,因为它在第14行被调用。 注意s命令后的--Call--行。

Conveniently, pdb remembers your last command. If you’re stepping through a lot of code, you can just press Enter to repeat the last command.

方便地,pdb会记住您的上一个命令。 如果您要遍历大量代码,则只需按Enter即可重复上一个命令。

Below is an example of using both s and n to step through the code. I enter s initially because I want to “step into” the function get_path() and stop. Then I enter n once to “stay local” or “step over” any other function calls and just press Enter to repeat the n command until I get to the last source line.

下面是使用sn来逐步执行代码的示例。 我最初输入s是因为我想“进入”函数get_path()并停止。 然后我一次输入n来“保持本地”或“跳过”任何其他函数调用,然后按Enter重复n命令,直到到达最后一个源代码行。

 $ ./example3.py 
$ ./example3.py 
> /code/example3.py> /code/example3.py (( 1414 )<module>) <module> ()
()
-> filename_path = get_path(filename)
-> filename_path = get_path(filename)
(Pdb) s
(Pdb) s
--Call--
--Call--
> /code/example3.py> /code/example3.py (( 66 )get_path) get_path ()
()
-> def get_path(filename):
-> def get_path(filename):
(Pdb) n
(Pdb) n
> /code/example3.py> /code/example3.py (( 88 )get_path) get_path ()
()
-> head, tail = os.path.split(filename)
-> head, tail = os.path.split(filename)
(Pdb) 
(Pdb) 
> /code/example3.py> /code/example3.py (( 99 )get_path) get_path ()
()
-> return head
-> return head
(Pdb) 
(Pdb) 
--Return--
--Return--
> /code/example3.py> /code/example3.py (( 99 )get_path) get_path ()->() -> '.'
'.'
-> return head
-> return head
(Pdb) 
(Pdb) 
> /code/example3.py> /code/example3.py (( 1515 )<module>) <module> ()
()
-> print(f'path = {filename_path}')
-> print(f'path = {filename_path}')
(Pdb) 
(Pdb) 
path = .
path = .
--Return--
--Return--
> /code/example3.py> /code/example3.py (( 1515 )<module>) <module> ()->None
() ->None
-> print(f'path = {filename_path}')
-> print(f'path = {filename_path}')
(Pdb) 
(Pdb) 

Note the lines --Call-- and --Return--. This is pdb letting you know why execution was stopped. n (next) and s (step) will stop before a function returns. That’s why you see the --Return-- lines above.

请注意--Call----Return-- 。 这是pdb,让您知道为什么执行停止。 n (下一个)和s (步骤)将在函数返回之前停止。 这就是为什么您看到上方的--Return--行。

Also note ->'.' at the end of the line after the first --Return-- above:

另请注意->'.' 在上面的第一个--Return--之后的行--Return--

When pdb stops at the end of a function before it returns, it also prints the return value for you. In this example it’s '.'.

当pdb在返回之前在函数末尾停止时,它还会为您打印返回值。 在此示例中为'.'

列出源代码 (Listing Source Code)

Don’t forget the command ll (longlist: list the whole source code for the current function or frame). It’s really helpful when you’re stepping through unfamiliar code or you just want to see the entire function for context.

不要忘记命令ll (longlist:列出当前功能或框架的全部源代码)。 当您逐步执行不熟悉的代码或只想查看上下文的整个功能时,这非常有用。

Here’s an example:

这是一个例子:

 $ ./example3.py 
$ ./example3.py 
> /code/example3.py> /code/example3.py (( 1414 )<module>) <module> ()
()
-> filename_path = get_path(filename)
-> filename_path = get_path(filename)
(Pdb) s
(Pdb) s
--Call--
--Call--
> /code/example3.py> /code/example3.py (( 66 )get_path) get_path ()
()
-> def get_path(filename):
-> def get_path(filename):
(Pdb) ll
(Pdb) ll
  6  -> def get_path(filename):
  6  -> def get_path(filename):
  7         """Return file's path or empty string if no path."""
  7         """Return file's path or empty string if no path."""
  8         head, tail = os.path.split(filename)
  8         head, tail = os.path.split(filename)
  9         return head
  9         return head
(Pdb) 
(Pdb) 

To see a shorter snippet of code, use the command l (list). Without arguments, it will print 11 lines around the current line or continue the previous listing. Pass the argument . to always list 11 lines around the current line: l .

要查看较短的代码段,请使用命令l (列表)。 如果不带参数,它将在当前行周围打印11行,或继续上一个列表。 传递论点. 始终在当前行周围列出11行: l .

使用断点 (Using Breakpoints)

Breakpoints are very convenient and can save you a lot of time. Instead of stepping through dozens of lines you’re not interested in, simply create a breakpoint where you want to investigate. Optionally, you can also tell pdb to break only when a certain condition is true.

断点非常方便,可以节省很多时间。 无需遍历数十条您不感兴趣的行,只需在要调查的地方创建一个断点即可。 (可选)您还可以告诉pdb仅在满足特定条件时才中断。

Use the command b (break) to set a breakpoint. You can specify a line number or a function name where execution is stopped.

使用命令b (中断)设置断点。 您可以指定一个行号或一个函数名,在此行中可以停止执行。

The syntax for break is:

break的语法为:

 b(reak) [ ([filename:]lineno | function) [, condition] ]
b(reak) [ ([filename:]lineno | function) [, condition] ]

If filename: is not specified before the line number lineno, then the current source file is used.

如果未在行号lineno之前指定filename: lineno则使用当前源文件。

Note the optional 2nd argument to b: condition. This is very powerful. Imagine a situation where you wanted to break only if a certain condition existed. If you pass a Python expression as the 2nd argument, pdb will break when the expression evaluates to true. We’ll do this in an example below.

请注意bcondition的可选第二个参数。 这是非常强大的。 想象一下一种情况,您只想在存在某种特定条件的情况下才休息。 如果您将Python表达式作为第二个参数传递,则表达式计算为true时,pdb将中断。 我们将在下面的示例中进行此操作。

In this example, there’s a utility module util.py. Let’s set a breakpoint to stop execution in the function get_path().

在此示例中,有一个实用程序模块util.py 让我们在函数get_path()设置一个断点以停止执行。

Here’s the source for the main script example4.py:

这是主要脚本example4.py的源代码:

Here is the source for the utility module util.py:

这是实用程序模块util.py的源代码:

 def def get_pathget_path (( filenamefilename ):
    ):
    """Return file's path or empty string if no path."""
    """Return file's path or empty string if no path."""
    import import os
    os
    headhead , , tail tail = = osos .. pathpath .. splitsplit (( filenamefilename )
    )
    return return head
head

First, let’s set a breakpoint using the source filename and line number:

首先,让我们使用源文件名和行号设置一个断点:

The command c (continue) continues execution until a breakpoint is found.

命令c (继续)继续执行,直到找到断点为止。

Next, let’s set a breakpoint using the function name:

接下来,让我们使用函数名称设置一个断点:

 $ ./example4.py 
$ ./example4.py 
> /code/example4.py> /code/example4.py (( 77 )<module>) <module> ()
()
-> filename_path = util.get_path(filename)
-> filename_path = util.get_path(filename)
(Pdb) b util.get_path
(Pdb) b util.get_path
Breakpoint 1 at /code/util.py:1
Breakpoint 1 at /code/util.py:1
(Pdb) c
(Pdb) c
> /code/util.py> /code/util.py (( 33 )get_path) get_path ()
()
-> import os
-> import os
(Pdb) p filename
(Pdb) p filename
'./example4.py'
'./example4.py'
(Pdb) 
(Pdb) 

Enter b with no arguments to see a list of all breakpoints:

输入不带参数的b以查看所有断点的列表:

You can disable and re-enable breakpoints using the command disable bpnumber and enable bpnumber. bpnumber is the breakpoint number from the breakpoints list’s 1st column Num. Notice the Enb column’s value change:

您可以使用命令disable bpnumberenable bpnumber禁用和重新启用断点。 bpnumber是断点列表的第一列Num的断点号。 注意Enb列的值更改:

 (Pdb) disable 1
(Pdb) disable 1
Disabled breakpoint 1 at /code/util.py:1
Disabled breakpoint 1 at /code/util.py:1
(Pdb) b
(Pdb) b
Num Type         Disp Enb   Where
Num Type         Disp Enb   Where
1   breakpoint   keep no    at /code/util.py:1
1   breakpoint   keep no    at /code/util.py:1
(Pdb) enable 1
(Pdb) enable 1
Enabled breakpoint 1 at /code/util.py:1
Enabled breakpoint 1 at /code/util.py:1
(Pdb) b
(Pdb) b
Num Type         Disp Enb   Where
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at /code/util.py:1
1   breakpoint   keep yes   at /code/util.py:1
(Pdb) 
(Pdb) 

To delete a breakpoint, use the command cl (clear):

要删除断点,请使用命令cl (清除):

Now let’s use a Python expression to set a breakpoint. Imagine a situation where you wanted to break only if your troubled function received a certain input.

现在,让我们使用Python表达式设置断点。 想象一下这样一种情况,您只想在遇到问题的功能收到某个输入时才中断。

In this example scenario, the get_path() function is failing when it receives a relative path, i.e. the file’s path doesn’t start with /. I’ll create an expression that evaluates to true in this case and pass it to b as the 2nd argument:

在此示例场景中,当get_path()函数接收到相对路径时即失败,即文件的路径不是以/开头。 在这种情况下,我将创建一个计算结果为true的表达式,并将其作为第二个参数传递给b

 $ ./example4.py 
$ ./example4.py 
> /code/example4.py> /code/example4.py (( 77 )<module>) <module> ()
()
-> filename_path = util.get_path(filename)
-> filename_path = util.get_path(filename)
(Pdb) b util.get_path, not filename.startswith('/')
(Pdb) b util.get_path, not filename.startswith('/')
Breakpoint 1 at /code/util.py:1
Breakpoint 1 at /code/util.py:1
(Pdb) c
(Pdb) c
> /code/util.py> /code/util.py (( 33 )get_path) get_path ()
()
-> import os
-> import os
(Pdb) a
(Pdb) a
filename = './example4.py'
filename = './example4.py'
(Pdb) 
(Pdb) 

After you create the breakpoint above and enter c to continue execution, pdb stops when the expression evaluates to true. The command a (args) prints the argument list of the current function.

在上面创建断点并输入c以继续执行后,当表达式的计算结果为true时,pdb停止。 命令a (args)打印当前函数的参数列表。

In the example above, when you’re setting the breakpoint with a function name rather than a line number, note that the expression should use only function arguments or global variables that are available at the time the function is entered. Otherwise, the breakpoint will stop execution in the function regardless of the expression’s value.

在上面的示例中,当您使用函数名称而不是行号设置断点时,请注意,表达式应仅使用输入函数时可用的函数参数或全局变量。 否则,无论表达式的值如何,断点将停止在函数中执行。

If you need to break using an expression with a variable name located inside a function, i.e. a variable name not in the function’s argument list, specify the line number:

如果需要中断使用函数内部具有变量名称的表达式,即变量名称不在函数的参数列表中,请指定行号:

You can also set a temporary breakpoint using the command tbreak. It’s removed automatically when it’s first hit. It uses the same arguments as b.

您还可以使用命令tbreak设置临时断点。 首次点击时会自动删除。 它使用与b相同的参数。

继续执行 (Continuing Execution)

So far, we’ve looked at stepping through code with n (next) and s (step) and using breakpoints with b (break) and c (continue).

到目前为止,我们已经研究了使用n (下一个)和s (上一步)逐步执行代码,以及使用b (break)和c (继续)上的断点。

There’s also a related command: unt (until).

还有一个相关的命令: unt (直到)。

Use unt to continue execution like c, but stop at the next line greater than the current line. Sometimes unt is more convenient and quicker to use and is exactly what you want. I’ll demonstrate this with an example below.

使用unt可以像c一样继续执行,但是要在比当前行大的下一行处停止。 有时unt更加方便快捷地使用,这正是您想要的。 我将在下面的示例中对此进行演示。

Let’s first look at the syntax and description for unt:

首先让我们看一下unt的语法和描述:

Command 命令 Syntax 句法 Description 描述
untunt unt(il) [lineno] unt(il)[lineno] lineno, continue execution until the line with a number greater than the current one is reached. With lineno ,请继续执行,直到达到行号大于当前行的行为止。 使用lineno, continue execution until a line with a number greater or equal to that is reached. In both cases, also stop when the current frame returns.lineno ,继续执行直到行号大于或等于该行。 在这两种情况下,当当前帧返回时也要停止。

Depending on whether or not you pass the line number argument lineno, unt can behave in two ways:

根据是否传递行号参数linenount可以通过两种方式lineno

  • Without lineno, continue execution until the line with a number greater than the current one is reached. This is similar to n (next). It’s an alternate way to execute and “step over” code. The difference between n and unt is that unt stops only when a line with a number greater than the current one is reached. n will stop at the next logically executed line.
  • With lineno, continue execution until a line with a number greater or equal to that is reached. This is like c (continue) with a line number argument.
  • 如果没有lineno ,请继续执行,直到达到行号大于当前行的行为止。 这类似于n (下一个)。 这是执行和“跳过”代码的另一种方法。 nunt之间的区别在于unt仅当到达行号大于当前行的行时unt停止。 n将停止在下一个逻辑执行的行。
  • 使用lineno ,继续执行直到行号大于或等于该行。 这类似于带有行号参数的c (继续)。

In both cases, unt stops when the current frame (function) returns, just like n (next) and s (step).

在这两种情况下,当当前帧(函数)返回时, unt停止,就像n (下一个)和s (步进)一样。

The primary behavior to note with unt is that it will stop when a line number greater or equal to the current or specified line is reached.

unt要注意的主要行为是,当达到或大于或等于当前行的行号时,它将停止。

Use unt when you want to continue execution and stop farther down in the current source file. You can treat it like a hybrid of n (next) and b (break), depending on whether you pass a line number argument or not.

当您要继续执行并在当前源文件中进一步停止时,请使用unt 。 您可以将其视为n (下一个)和b (断点)的混合体,具体取决于是否传递行号参数。

In the example below, there is a function with a loop. Here, you want to continue execution of the code and stop after the loop, without stepping through each iteration of the loop or setting a breakpoint:

在下面的示例中,有一个带有循环的函数。 在这里,您希望继续执行代码并在循环之后停止,而无需单步执行循环的每次迭代或设置断点:

Here’s the example source for example4unt.py:

这是example4unt.py的示例源:

 #!/usr/bin/env python3

#!/usr/bin/env python3

import import os


os


def def get_pathget_path (( fnamefname ):
    ):
    """Return file's path or empty string if no path."""
    """Return file's path or empty string if no path."""
    import import pdbpdb ; ; pdbpdb .. set_traceset_trace ()
    ()
    headhead , , tail tail = = osos .. pathpath .. splitsplit (( fnamefname )
    )
    for for char char in in tailtail :
        :
        pass  pass  # Check filename char
    # Check filename char
    return return head


head


filename filename = = __file__
__file__
filename_path filename_path = = get_pathget_path (( filenamefilename )
)
printprint (( ff 'path = {filename_path}''path = {filename_path}' )
)

And the console output using unt:

和控制台输出使用unt

The ll command was used first to print the function’s source, followed by unt. pdb remembers the last command entered, so I just pressed Enter to repeat the unt command. This continued execution through the code until a source line greater than the current line was reached.

首先使用ll命令来打印函数的源,然后是unt 。 pdb会记住上一次输入的命令,因此我只是按Enter来重复unt命令。 这将继续执行代码,直到到达比当前行大的源行为止。

Note in the console output above that pdb stopped only once on lines 10 and 11. Since unt was used, execution was stopped only in the 1st iteration of the loop. However, each iteration of the loop was executed. This can be verified in the last line of output. The char variable’s value 'y' is equal to the last character in tail‘s value 'example4unt.py'.

注意,在上面的控制台输出中,pdb在第10行和第11行仅停止了一次。 由于使用了unt ,因此仅在循环的第一次迭代中停止执行。 但是,循环的每次迭代都已执行。 这可以在输出的最后一行中进行验证。 char变量的值'y'等于tail的值'example4unt.py'的最后一个字符。

显示表情 (Displaying Expressions)

Similar to printing expressions with p and pp, you can use the command display [expression] to tell pdb to automatically display the value of an expression, if it changed, when execution stops. Use the command undisplay [expression] to clear a display expression.

与使用ppp打印表达式类似,可以使用命令display [expression]告诉pdb在执行停止时自动显示表达式的值(如果更改)。 使用命令undisplay [expression]清除显示表达式。

Here’s the syntax and description for both commands:

这是这两个命令的语法和说明:

Command 命令 Syntax 句法 Description 描述
displaydisplay display [expression] 显示[表情] expression if it changed, each time execution stops in the current frame. Without expression的值(如果更改)。 如果不使用expression, list all display expressions for the current frame.expression ,则列出当前帧的所有显示表达式。
undisplayundisplay undisplay [expression] 取消显示[表情] expression any more in the current frame. Without expression 。 如果不使用expression, clear all display expressions for the current frame.expression ,则清除当前帧的所有显示表达式。

Below is an example, example4display.py, demonstrating its use with a loop:

下面是一个example4display.py示例,通过循环演示了其用法:

 $ ./example4display.py 
$ ./example4display.py 
> /code/example4display.py> /code/example4display.py (( 99 )get_path) get_path ()
()
-> head, tail = os.path.split(fname)
-> head, tail = os.path.split(fname)
(Pdb) ll
(Pdb) ll
  6     def get_path(fname):
  6     def get_path(fname):
  7         """Return file's path or empty string if no path."""
  7         """Return file's path or empty string if no path."""
  8         import pdb; pdb.set_trace()
  8         import pdb; pdb.set_trace()
  9  ->     head, tail = os.path.split(fname)
  9  ->     head, tail = os.path.split(fname)
 10         for char in tail:
 10         for char in tail:
 11             pass  # Check filename char
 11             pass  # Check filename char
 12         return head
 12         return head
(Pdb) b 11
(Pdb) b 11
Breakpoint 1 at /code/example4display.py:11
Breakpoint 1 at /code/example4display.py:11
(Pdb) c
(Pdb) c
> /code/example4display.py> /code/example4display.py (( 1111 )get_path) get_path ()
()
-> pass  # Check filename char
-> pass  # Check filename char
(Pdb) display char
(Pdb) display char
display char: 'e'
display char: 'e'
(Pdb) c
(Pdb) c
> /code/example4display.py> /code/example4display.py (( 1111 )get_path) get_path ()
()
-> pass  # Check filename char
-> pass  # Check filename char
display char: 'x'  [old: 'e']
display char: 'x'  [old: 'e']
(Pdb) 
(Pdb) 
> /code/example4display.py> /code/example4display.py (( 1111 )get_path) get_path ()
()
-> pass  # Check filename char
-> pass  # Check filename char
display char: 'a'  [old: 'x']
display char: 'a'  [old: 'x']
(Pdb) 
(Pdb) 
> /code/example4display.py> /code/example4display.py (( 1111 )get_path) get_path ()
()
-> pass  # Check filename char
-> pass  # Check filename char
display char: 'm'  [old: 'a']
display char: 'm'  [old: 'a']

In the output above, pdb automatically displayed the value of the char variable because each time the breakpoint was hit its value had changed. Sometimes this is helpful and exactly what you want, but there’s another way to use display.

在上面的输出中,pdb自动显示char变量的值,因为每次命中断点时其值都会更改。 有时候这很有用,而且正是您想要的,但是还有另一种使用display

You can enter display multiple times to build a watch list of expressions. This can be easier to use than p. After adding all of the expressions you’re interested in, simply enter display to see the current values:

您可以多次输入display来构建表达式监视列表。 这可能比p更易于使用。 添加所有您感兴趣的表达式后,只需输入display以查看当前值:

Python来电显示 (Python Caller ID)

In this last section, we’ll build upon what we’ve learned so far and finish with a nice payoff. I use the name “caller ID” in reference to the phone system’s caller identification feature. That is exactly what this example demonstrates, except it’s applied to Python.

在最后一部分中,我们将以到目前为止所学的知识为基础,并获得可观的回报。 我使用“呼叫者ID”作为呼叫系统的呼叫者识别功能。 这就是该示例所演示的内容,只是将其应用于Python。

Here’s the source for the main script example5.py:

这是主要脚本example5.py的源代码:

 #!/usr/bin/env python3

#!/usr/bin/env python3

import import fileutil


fileutil


def def get_file_infoget_file_info (( full_fnamefull_fname ):
    ):
    file_path file_path = = fileutilfileutil .. get_pathget_path (( full_fnamefull_fname )
    )
    return return file_path


file_path


filename filename = = __file__
__file__
filename_path filename_path = = get_file_infoget_file_info (( filenamefilename )
)
printprint (( ff 'path = {filename_path}''path = {filename_path}' )
)

Here is the utility module fileutil.py:

这是实用程序模块fileutil.py

In this scenario, imagine there’s a large code base with a function in a utility module, get_path(), that’s being called with invalid input. However, it’s being called from many places in different packages.

在这种情况下,假设在实用程序模块中有一个功能强大的代码库get_path() ,该代码被无效输入调用。 但是,它在许多地方以不同的软件包被调用。

How do you find who the caller is?

您如何找到来电者?

Use the command w (where) to print a stack trace, with the most recent frame at the bottom:

使用命令w (where)打印堆栈跟踪,最后一帧显示在底部:

 $ ./example5.py 
$ ./example5.py 
> /code/fileutil.py> /code/fileutil.py (( 55 )get_path) get_path ()
()
-> head, tail = os.path.split(fname)
-> head, tail = os.path.split(fname)
(Pdb) w
(Pdb) w
  /code/example5.py(12)<module>()
  /code/example5.py(12)<module>()
-> filename_path = get_file_info(filename)
-> filename_path = get_file_info(filename)
  /code/example5.py(7)get_file_info()
  /code/example5.py(7)get_file_info()
-> file_path = fileutil.get_path(full_fname)
-> file_path = fileutil.get_path(full_fname)
> /code/fileutil.py> /code/fileutil.py (( 55 )get_path) get_path ()
()
-> head, tail = os.path.split(fname)
-> head, tail = os.path.split(fname)
(Pdb) 
(Pdb) 

Don’t worry if this looks confusing or if you’re not sure what a stack trace or frame is. I’ll explain those terms below. It’s not as difficult as it might sound.

如果这看起来令人困惑,或者您不确定堆栈跟踪或框架是什么,请不要担心。 我将在下面解释这些术语。 这并不像听起来那样困难。

Since the most recent frame is at the bottom, start there and read from the bottom up. Look at the lines that start with ->, but skip the 1st instance since that’s where pdb.set_trace() was used to enter pdb in the function get_path(). In this example, the source line that called the function get_path() is:

由于最近的一帧位于底部,因此从此处开始并从下向上读取。 查看以->开头的行,但跳过第一个实例,因为那是使用pdb.set_trace()在函数get_path()输入pdb的get_path() 。 在此示例中,调用函数get_path()的源代码行是:

The line above each -> contains the filename, line number (in parentheses), and function name the source line is in. So the caller is:

每个->上方的行包含文件名,行号(在括号中)和源行所在的函数名称。因此,调用方为:

   /code/example5.py(7)get_file_info()
  /code/example5.py(7)get_file_info()
-> file_path = fileutil.get_path(full_fname)
-> file_path = fileutil.get_path(full_fname)

That is no surprise in this small example for demonstration purposes, but imagine a large application where you’ve set a breakpoint with a condition to identify where a bad input value is originating.

在这个用于演示目的的小示例中,这并不奇怪,但是请想象一下,在一个大型应用程序中,您已经设置了一个断点,并带有条件来标识错误的输入值源自何处。

Now we know how to find the caller.

现在我们知道如何找到呼叫者。

But what about this stack trace and frame stuff?

但是这个堆栈跟踪和框架的东西呢?

A stack trace is just a list of all the frames that Python has created to keep track of function calls. A frame is a data structure Python creates when a function is called and deletes when it returns. The stack is simply an ordered list of frames or function calls at any point in time. The (function call) stack grows and shrinks throughout the life of an application as functions are called and then return.

堆栈跟踪只是Python创建的用于跟踪函数调用的所有框架的列表。 框架是Python在调用函数时创建并在返回时删除的数据结构。 堆栈只是在任何时间点的帧或函数调用的有序列表。 (函数调用)堆栈在应用程序的整个生命周期中随着调用函数然后返回而增长和缩小。

When printed, this ordered list of frames, the stack, is called a stack trace. You can see it at any time by entering the command w, as we did above to find the caller.

打印时,此有序的框架列表即堆栈称为堆栈跟踪。 您可以随时输入命令w来查看它,就像我们在上面找到呼叫者时所做的那样。

See this call stack article on Wikipedia for details.

有关详细信息,请参阅Wikipedia上的调用堆栈文章

To understand better and get more out of pdb, let’s look more closely at the help for w:

为了更好地理解pdb并从中获得更多信息,让我们仔细看看w的帮助:

What does pdb mean by “current frame”?

pdb“当前帧”是什么意思?

Think of the current frame as the current function where pdb has stopped execution. In other words, the current frame is where your application is currently paused and is used as the “frame” of reference for pdb commands like p (print).

将当前帧视为pdb已停止执行的当前函数。 换句话说,当前框架是您的应用程序当前暂停的位置,并用作pdb命令(例如p (打印))的参考“框架”。

p and other commands will use the current frame for context when needed. In the case of p, the current frame will be used for looking up and printing variable references.

p和其他命令将在需要时将当前帧用于上下文。 在p的情况下,当前帧将用于查找和打印变量参考。

When pdb prints a stack trace, an arrow > indicates the current frame.

当pdb打印堆栈跟踪时,箭头>表示当前帧。

How is this useful?

这有什么用?

You can use the two commands u (up) and d (down) to change the current frame. Combined with p, this allows you to inspect variables and state in your application at any point along the call stack in any frame.

您可以使用两个命令u (向上)和d (向下)更改当前帧。 与p结合使用,这使您可以在任何帧中的调用堆栈的任何位置检查应用程序中的变量和状态。

Here’s the syntax and description for both commands:

这是这两个命令的语法和说明:

Command 命令 Syntax 句法 Description 描述
uu u(p) [count] u(p)[计数] count (default one) levels up in the stack trace (to an older frame).count (默认为一个)上移(至较旧的帧)。
dd d(own) [count] d(拥有)[计数] count (default one) levels down in the stack trace (to a newer frame).count (默认为一个)下移(至新的帧)。

Let’s look at an example using the u and d commands. In this scenario, we want to inspect the variable full_fname that’s local to the function get_file_info() in example5.py. In order to do this, we have to change the current frame up one level using the command u:

让我们来看一个使用ud命令的示例。 在这种情况下,我们要检查full_fname中函数get_file_info()本地的变量example5.py 。 为此,我们必须使用命令u将当前帧向上更改一级:

 $ ./example5.py 
$ ./example5.py 
> /code/fileutil.py> /code/fileutil.py (( 55 )get_path) get_path ()
()
-> head, tail = os.path.split(fname)
-> head, tail = os.path.split(fname)
(Pdb) w
(Pdb) w
  /code/example5.py(12)<module>()
  /code/example5.py(12)<module>()
-> filename_path = get_file_info(filename)
-> filename_path = get_file_info(filename)
  /code/example5.py(7)get_file_info()
  /code/example5.py(7)get_file_info()
-> file_path = fileutil.get_path(full_fname)
-> file_path = fileutil.get_path(full_fname)
> /code/fileutil.py> /code/fileutil.py (( 55 )get_path) get_path ()
()
-> head, tail = os.path.split(fname)
-> head, tail = os.path.split(fname)
(Pdb) u
(Pdb) u
> /code/example5.py> /code/example5.py (( 77 )get_file_info) get_file_info ()
()
-> file_path = fileutil.get_path(full_fname)
-> file_path = fileutil.get_path(full_fname)
(Pdb) p full_fname
(Pdb) p full_fname
'./example5.py'
'./example5.py'
(Pdb) d
(Pdb) d
> /code/fileutil.py> /code/fileutil.py (( 55 )get_path) get_path ()
()
-> head, tail = os.path.split(fname)
-> head, tail = os.path.split(fname)
(Pdb) p fname
(Pdb) p fname
'./example5.py'
'./example5.py'
(Pdb) 
(Pdb) 

The call to pdb.set_trace() is in fileutil.py in the function get_path(), so the current frame is initially set there. You can see it in the 1st line of output above:

到呼叫pdb.set_trace()是在fileutil.py在函数get_path()所以在当前帧被初始设置在那里。 您可以在上面的第一行输出中看到它:

To access and print the local variable full_fname in the function get_file_info() in example5.py, the command u was used to move up one level:

访问和打印的局部变量full_fname在功能get_file_info()example5.py ,命令u用来返回上一级菜单:

 (Pdb) u
(Pdb) u
> /code/example5.py> /code/example5.py (( 77 )get_file_info) get_file_info ()
()
-> file_path = fileutil.get_path(full_fname)
-> file_path = fileutil.get_path(full_fname)

Note in the output of u above that pdb printed the arrow > at the beginning of the 1st line. This is pdb letting you know the frame was changed and this source location is now the current frame. The variable full_fname is accessible now. Also, it’s important to realize the source line starting with -> on the 2nd line has been executed. Since the frame was moved up the stack, fileutil.get_path() has been called. Using u, we moved up the stack (in a sense, back in time) to the function example5.get_file_info() where fileutil.get_path() was called.

注意,在上面的u输出中,pdb在第一行的开头打印了箭头> 。 这是pdb,让您知道框架已更改,并且此源位置现在是当前框架。 现在可以访问变量full_fname 。 同样,重要的是要实现第二行以->开头的源代码行。 由于框架已在堆栈中向上移动,因此已调用fileutil.get_path() 。 使用u ,我们将栈上移(从某种意义上讲,是时光倒流)到函数example5.get_file_info() ,其中调用了fileutil.get_path()

Continuing with the example, after full_fname was printed, the current frame was moved to its original location using d, and the local variable fname in get_path() was printed.

继续该示例,在打印full_fname之后,使用d将当前帧移动到其原始位置,并打印get_path()的局部变量fname

If we wanted to, we could have moved multiple frames at once by passing the count argument to u or d. For example, we could have moved to module level in example5.py by entering u 2:

如果我们愿意,可以通过将count参数传递给ud一次移动多个帧。 例如,我们可以通过输入u 2进入example5.py的模块级别:

It’s easy to forget where you are when you’re debugging and thinking of many different things. Just remember you can always use the aptly named command w (where) to see where execution is paused and what the current frame is.

当您调试和思考许多不同的事物时,很容易忘记自己在哪里。 只需记住,您始终可以使用恰当命名的命令w (哪里)来查看暂停执行的位置以及当前帧是什么。

基本的pdb命令 (Essential pdb Commands)

Once you’ve spent a little time with pdb, you’ll realize a little knowledge goes a long way. Help is always available with the h command.

在pdb上花了一些时间后,您将意识到一点点知识会大有帮助。 h命令始终提供帮助。

Just enter h or help <topic> to get a list of all commands or help for a specific command or topic.

只需输入hhelp <topic>即可获取所有命令的列表或特定命令或主题的帮助。

For quick reference, here’s a list of essential commands:

为了快速参考,下面是一些基本命令:

Command 命令 Description 描述
pp Print the value of an expression. 打印表达式的值。
pppp Pretty-print the value of an expression. 漂亮地打印表达式的值。
nn Continue execution until the next line in the current function is reached or it returns. 继续执行,直到到达当前函数的下一行或它返回为止。
ss Execute the current line and stop at the first possible occasion (either in a function that is called or in the current function). 执行当前行并在第一个可能的情况下停止(在被调用的函数中或在当前函数中)。
cc Continue execution and only stop when a breakpoint is encountered. 继续执行,仅在遇到断点时停止。
untunt Continue execution until the line with a number greater than the current one is reached. With a line number argument, continue execution until a line with a number greater or equal to that is reached. 继续执行,直到行号大于当前行号为止。 使用行号参数,继续执行直到行号大于或等于该行。
ll List source code for the current file. Without arguments, list 11 lines around the current line or continue the previous listing. 列出当前文件的源代码。 不带参数的情况下,在当前行周围列出11行,或继续上一个列表。
llll List the whole source code for the current function or frame. 列出当前功能或框架的整个源代码。
bb With no arguments, list all breaks. With a line number argument, set a breakpoint at this line in the current file. 不带任何参数,列出所有中断。 使用行号参数在当前文件的此行设置一个断点。
ww Print a stack trace, with the most recent frame at the bottom. An arrow indicates the current frame, which determines the context of most commands. 打印堆栈跟踪,最新一帧显示在底部。 箭头指示当前框架,该框架确定大多数命令的上下文。
uu Move the current frame count (default one) levels up in the stack trace (to an older frame). 在堆栈跟踪中将当前帧计数(默认为一个)上移(至较旧的帧)。
dd Move the current frame count (default one) levels down in the stack trace (to a newer frame). 在堆栈跟踪中将当前帧计数(默认为一个)下移(至新的帧)。
hh See a list of available commands. 查看可用命令列表。
h <topic>h <topic> Show help for a command or topic. 显示命令或主题的帮助。
h pdbh pdb Show the full pdb documentation. 显示完整的pdb文档。
qq Quit the debugger and exit. 退出调试器并退出。

使用pdb进行Python调试:结论 (Python Debugging With pdb: Conclusion)

In this tutorial, we covered a few basic and common uses of pdb:

在本教程中,我们介绍了pdb的一些基本和常见用法:

  • printing expressions
  • stepping through code with n (next) and s (step)
  • using breakpoints
  • continuing execution with unt (until)
  • displaying expressions
  • finding the caller of a function
  • 打印表达式
  • 单步执行代码n (下一个)和s (步骤)
  • 使用断点
  • 继续执行unt (直到)
  • 显示表情
  • 查找函数的调用者

I hope it’s been helpful to you. If you’re curious about learning more, see:

希望对您有所帮助。 如果您想了解更多信息,请参阅:

  • 在您附近的pdb提示符下显示pdb的完整文档: (Pdb) h pdb
  • Python的PDB文档

The source code used in the examples can be found on the associated GitHub repository. Be sure to check out our printable pdb Command Reference, which you can use as a cheat sheet while debugging:

示例中使用的源代码可以在关联的GitHub存储库找到 。 请务必查看我们可打印的pdb命令参考,您可以在调试时将其用作备忘单:

Free Bonus: Click here to get a printable “pdb Command Reference” (PDF) that you can keep on your desk and refer to while debugging.

免费赠品: 单击此处可获得可打印的“ pdb命令参考”(PDF) ,您可以将其放在办公桌上,并在调试时参考。

Also, if you’d like to try a GUI-based Python debugger, read our Python IDEs and Editors Guide to see what options will work best for you. Happy Pythoning!

另外,如果您想尝试基于GUI的Python调试器,请阅读我们的《 Python IDE和编辑器指南》,以了解哪些选项最适合您。 快乐的Pythoning!

翻译自: https://www.pybloggers.com/2018/04/python-debugging-with-pdb/

python pdb调试

 类似资料: