4

当我在交互式会话中运行时(在我的情况下ipython),并且当前在调试器(ipdbpdb)中时,我希望能够从调试命名空间中将变量放入主交互式命名空间中。

如果我的代码崩溃但已经完成了大量工作,这很有用,其中一些可以挽救以节省时间(例如,从磁盘加载数据)。

所以我想要的是这样的,例如:

>>> run -m my.module
loading data from disk...
done loading data.
processing data...
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
...

-> 这里在处理过程中出了点问题,但数据的加载工作正常......所以我会进入调试器检查发生了什么,并查看loaded_data

>>> debug
ipdb> len(loaded_data)
100000

-> 然后我希望能够将此变量保存到交互式命名空间以在调试器外部使用,如下所示:

ipdb> save_to_interactive('loaded_data')
ipdb> exit
>>> len(loaded_data)
100000
4

1 回答 1

8

您可以通过获取对外部解释器堆栈帧的引用并写入其帧全局变量来完成此操作。

给定一个带有断点的示例模块,将我们踢到 pdb:

my_module.py

def fun(arg):
    import pdb; pdb.set_trace()
    print arg

演示基本概念的示例:

    >>> import my_module
    >>> my_module.fun(1)
    > /Users/lukasgraf/src/stackoverflow/my_module.py(3)fun()
    -> print arg
    (Pdb) import sys
    (Pdb) sys._getframe(0)
    <frame object at 0x1032ab290>
    # this is the current frame

    (Pdb) sys._getframe(0).f_globals['__name__']
    'my_module'

    # Next outer frame
    (Pdb) sys._getframe(1).f_globals['__name__']
    'pdb'

    # etc...

    # In this example, frame 10 happens to be
    # the one from the outer interpreter
    (Pdb) sys._getframe(10).f_globals['__name__']
    '__main__'

所以这是一个快速而肮脏的函数,它在堆栈中查找,'__name__'其值为'__main__'in frame globals:

调试助手.py

import sys

# Be safe and define a maximum of frames we're trying to walk up
MAX_FRAMES = 20

def save_to_interactive(dct):
    n = 0
    # Walk up the stack looking for '__name__'
    # with a value of '__main__' in frame globals
    for n in range(MAX_FRAMES):
        cur_frame = sys._getframe(n)
        name = cur_frame.f_globals.get('__name__')
        if name == '__main__':
            # Yay - we're in the stack frame of the interactive interpreter!
            # So we update its frame globals with the dict containing our data
            cur_frame.f_globals.update(dct)
            break

用法:

>>> import my_module
>>> my_module.fun('foo')
> /Users/lukasgraf/src/stackoverflow/my_module.py(3)fun()
-> print arg
(Pdb) import debughelper
(Pdb) debughelper.save_to_interactive({'mykey': 42})
(Pdb) c
foo
# We continued PDB, so we're in the outer interpreter again
>>> print mykey
42
>>>
于 2013-08-08T12:05:12.200 回答