从python调试器将变量保存到交互式命名空间

Rob*_*uil 4 python debugging namespaces

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

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

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

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

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

>>> debug
ipdb> len(loaded_data)
100000
Run Code Online (Sandbox Code Playgroud)

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

ipdb> save_to_interactive('loaded_data')
ipdb> exit
>>> len(loaded_data)
100000
Run Code Online (Sandbox Code Playgroud)

Luk*_*raf 6

您可以通过获取对外部解释器的堆栈框架的引用,并写入其框架全局变量来实现此目的.

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

my_module.py:

def fun(arg):
    import pdb; pdb.set_trace()
    print arg
Run Code Online (Sandbox Code Playgroud)

演示基本概念的示例:

    >>> 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__'
Run Code Online (Sandbox Code Playgroud)

所以这里有一个快速而又脏的函数,它在堆栈中寻找'__name__'具有'__main__'帧内全局值的值:

debughelper.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
Run Code Online (Sandbox Code Playgroud)

用法:

>>> 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
>>>
Run Code Online (Sandbox Code Playgroud)

  • 这绝对是太棒了,卢卡斯。确实非常感谢:*正是*我想要的,完全解释和编程,而且如此之快!如果可以的话,我会给一颗星以上。 (2认同)