719*_*016 15 python debugging perl breakpoints conditional-execution
在PEP 553 breakpoint()实用程序之前的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";
Run Code Online (Sandbox Code Playgroud)
如果我将此代码运行为:perl code.pl,它将运行完成。如果我使用以下代码运行该代码:perl -d code.pl,pdb它将在断点行处停止(而不是在带有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
Run Code Online (Sandbox Code Playgroud)
然后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;
Run Code Online (Sandbox Code Playgroud)
下面的语句pdb.set_trace()是为了使我能够与Perl 1;之后的同一行中的功能相同$DB::single=1;,这是使调试器停止我放置断点的位置,而不是下一条语句。这样,如果在它们之间有大量的注释代码或文档,调试器将不会跳转到远离断点的下一条语句。
或条件如下:
if args.debug or debug:
import pdb; pdb.set_trace()
_debug=False; #args.debug=False
Run Code Online (Sandbox Code Playgroud)
这样,如果我完成了脚本调试,便可以设置args.debug=False或debug=False不必触摸代码中的所有这些断点。
与perl相同,可以与python一起运行-d以设置调试标志:
$ python --help
[...]
-d : debug output from parser; also PYTHONDEBUG=x
[...]
Run Code Online (Sandbox Code Playgroud)
您可以通过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
Run Code Online (Sandbox Code Playgroud)
它允许以下一线式启用调试:
import pdb, sys; pdb.set_trace() if sys.flags[0] else None
Run Code Online (Sandbox Code Playgroud)
关于这部分
[...]一旦我很高兴它不需要在其他任何地方停止,然后执行[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
Run Code Online (Sandbox Code Playgroud)
但据我测试,除非您使用其他标志运行python,否则以下工作可停用后续跟踪,而不会改变程序的其他行为:
import sys; sys.flags = [0]*len(sys.flags) # even fits onto a single line
Run Code Online (Sandbox Code Playgroud)
如果您要使用一个稍微更健壮的猴子补丁,以防前一个补丁导致奇怪的错误,则需要具有以下内容:
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:])
Run Code Online (Sandbox Code Playgroud)
虽然此语句可以放在一行上,但可能有点太多。您可以将该函数粘贴到.py计划使用它的文件中,或者utils.py在调试期间从中导入该函数,然后ac(ontinue)应该再次运行程序的其余部分:
(Pdb) import utils; utils.untrace()
(Pdb) c
Run Code Online (Sandbox Code Playgroud)
.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
Run Code Online (Sandbox Code Playgroud)
.pdbrc:
r
Run Code Online (Sandbox Code Playgroud)
会话示例:
$ 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
$
Run Code Online (Sandbox Code Playgroud)