在3.7版本之前,与Perl的$DB::single=1类似的一行代码,用于 python 条件调试断点的PEP 553版本

2024-04-26 11:18:22 发布

您现在位置:Python中文网/ 问答频道 /正文

在pep553breakpoint()实用程序之前的python版本中,建议使用什么方法添加(理想情况下是一行代码)代码以使断点在某个条件下可以被忽略(例如,全局调试标志或参数调试标志)。在

在Perl中,我习惯于使用$DB::single=1;1;单行,我知道我可以安全地将其保留在代码中,除非显式调用perl -d code.pl,否则不会影响{}的正常运行。E、 g.:

my $a = 1;
$DB::single=1;1; # breakpoint line
my $b = 2;
print "$a $b\n";

如果我以:perl code.pl的形式运行此代码,它将一直运行到完成。 如果我使用:perl -d code.pl运行此代码,pdb将在断点行停止(而不是在下一行使用my $b = 2;语句之前),因为它在$DB::single=1;语句之后包含一个1;语句

同样,如果我写下:

^{pr2}$

然后我可以执行perl -d code.pl,它将在第一个断点行停止,然后在pdb会话中,一旦我很高兴它不需要在任何其他地方停止,然后执行:$debug = 0,然后pdb继续^{{},这将使它不会在代码中的第二个或其他类似的断点行停止。在

在同一行中,如何在553.3中实现python.3语句?在

我知道pep553,除了必须显式地设置PYTHONBREAKPOINT=0 python3.7 code.py或注释掉breakpoint()行的麻烦之外,它是这里问题的解决方案。在

我想到了一些选择,比如:

import pdb; pdb.set_trace()
dummy=None;

pdb.set_trace()下面的语句使我可以实现与Perl中$DB::single=1;后面同一行中的1;相同的操作,即让调试器停止在我放置断点的位置,而不是下一个语句。这样,如果中间有大量带注释的代码或文档,调试器不会跳到离断点很远的下一个语句。在

或附加条件,如:

if args.debug or debug:
    import pdb; pdb.set_trace()
    _debug=False; #args.debug=False

因此,如果我完成了脚本的调试,我可以设置args.debug=False或{},而不必在代码中接触所有这些断点。在


Tags: 代码debugfalsedbmytraceargscode
2条回答

设置条件断点

与perl相同,python可以与-d一起运行以设置调试标志:

$ python  help
[...]
-d     : debug output from parser; also PYTHONDEBUG=x
[...]

您可以在运行时通过sys.flags检查其状态:

^{pr2}$

允许使用以下一个命令行来启用调试:

import pdb, sys; pdb.set_trace() if sys.flags[0] else None

从调试器禁用条件断点

关于这部分

[...] once I am happy that it does not need stopping anywhere else, then execute [something] which will make it not stop at the second or other similar breakpoint lines in the code.

不过,这有点棘手,因为python不允许the ^{} structure的变异,甚至不允许创建它的实例:

>>> import sys
>>> sys.flags.debug = 0                 # no mutating ...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: readonly attribute
>>> type(sys.flags)()                   # ... and no instanciating
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: cannot create 'sys.flags' instances

但就我所测试的情况而言,除非您使用其他标志运行python,否则以下操作可以在不改变程序的其他行为的情况下停用后续跟踪:

import sys; sys.flags = [0]*len(sys.flags)  # even fits onto a single line

对于一个稍微健壮一点的monkey补丁,您应该使用前一个补丁导致奇怪的bug,您需要这样的东西:

def untrace():
  """Call this function in the pdb session to skip debug-only set_trace() calls"""
  import re
  import sys
  from collections import namedtuple  # has the same interface as struct sequence
  sys.flags = namedtuple(
    'sys_flags', 
    [m.group() for m in re.finditer(r'\w{2,}', repr(sys.flags)[10:-1])]
  )(0, *sys.flags[1:])

虽然这句话可以放在一行,但可能有点太多了。您可以将此函数粘贴到您计划使用它的.py文件中,也可以在调试期间从中导入某种{},然后c(继续)应再次运行程序的其余部分:

(Pdb) import utils; utils.untrace()
(Pdb) c

下面是在当前目录中使用.pdbrc文件的简单方法:

t.py

def my_trace():
    global debug
    if debug:
        import pdb; pdb.set_trace()

debug = True
a= 1
my_trace()
b = 2
c = 3
my_trace()
d = 4

.pdbrc

^{pr2}$

示例会话

$ python t.py
 Return 
> [...]/t.py(12)<module>()
-> b = 2
(Pdb) p a
1
(Pdb) p b
*** NameError: name 'b' is not defined
(Pdb) !debug=False
(Pdb) c
$ 

相关问题 更多 >