Python错误后无法以交互方式访问本地变量

时间:2016-01-05 15:12:26

标签: python interactive

如果以交互式(-i)模式运行python脚本,为了帮助调试,如何在发生错误时访问堆栈帧?

脚本

# pytest.py
def foo(x):
    assert False

foo(24601)

命令会话

D:\>python.exe -i pytest.py
Traceback (most recent call last):
  File "pytest.py", line 4, in <module>
    foo(3)
  File "pytest.py", line 2, in foo
    assert False
AssertionError
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

在这种情况下,如何访问断言失败的x的值?

4 个答案:

答案 0 :(得分:1)

使用python调试器 - https://docs.python.org/2/library/pdb.html

def foo(x):
    import pdb; pdb.set_trace()   #add this line to set a breakpoint
    assert False

(你不需要它-i flag)

答案 1 :(得分:1)

http://code.activestate.com/recipes/52215-get-more-information-from-tracebacks/

Python调试器的答案听起来不错。但是,如果你想尝试别的东西&#39;。 我发现了这件事 - 它看起来就像你正在寻找的答案。如果发生错误,您可以使用traceback模块构建一个逐帧打印本地的功能。从那里,我猜你可以从日志中提取数据。

如链接示例中所述:

import sys, traceback

def print_exc_plus():
    """
    Print the usual traceback information, followed by a listing of all the
    local variables in each frame.
    """
    tb = sys.exc_info()[2]
    while 1:
        if not tb.tb_next:
            break
        tb = tb.tb_next
    stack = []
    f = tb.tb_frame
    while f:
        stack.append(f)
        f = f.f_back
    stack.reverse()
    traceback.print_exc()
    print "Locals by frame, innermost last"
    for frame in stack:
        print
        print "Frame %s in %s at line %s" % (frame.f_code.co_name,
                                             frame.f_code.co_filename,
                                             frame.f_lineno)
        for key, value in frame.f_locals.items():
            print "\t%20s = " % key,
            #We have to be careful not to cause a new error in our error
            #printer! Calling str() on an unknown object could cause an
            #error we don't want.
            try:
                print value
            except:
                print "<ERROR WHILE PRINTING VALUE>"


if __name__ == '__main__':
    #A simplistic demonstration of the kind of problem this approach can help
    #with. Basically, we have a simple function which manipulates all the
    #strings in a list. The function doesn't do any error checking, so when
    #we pass a list which contains something other than strings, we get an
    #error. Figuring out what bad data caused the error is easier with our
    #new function.

    data = ["1", "2", 3, "4"] #Typo: We 'forget' the quotes on data[2]
    def pad4(seq):
        """
        Pad each string in seq with zeros, to four places. Note there
        is no reason to actually write this function, Python already
        does this sort of thing much better.
        Just an example.
        """
        return_value = []
        for thing in seq:
            return_value.append("0" * (4 - len(thing)) + thing)
        return return_value

    #First, show the information we get from a normal traceback.print_exc().
    try:
        pad4(data)
    except:
        traceback.print_exc()
    print
    print "----------------"
    print

    #Now with our new function. Note how easy it is to see the bad data that
    #caused the problem. The variable 'thing' has the value 3, so we know
    #that the TypeError we got was because of that. A quick look at the
    #value for 'data' shows us we simply forgot the quotes on that item.
    try:
        pad4(data)
    except:
        print_exc_plus()

执行代码后,我得到了包含局部变量及其值的输出!

TypeError: object of type 'int' has no len()
                __name__ =  __main__
                    data =  ['1', '2', 3, '4']
                 __doc__ =  None
          print_exc_plus =  <function print_exc_plus at 0x7ffb8ee86668>

Frame pad4 in /home/robert.sawicki/PycharmProjects/python_challenge/test.py at line 55
                   thing =  3
            return_value =  ['0001', '0002']
                     seq =  ['1', '2', 3, '4']

答案 2 :(得分:1)

您可以直接在交互模式下使用python调试器

D:&gt; python.exe -m pdb pytest.py

使用

答案 3 :(得分:0)

您也可以在交互式Python shell中使用pdb - 您只需将代码封装在适当的函数中:

bruno@bigb:~/Work/playground$ cat pytest.py
# pytest.py
def foo(x):
    assert False

def main():
    print foo(24601)


if __name__ == "__main__":
    main()

bruno@bigb:~/Work/playground$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
Type "help", "copyright", "credits" or "license" for more information.
>>> import pytest
>>> import pdb
>>> pdb.runcall(pytest.main)
> /home/bruno/Work/playground/pytest.py(6)main()
-> print foo(24601)
(Pdb) s
--Call--
> /home/bruno/Work/playground/pytest.py(2)foo()
-> def foo(x):
(Pdb) l
  1     # pytest.py
  2  -> def foo(x):
  3         assert False
  4     
  5     def main():
  6         print foo(24601)
  7     
  8     
  9     if __name__ == "__main__":
 10         main()
[EOF]
(Pdb) n
> /home/bruno/Work/playground/pytest.py(3)foo()
-> assert False
(Pdb) !x
24601
(Pdb) c
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/pdb.py", line 1248, in runcall
    return Pdb().runcall(*args, **kwds)
  File "/usr/lib/python2.7/bdb.py", line 436, in runcall
    res = func(*args, **kwds)
  File "pytest.py", line 6, in main
    print foo(24601)
  File "pytest.py", line 3, in foo
    assert False
AssertionError
>>>