据我所知,pdb无法识别源代码何时在“运行”之间发生了变化。也就是说,如果我正在调试,注意一个错误,修复该错误,并在pdb中重新运行程序(即不退出pdb),pdb将不会重新编译代码。即使pdb列出了新的源代码,我仍然会调试旧版本的代码。
那么,pdb是否在源更改时不更新已编译的代码?如果没有,有没有办法让它这样做?我希望能够保持单个pdb会话以保持我的断点等。
FWIW,gdb会注意到它正在调试的程序在它下面发生变化,尽管只是重启该程序。这是我试图在pdb中复制的行为。
答案 0 :(得分:4)
以下迷你模块可能有所帮助。如果您在pdb会话中导入它,则可以使用:
pdb> pdbs.r()
随时强制重新加载除 main 之外的所有非系统模块。代码跳过了因为它抛出了ImportError('无法重新初始化内部模块主')异常。
# pdbs.py - PDB support
from __future__ import print_function
def r():
"""Reload all non-system modules, so a pdb restart
will reload anything new
"""
import sys
# This is likely to be OS-specific
SYS_PREFIX = '/usr/lib'
for k, v in sys.modules.items():
if not hasattr(v, '__file__'):
continue
if v.__file__.startswith(SYS_PREFIX):
continue
if k == '__main__':
continue
print('reloading %s [%s]' % (k, v.__file__))
reload(v)
答案 1 :(得分:3)
“在pdb中重新运行程序是什么意思?”如果您导入了一个模块,Python将不会重新读取它,除非您明确要求这样做,即使用reload(module)
。但是,reload
远非防弹(请参阅xreload了解其他策略)。
Python代码重新加载存在很多陷阱。为了更有力地解决您的问题,您可以将pdb包含一个类,该类将断点信息记录到磁盘上的文件中,然后根据命令播放它们。
(对不起,请忽略这个答案的第一个版本;它已经很早了,我没有仔细阅读你的问题。)
答案 2 :(得分:1)
ipdb %autoreload
分机
6.2.0 docs document http://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html#module-IPython.extensions.autoreload:
In [1]: %load_ext autoreload
In [2]: %autoreload 2
In [3]: from foo import some_function
In [4]: some_function()
Out[4]: 42
In [5]: # open foo.py in an editor and change some_function to return 43
In [6]: some_function()
Out[6]: 43
答案 3 :(得分:1)
基于@pourhaus答案(从2014年开始),此食谱使用reload
命令扩展了 pdb++
调试器(预计可在Linux和Windows上运行, Python安装)。
提示:新的reload
命令接受可选的模块前缀列表,以重新加载(和 exclude ),而不会破坏已加载的 globals 恢复调试。
只需将以下 Python-3.6 代码插入您的~/.pdbrc.py
文件中即可:
## Augment `pdb++` with a `reload` command
#
# See https://stackoverflow.com/questions/724924/how-to-make-pdb-recognize-that-the-source-has-changed-between-runs/64194585#64194585
from pdb import Pdb
def _pdb_reload(pdb, modules):
"""
Reload all non system/__main__ modules, without restarting debugger.
SYNTAX:
reload [<reload-module>, ...] [-x [<exclude-module>, ...]]
* a dot(`.`) matches current frame's module `__name__`;
* given modules are matched by prefix;
* any <exclude-modules> are applied over any <reload-modules>.
EXAMPLES:
(Pdb++) reload # reload everything (brittle!)
(Pdb++) reload myapp.utils # reload just `myapp.utils`
(Pdb++) reload myapp -x . # reload `myapp` BUT current module
"""
import importlib
import sys
## Derive sys-lib path prefix.
#
SYS_PREFIX = importlib.__file__
SYS_PREFIX = SYS_PREFIX[: SYS_PREFIX.index("importlib")]
## Parse args to decide prefixes to Include/Exclude.
#
has_excludes = False
to_include = set()
# Default prefixes to Exclude, or `pdb++` will break.
to_exclude = {"__main__", "pdb", "fancycompleter", "pygments", "pyrepl"}
for m in modules.split():
if m == "-x":
has_excludes = True
continue
if m == ".":
m = pdb._getval("__name__")
if has_excludes:
to_exclude.add(m)
else:
to_include.add(m)
to_reload = [
(k, v)
for k, v in sys.modules.items()
if (not to_include or any(k.startswith(i) for i in to_include))
and not any(k.startswith(i) for i in to_exclude)
and getattr(v, "__file__", None)
and not v.__file__.startswith(SYS_PREFIX)
]
print(
f"PDB-reloading {len(to_reload)} modules:",
*[f" +--{k:28s}:{getattr(v, '__file__', '')}" for k, v in to_reload],
sep="\n",
file=sys.stderr,
)
for k, v in to_reload:
try:
importlib.reload(v)
except Exception as ex:
print(
f"Failed to PDB-reload module: {k} ({v.__file__}) due to: {ex!r}",
file=sys.stderr,
)
Pdb.do_reload = _pdb_reload
答案 4 :(得分:0)
我决定在输入脚本中以及之后添加一些注释
(Pdb) run
我让pdb意识到了这一变化。不好的事情:它从一开始就运行脚本。下面的好东西。
(Pdb) help run
run [args...]
Restart the debugged python program. If a string is supplied
it is split with "shlex", and the result is used as the new
sys.argv. History, breakpoints, actions and debugger options
are preserved. "restart" is an alias for "run".