简体   繁体   English

回溯后如何检查变量?

[英]How to inspect variables after Traceback?

My Python script is crashing.我的 Python 脚本崩溃了。 To debug it, I ran it in interactive mode python -i example.py为了调试它,我以交互模式运行它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

At this point, I would like to inspect the variable message .此时,我想检查变量message I tried我试过

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

Alas message is not in scope (though main is).message不在范围内(尽管main是)。 That's frustrating.这令人沮丧。 How can I inspect the variable?如何检查变量? Is there a more useful version of python -i that keeps what's in scope at the crash (rather than the top level)?是否有更有用的python -i版本可以在崩溃时保留范围内的内容(而不是顶级)?


Code used for example.py above.用于上面example.py代码。 Needless to say, this is a simplification.不用说,这是一种简化。

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

main()

To drop to a debugger only if there is an exception you could define a custom excepthook :仅在出现异常时才进入调试器,您可以定义自定义 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()

Running the script drops you into pdb and in the frame which raised the exception:运行脚本会将您带入 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

If defining the excepthook seems like too much code, you could tuck it away in a utility module, such as utils_debug.py:如果定义 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

and then you would only need to add然后你只需要添加

import utils_debug as UDBG
UDBG.enable_pdb()

to your script.py .到您的script.py


Or, if you are using IPython , you could use the %pdb magic function (which drops you into ipdb when there is an exception).或者,如果您使用的是IPython ,则可以使用%pdb 魔法函数(当出现异常时,它ipdb您放入ipdb )。


It is unclear why inspecting size at the pdb prompt is giving you a NameError.不清楚为什么在 pdb 提示符下检查size会给你一个 NameError。 (A runnable example would be very useful.) You might try using bt (backtrace) to inspect the frame stack. (可运行的示例非常有用。)您可以尝试使用bt (回溯)来检查帧堆栈。 If size is defined in a different frame than the one pdb is currently in, you might be able use u (up) to go up to the frame where size is defined.如果size在与pdb当前所在的帧不同的帧中定义,则您可以使用u (up)转到定义size的帧。

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

pdb.py can also be invoked as a script to debug other scripts. pdb.py也可以作为脚本调用来调试其他脚本。 For example: python -m pdb myscript.py .例如: python -m pdb myscript.py When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally.当作为脚本调用时,如果被调试的程序异常退出,pdb会自动进入事后调试。

This isn't entirely accurate.这并不完全准确。 It actually enters debugging at the first line.它实际上在第一行进入调试。

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

However if you type c it will then continue to the crash但是,如果您键入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()

At this point you can type message to inspect the variable.此时,您可以键入message来检查变量。

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

Wahey!哇!

A simple alternative is to use cgitb module.一个简单的替代方法是使用cgitb模块。

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


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

main()

Now the traceback itself prints the value of the message.现在回溯本身打印消息的值。

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

You can use some of the Python debuggers as mentioned at the other answer or give a try to my diagnostics library that stores more detailed traceback for you as HTML file :) Just create directory named log next to the cheaters.py file and enable exception hook by lines below:您可以使用其他答案中提到的一些Python 调试器,或者尝试使用我的诊断库,该库将更详细的回溯存储为 HTML 文件:) 只需在cheaters.py文件旁边创建名为log目录并启用异常挂钩通过下面的行:

from diagnostics import exception_hook
exception_hook.enable()

I usually use the code module for this type of thing.我通常使用代码模块来处理这种类型的事情。 Catch the exception as early as you can and dump everything into an interactive console right there.尽早捕获异常并将所有内容转储到交互式控制台中。

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()

This will start a python REPL inside the exception handler, the raised exception will be in local_vars['e'], and you'll have access to the scope where the try block was called.这将在异常处理程序中启动一个 python REPL,引发的异常将在 local_vars['e'] 中,您将可以访问调用 try 块的范围。 If the exception is being raised inside some other library, you can modify the other library's code with this exception handler, use the PYTHONPATH environment variable to point python at the modified version of the library, and leave the original in place.如果在其他库中引发异常,您可以使用此异常处理程序修改其他库的代码,使用 PYTHONPATH 环境变量将 python 指向库的修改版本,并将原始版本保留在原处。

I highly recommend both ipython and ipdb for these sorts of situations.对于这些情况,我强烈推荐 ipython 和 ipdb。

From within the ipython shell, you type在 ipython shell 中,您键入

run example.py

When the unhandled exception returns you to the ipython shell, you type当未处理的异常返回到 ipython shell 时,您键入

%debug

This will put you in ipdb, at the exact line of code that throws the unhandled exception.这将使您进入 ipdb,位于引发未处理异常的确切代码行。 You can then inspect the variables simply by evaluating them, just as you would in a normal python shell.然后,您可以简单地通过评估变量来检查变量,就像在普通 python shell 中一样。

My answer is similar to Colonel Panic's answer that was already accepted.我的回答类似于已经被接受的恐慌上校的回答。 The main advantage here is ipython and ipdb.这里的主要优势是 ipython 和 ipdb。 I prefer these tools for a variety of reasons, the most prominent is that they enable tab completion of variable names.我更喜欢这些工具的原因有很多,最突出的是它们启用了变量名称的制表符补全。 Once you become used to tab completion, it's hard to live without it, because it allows you to work so much faster.一旦您习惯了 Tab 补全,就很难没有它,因为它可以让您工作得更快。

use , pdb for debugging each line使用 , pdb 调试每一行

import pdb; pdb.set_trace()

this will give you break after each line and you can track your code这会让你在每一行之后休息,你可以跟踪你的代码

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

main()

when main() will be call this function will start working and you can track message , you can debug it当 main() 被调用时,这个函数将开始工作,你可以跟踪消息,你可以调试它

your terminal will look like it你的终端看起来像这样

> /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]

It depends what fits you best.这取决于什么最适合你。 since the question leaves some space for interpretation, here are some alternatives.由于这个问题留下了一些解释空间,这里有一些替代方案。

Programmatically access variables to use them in your code以编程方式访问变量以在代码中使用它们

Use inspect module使用inspect模块

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

Pass a certain variable value for debug purposes, say to log it为调试目的传递某个变量值,比如记录它

Add the value to the exception message.将该值添加到异常消息中。

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

But you can't do that if some external code raises.但是如果一些外部代码引发,你就不能这样做。 Also it takes time and is not too practical.此外,它需要时间并且不太实用。

Simply print the variables that caused the exception只需打印导致异常的变量

Try traceback-with-variables ( pip install traceback-with-variables ), here is it's postcard尝试使用回溯变量pip install traceback-with-variables ),这是明信片

在此处输入图片说明

Or tbvaccine , or better-exceptions , any other packagetbvaccine ,或Better -exceptions任何其他包

There's also an option to use debugger, like python -m pdb .还有一个使用调试器的选项,比如python -m pdb This allows printing information for debug runs only and doesn't help in production, also it takes much time.这仅允许打印调试运行的信息,对生产没有帮助,而且需要很多时间。 So this option is least preferable I'd say.所以我会说这个选项是最不可取的。

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

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