繁体   English   中英

回溯后如何检查变量?

[英]How to inspect variables after Traceback?

我的 Python 脚本崩溃了。 为了调试它,我以交互模式运行它python -i example.py

Traceback (most recent call last):
  File "example.py", line 5, in <module>
    main()
  File "example.py", line 3, in main
    message[20]
IndexError: string index out of range

此时,我想检查变量message 我试过

>>> message
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'message' is not defined

message不在范围内(尽管main是)。 这令人沮丧。 如何检查变量? 是否有更有用的python -i版本可以在崩溃时保留范围内的内容(而不是顶级)?


用于上面example.py代码。 不用说,这是一种简化。

def main():
    message = "hello world"
    message[20]

main()

仅在出现异常时才进入调试器,您可以定义自定义 exceptionhook

import sys
def excepthook(type_, value, tb):
    import traceback
    import pdb
    traceback.print_exception(type_, value, tb)
    pdb.post_mortem(tb)
sys.excepthook = excepthook

def main():
    message = "hello world"
    message[20]

main()

运行脚本会将您带入 pdb 和引发异常的框架中:

% script.py
Traceback (most recent call last):
  File "/home/unutbu/pybin/script.py", line 16, in <module>
    main()
  File "/home/unutbu/pybin/script.py", line 14, in main
    message[20]
IndexError: string index out of range
> /home/unutbu/pybin/script.py(14)main()
-> message[20]
(Pdb) p message
'hello world'
(Pdb) p message[20]
*** IndexError: IndexError('string index out of range',)
(Pdb) p len(message)
11

如果定义 exceptionhook 看起来代码太多,您可以将其隐藏在实用程序模块中,例如 utils_debug.py:

import sys
def enable_pdb():
    def excepthook(type_, value, tb):
        import traceback
        import pdb
        traceback.print_exception(type_, value, tb)
        pdb.post_mortem(tb)
    sys.excepthook = excepthook

然后你只需要添加

import utils_debug as UDBG
UDBG.enable_pdb()

到您的script.py


或者,如果您使用的是IPython ,则可以使用%pdb 魔法函数(当出现异常时,它ipdb您放入ipdb )。


不清楚为什么在 pdb 提示符下检查size会给你一个 NameError。 (可运行的示例非常有用。)您可以尝试使用bt (回溯)来检查帧堆栈。 如果size在与pdb当前所在的帧不同的帧中定义,则您可以使用u (up)转到定义size的帧。

根据 Python 文档https://docs.python.org/3.4/library/pdb.html

pdb.py也可以作为脚本调用来调试其他脚本。 例如: python -m pdb myscript.py 当作为脚本调用时,如果被调试的程序异常退出,pdb会自动进入事后调试。

这并不完全准确。 它实际上在第一行进入调试。

$ python -m pdb example.py
> example.py(1)<module>()
-> def main():

但是,如果您键入c它将继续崩溃

(Pdb) c
Traceback (most recent call last):
  File "C:\Python34\lib\pdb.py", line 1661, in main
    pdb._runscript(mainpyfile)
  File "C:\Python34\lib\pdb.py", line 1542, in _runscript
    self.run(statement)
  File "C:\Python34\lib\bdb.py", line 431, in run
    exec(cmd, globals, locals)
  File "<string>", line 1, in <module>
  File "example.py", line 1, in <module>
    def main():
  File "example.py", line 3, in main
    message[20]
IndexError: string index out of range
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> example.py(3)main()

此时,您可以键入message来检查变量。

-> message[20]
(Pdb) message
'hello world'

哇!

一个简单的替代方法是使用cgitb模块。

import cgitb; cgitb.enable(format='text')


def main():
    message = "hello world"
    message[20]

main()

现在回溯本身打印消息的值。

A problem occurred in a Python script.  Here is the sequence of
function calls leading up to the error, in the order they occurred.

 /home/anand/projects/python/ptb/tes.py in <module>()
    4 def main():
    5     message = "hello world"
    6     message[20]
    7 
    8 main()
main = <function main>

 /home/anand/projects/python/ptb/tes.py in main()
    4 def main():
    5     message = "hello world"
    6     message[20]
    7 
    8 main()
message = 'hello world'
IndexError: string index out of range

您可以使用其他答案中提到的一些Python 调试器,或者尝试使用我的诊断库,该库将更详细的回溯存储为 HTML 文件:) 只需在cheaters.py文件旁边创建名为log目录并启用异常挂钩通过下面的行:

from diagnostics import exception_hook
exception_hook.enable()

我通常使用代码模块来处理这种类型的事情。 尽早捕获异常并将所有内容转储到交互式控制台中。

try:
    # something that might throw an error
except Exception as e:
    import code
    l={}
    l['global_vars'] = globals()
    l['local_vars'] = locals()
    code.InteractiveConsole(locals=l).interact()

这将在异常处理程序中启动一个 python REPL,引发的异常将在 local_vars['e'] 中,您将可以访问调用 try 块的范围。 如果在其他库中引发异常,您可以使用此异常处理程序修改其他库的代码,使用 PYTHONPATH 环境变量将 python 指向库的修改版本,并将原始版本保留在原处。

对于这些情况,我强烈推荐 ipython 和 ipdb。

在 ipython shell 中,您键入

run example.py

当未处理的异常返回到 ipython shell 时,您键入

%debug

这将使您进入 ipdb,位于引发未处理异常的确切代码行。 然后,您可以简单地通过评估变量来检查变量,就像在普通 python shell 中一样。

我的回答类似于已经被接受的恐慌上校的回答。 这里的主要优势是 ipython 和 ipdb。 我更喜欢这些工具的原因有很多,最突出的是它们启用了变量名称的制表符补全。 一旦您习惯了 Tab 补全,就很难没有它,因为它可以让您工作得更快。

使用 , pdb 调试每一行

import pdb; pdb.set_trace()

这会让你在每一行之后休息,你可以跟踪你的代码

def main():
    import pdb; pdb.set_trace()
    message = "hello world"
    message[20]

main()

当 main() 被调用时,这个函数将开始工作,你可以跟踪消息,你可以调试它

你的终端看起来像这样

> /home/admin/dxservices/example.py(3)main()
-> message = "hello world"
(Pdb) 
> /home/admin/dxservices/example.py(4)main()
-> message[20]
(Pdb) n
 IndexError: 'string index out of range'  
 > /home/admin/dxservices/example.py(4)main()
-> message[20]

这取决于什么最适合你。 由于这个问题留下了一些解释空间,这里有一些替代方案。

以编程方式访问变量以在代码中使用它们

使用inspect模块

except ... as ...:
    x = inspect.trace()[-1][0].f_locals['x']

为调试目的传递某个变量值,比如记录它

将该值添加到异常消息中。

raise ValueError("oops, x={}".format(x))

但是如果一些外部代码引发,你就不能这样做。 此外,它需要时间并且不太实用。

只需打印导致异常的变量

尝试使用回溯变量pip install traceback-with-variables ),这是明信片

在此处输入图片说明

tbvaccine ,或Better -exceptions任何其他包

还有一个使用调试器的选项,比如python -m pdb 这仅允许打印调试运行的信息,对生产没有帮助,而且需要很多时间。 所以我会说这个选项是最不可取的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM