TL;DR:修改bdb.Bdb
,以便将装饰器的模块名称添加到跳过的代码列表中。这适用于两者pdb
,ipdb
可能还有许多其他人。底部的例子。
从我自己的实验pdb.Pdb
(在 pdb 和 ipdb 的情况下实际进行调试的类)看来,它似乎是完全可行的,既不修改要调试的函数的代码也不修改装饰器。
Python 调试器具有可以跳过一些预定义代码的功能。毕竟,调试器必须跳过自己的代码才能发挥作用。
事实上,python 调试器的基类有一个叫做“skip
参数”的东西。它是 it's 的一个参数,它__init__()
指定调试器应该忽略的内容。
来自Python 文档:
如果给定,skip 参数必须是 glob 样式的模块名称模式的可迭代。调试器不会单步执行源自与这些模式之一匹配的模块的帧。框架是否被认为源自某个模块由框架全局变量中的 __name__ 确定。
这样做的问题是它是在对 的调用中指定的set_trace()
,之后我们已经进入装饰器的框架,在休息时。因此,没有任何功能可以让我们在运行时添加到该参数。
幸运的是,在 Python 中在运行时修改现有代码很容易,并且我们可以使用一些技巧来在Bdb.__init__()
调用时添加装饰器的模块名称。我们可以“装饰”Bdb
类,这样每当有人创建Bdb
对象时,我们的模块就会被添加到跳过列表中。
所以,这里就是一个例子。请原谅奇怪的签名和用法,Bdb.__init__()
而不是super()
- 为了与pdb
我们必须这样做兼容:
# magic_decorator.py
import bdb
old_bdb = bdb.Bdb
class DontDebugMeBdb(bdb.Bdb):
@classmethod
def __init__(cls, *args, **kwargs):
if 'skip' not in kwargs or kwargs['skip'] is None:
kwargs['skip'] = []
kwargs['skip'].append(__name__)
old_bdb.__init__(*args, **kwargs)
@staticmethod
def reset(*args, **kwargs):
old_bdb.reset(*args, **kwargs)
bdb.Bdb = DontDebugMeBdb
def dont_debug_decorator(func):
print("Decorating {}".format(func))
def decorated():
"""IF YOU SEE THIS IN THE DEBUGER - YOU LOST"""
print("I'm decorated")
return func()
return decorated
# buged.py
from magic_decorator import dont_debug_decorator
@dont_debug_decorator
def debug_me():
print("DEBUG ME")
ipdb.runcall
在 Ipython 中的输出:
In [1]: import buged, ipdb
Decorating <function debug_me at 0x7f0edf80f9b0>
In [2]: ipdb.runcall(buged.debug_me)
I'm decorated
--Call--
> /home/mrmino/treewrite/buged.py(4)debug_me()
3
----> 4 @dont_debug_decorator
5 def debug_me():
ipdb>