16

在 PEP 553breakpoint()实用程序之前的 python 版本中,添加(理想情况下是单行)代码以具有可以在条件下忽略的断点的推荐方法是什么(例如,全局调试标志或 args.debug 标志)。

在 Perl 中,我习惯使用$DB::single=1;1;单行,我知道我可以安全地将其留在代码中,并且不会影响正常运行,perl code.pl除非显式调用perl -d code.pl. 例如:

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

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

同样,如果我写:

my $debug = 1;
my $a = 1;
$DB::single=$debug;1; # first breakpoint line
my $b = 2;
$DB::single=$debug;1; # second breakpoint line
print "$a $b\n";
# [...] Lots more code sprinkled with more of these
$DB::single=$debug;1; # n'th breakpoint line

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

我怎样才能在python(PEP 553之前的2.x和3.x)中实现相同的目标,理想情况下是单行语句?

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

我想到了以下选项:

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

下面的语句pdb.set_trace()是为了让我可以在 Perl1;之后的同一行中实现相同的$DB::single=1;效果,即让调试器停止我放置断点的位置,而不是下一条语句。这样如果中间有大块的注释代码或文档,调试器就不会跳转到离断点很远的下一条语句。

或使用以下条件:

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

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

4

2 回答 2

7

设置条件断点

与 perl 一样,可以运行 python-d来设置调试标志:

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

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

$ python -d
Python 2.7.15+ (default, Nov 27 2018, 23:36:35) 
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.flags
sys.flags(debug=1, py3k_warning=0, division_warning=0, ...)
#         ^ there it is, right at the front

这允许以下单行启用调试:

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

从调试器禁用条件断点

关于这部分

[...] 一旦我很高兴它不需要在其他任何地方停止,然后执行 [something] 这将使它不会在代码中的第二个或其他类似的断点行处停止。

不过它变得有点棘手,因为 python 不允许结构flags突变,甚至不允许创建它的实例:

>>> 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

对于一个更强大的猴子补丁,你应该使用它以防前一个导致奇怪的错误,你需要有这样的东西:

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您计划使用它的文件中,或者在调试期间从其中导入某种函数utils.py,之后 ac(ontinue) 应该再次运行程序的其余部分:

(Pdb) import utils; utils.untrace()
(Pdb) c
于 2019-06-18T18:38:47.887 回答
4

.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

r

示例会话

$ 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
$ 
于 2019-06-16T17:25:57.013 回答