The text is released under the CC-BY-NC-ND license, and code is released under the MIT license. If you find this content useful, please consider supporting the work by buying the book!
代码开发和数据分析总是需要一些试错,IPython 包含了简化这个过程的工具。本节首先简要介绍一些控制 Python 异常报告的方法,然后探索代码中 Debug 的工具。
Code development and data analysis always require a bit of trial and error, and IPython contains tools to streamline this process. This section will briefly cover some options for controlling Python's exception reporting, followed by exploring tools for debugging errors in code.
%xmode
进行报错控制¶%xmode
¶当 Python 脚本执行失败的时候会引发一个异常。当解释器遇到这些异常时会在 traceback 中展示有关错误原因的信息,这可以从 Python 解释器的输出中看得到。使用 %xmode
魔法函数,IPython 允许您控制在异常发生时打印的信息量。看下面的代码:
Most of the time when a Python script fails, it will raise an Exception.
When the interpreter hits one of these exceptions, information about the cause of the error can be found in the traceback, which can be accessed from within Python.
With the %xmode
magic function, IPython allows you to control the amount of information printed when the exception is raised.
Consider the following code:
def func1(a, b):
return a / b
def func2(x):
a = x
b = x - 1
return func1(a, b)
func2(1)
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-2-b2e110f6fc8f> in <module>() ----> 1 func2(1) <ipython-input-1-d849e34d61fb> in func2(x) 5 a = x 6 b = x - 1 ----> 7 return func1(a, b) <ipython-input-1-d849e34d61fb> in func1(a, b) 1 def func1(a, b): ----> 2 return a / b 3 4 def func2(x): 5 a = x ZeroDivisionError: integer division or modulo by zero
调用 func2
会报错,通过查看打印出来的报错信息我们可以知道除了什么问题。默认情况下,这个信息(trace)包括会展示各个阶段报错位置前后的代码内容。使用 %xmode
魔法函数(异常模式的缩写),我们可以控制打印的内容。
Calling func2
results in an error, and reading the printed trace lets us see exactly what happened.
By default, this trace includes several lines showing the context of each step that led to the error.
Using the %xmode
magic function (short for Exception mode), we can change what information is printed.
%xmode
只有一个参数,包含三个选项:Plain
Context
和 Verbose
。默认值是 Context
所打印的信息就像上面的例子那样。Plain
意思是更少的信息:
%xmode
takes a single argument, the mode, and there are three possibilities: Plain
, Context
, and Verbose
.
The default is Context
, and gives output like that just shown before.
Plain
is more compact and gives less information:
%xmode Plain
Exception reporting mode: Plain
func2(1)
Traceback (most recent call last): File "<ipython-input-4-b2e110f6fc8f>", line 1, in <module> func2(1) File "<ipython-input-1-d849e34d61fb>", line 7, in func2 return func1(a, b) File "<ipython-input-1-d849e34d61fb>", line 2, in func1 return a / b ZeroDivisionError: integer division or modulo by zero
Verbose
是指展示更多的信息,会包含函数被调用时所传递的参数:
The Verbose
mode adds some extra information, including the arguments to any functions that are called:
%xmode Verbose
Exception reporting mode: Verbose
func2(1)
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-6-b2e110f6fc8f> in <module>() ----> 1 func2(1) global func2 = <function func2 at 0x10ff42c80> <ipython-input-1-d849e34d61fb> in func2(x=1) 5 a = x 6 b = x - 1 ----> 7 return func1(a, b) global func1 = <function func1 at 0x10ff42c08> a = 1 b = 0 <ipython-input-1-d849e34d61fb> in func1(a=1, b=0) 1 def func1(a, b): ----> 2 return a / b a = 1 b = 0 3 4 def func2(x): 5 a = x ZeroDivisionError: integer division or modulo by zero
额外的信息让我们更易于锁定报错的原因。那为什么不一直都使用 Verbose
参数呢?因为如果代码非常复杂,这种模式下的报错信息会显得非常混乱。所以依据具体情况,有的时候 Default
就够了。
This extra information can help narrow-in on why the exception is being raised.
So why not use the Verbose
mode all the time?
As code gets complicated, this kind of traceback can get extremely long.
Depending on the context, sometimes the brevity of Default
mode is easier to work with.
标准 Python 使用的调试工具是 pdb
,即 the Python debugger。这个调试器允许用户逐行执行代码,以查看那些难以察觉的错误。IPython 提供了增强版本:ipdb
即 IPython debugger。
The standard Python tool for interactive debugging is pdb
, the Python debugger.
This debugger lets the user step through the code line by line in order to see what might be causing a more difficult error.
The IPython-enhanced version of this is ipdb
, the IPython debugger.
使用这两个调试器有很多方式和情况,我们不在这里一一列举。在内建文档中有它们的全部信息。在 IPython 中用 %debug
命令是使用调试工具最简便的方法。如果你在遇到异常之后调用这个命令,它会自动帮你在报错的位置创建一个断点。ipbd
可以辅助你查看断点位置的状态、当前的变量内容甚至是执行 Python 命令。
There are many ways to launch and use both these debuggers; we won't cover them fully here. Refer to the online documentation of these two utilities to learn more.
In IPython, perhaps the most convenient interface to debugging is the %debug
magic command.
If you call it after hitting an exception, it will automatically open an interactive debugging prompt at the point of the exception.
The ipdb
prompt lets you explore the current state of the stack, explore the available variables, and even run Python commands!
让我们试试最近一次报错的情况,在弹出框下打印 a
和 b
的值,然后输入 quit
退出调试:
Let's look at the most recent exception, then do some basic tasks–print the values of a
and b
, and type quit
to quit the debugging session:
%debug
> <ipython-input-1-d849e34d61fb>(2)func1() 1 def func1(a, b): ----> 2 return a / b 3 ipdb> print(a) 1 ipdb> print(b) 0 ipdb> quit
除此之外,交互式调试器还能在函数调用栈之间切换并查看各个栈下的变量内容:
The interactive debugger allows much more than this, though–we can even step up and down through the stack and explore the values of variables there:
%debug
> <ipython-input-1-d849e34d61fb>(2)func1() 1 def func1(a, b): ----> 2 return a / b 3 ipdb> up > <ipython-input-1-d849e34d61fb>(7)func2() 5 a = x 6 b = x - 1 ----> 7 return func1(a, b) ipdb> print(x) 1 ipdb> up > <ipython-input-6-b2e110f6fc8f>(1)<module>() ----> 1 func2(1) ipdb> down > <ipython-input-1-d849e34d61fb>(7)func2() 5 a = x 6 b = x - 1 ----> 7 return func1(a, b) ipdb> quit
这允许你快速找出导致错误的原因并定位那个函数调用导致了错误。
This allows you to quickly find out not only what caused the error, but what function calls led up to the error.
如果您希望调试器在引发异常时自动启动,您可以使用 %pdb
魔法函数打开此行为:
If you'd like the debugger to launch automatically whenever an exception is raised, you can use the %pdb
magic function to turn on this automatic behavior:
%xmode Plain
%pdb on
func2(1)
Exception reporting mode: Plain Automatic pdb calling has been turned ON
Traceback (most recent call last): File "<ipython-input-7-35491686a29e>", line 3, in <module> func2(1) File "<ipython-input-1-d849e34d61fb>", line 7, in func2 return func1(a, b) File "<ipython-input-1-d849e34d61fb>", line 2, in func1 return a / b ZeroDivisionError: integer division or modulo by zero
> <ipython-input-1-d849e34d61fb>(2)func1() 1 def func1(a, b): ----> 2 return a / b 3 4 def func2(x): 5 a = x ipdb> quit
如果你想在交互模式下执行一个文件,你可以用 %run -d
命令,并使用 next
按行执行它。
Finally, if you have a script that you'd like to run from the beginning in interactive mode, you can run it with the command %run -d
, and use the next
command to step through the lines of code interactively.
除了下面这些之外还有很多很多调试命令没有展示,下面只包含了最常用的一些命令:
There are many more available commands for interactive debugging than we've listed here; the following table contains a description of some of the more common and useful ones:
命令 | 作用 |
---|---|
list |
展示目前执行的位置 |
h(elp) |
展示所有命令,用于查找某个命令 |
q(uit) |
退出调试状态和所执行的程序 |
c(ontinue) |
退出调试状态,回到所执行的程序 |
n(ext) |
执行下一步 |
<enter> |
重复执行上一条命令 |
p(rint) |
打印变量内容 |
s(tep) |
进入下一个函数 |
r(eturn) |
回到上一个函数 |
Command | Description |
---|---|
list |
Show the current location in the file |
h(elp) |
Show a list of commands, or find help on a specific command |
q(uit) |
Quit the debugger and the program |
c(ontinue) |
Quit the debugger, continue in the program |
n(ext) |
Go to the next step of the program |
<enter> |
Repeat the previous command |
p(rint) |
Print variables |
s(tep) |
Step into a subroutine |
r(eturn) |
Return out of a subroutine |
更多相关信息请用调试器中的 help
或是查看 ipdb
的[在线文档]
For more information, use the help
command in the debugger, or take a look at ipdb
's online documentation.