[英]python conditional debug breakpoint one-liner for versions before 3.7 PEP 553 that acts similarly to Perl's $DB::single=1
在PEP 553 breakpoint()
實用程序之前的python版本中,建議添加(理想情況下是單線程)代碼的方法是在條件(例如全局調試標志或args.debug標志)上有一個可以忽略的斷點。
在Perl中,我習慣使用$DB::single=1;1;
單行,我知道我可以安全地留在代碼中,除非顯式調用perl -d code.pl
否則不會影響perl code.pl
的正常運行。 例如:
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;
語句的下一行之前),因為它包含1;
$DB::single=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()
下面的語句是這樣的,我可以實現與1;
相同1;
在$DB::single=1;
之后的同一行$DB::single=1;
在Perl中,將調試器停在我放置斷點的位置,而不是下一個語句。 這樣,如果中間存在大量注釋代碼或文檔,則調試器不會跳轉到遠離斷點的下一個語句。
或者使用以下條件:
if args.debug or debug:
import pdb; pdb.set_trace()
_debug=False; #args.debug=False
因此,如果我完成了腳本的調試,我可以設置args.debug=False
或debug=False
,而不必觸及代碼中的所有這些斷點。
與perl相同,可以使用-d
運行python來設置調試標志:
$ 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
這是在當前目錄中使用.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
$
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.