如何从PDB导出变量?

15 投票
4 回答
6399 浏览
提问于 2025-04-17 15:46

想象一下这样的场景:你在IPython的命令行中启动了一个脚本,然后在某个断点时调用了Python的调试器。通过使用调试器的命令,你可以分析此时的代码和变量。但是,很多时候你会发现变量的值需要更深入的研究。

那么,有没有办法把一个变量的值导出到IPython的命令行呢?

我具体的需求是:我正在处理一个相当大的numpy数组,但它似乎没有正确的值。我知道我可以在调试器中运行任何Python命令,但如果能在不同的断点保存变量的值,并在IPython命令行中使用这些值,那就太好了。我想象的效果是这样的:

ipdb> global var1; var1 = var
ipdb> continue
...
ipdb> global var2; var2 = var
ipdb> continue
... 
In [2]: abs(var1 - var2) # do some interesting calculations with IPython

4 个回答

6

你需要区分不同的 globals()
比如说,我们有一个模块:mymodule.py

foo = 100
def test():
    bar = 200
    return bar

我们在 pdb 的控制下运行它。

>>> import pdb
>>> import mymodule
>>> foobar = 300
>>> pdb.run('mymodule.test()')
> <string>(1)<module>()
(Pdb) print foobar
300
(Pdb) print foo
*** NameError: name 'foo' is not defined
(Pdb) global foobar2; foobar2 = 301
(Pdb) print foobar2
301

一开始,也就是在执行 test() 之前,pdb 中的环境是你当前的 globals()。所以 foobar 是定义过的,而 foo 是没有定义的。
接着我们执行 test(),并在 bar = 200 的最后停下。

-> bar = 200
(Pdb) print bar
200
(Pdb) print foo
100
(Pdb) print foobar
*** NameError: name 'foobar' is not defined
(Pdb) global foo2; foo2 = 101
(Pdb) print foo2
101
(Pdb) c
>>> 

此时,pdb 中的环境发生了变化。它使用的是 test() 中的 mymoduleglobals()。因此,foobar 现在没有定义,而 foo 是定义过的。

我们已经导出了两个变量 foobar2foo2,但是它们存在于不同的作用域中。

>>> foobar2
301
>>> mymodule.foobar2

Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    mymodule.foobar2
AttributeError: 'module' object has no attribute 'foobar2'
>>> mymodule.foo2
101
>>> foo2

Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    foo2
NameError: name 'foo2' is not defined

你已经找到了解决方案。不过它的工作方式稍微有点不同。

7

这不是一个很优雅的解决方案,但它能正常工作:

ipdb> import cPickle; f=open('/tmp/dump1','w+'); cPickle.dump(var,f); f.close()

...

ipdb> import cPickle; f=open('/tmp/dump2','w+'); cPickle.dump(var,f); f.close()

然后

In [2]: var1 = cPickle.load(open('/tmp/dump1'))
In [3]: var2 = cPickle.load(open('/tmp/dump2'))
16

你可以使用globals()这个函数:

ipdb>__name__
'my_module'
ipdb> get_var = 'a value'
ipdb> globals()['myvar'] = get_var
ipdb> q
In [11]: my_module.myvar
Out[11]: 'a value'

这里假设你在my_module.py这个文件里设置了一个断点,所以我们是在修改my_module这个模块的全局变量。

撰写回答