簡體   English   中英

python條件調試斷點單行為3.7 PEP 553之前的版本,其作用類似於Perl的$ DB :: single = 1

[英]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=Falsedebug=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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM