デバッグ方法の比較 breakpoint関数の基本 基本的な使い方 デバッガが起動したら pdbの基本コマンド ナビゲーションコマンド 情報表示コマンド 実行例 ブレークポイントの制御 動的なブレークポイント設定 条件付きbreakpoint プログラム的な条件付きブレーク 環境変数による制御 PYTHONBREAKPOINT環境変数 プログラム内での制御 sys.breakpointhookのカスタマイズ 実践的なデバッグパターン 例外発生箇所の調査 事後デバッグ(Post-mortem debugging) ループのデバッグ 再帰関数のデバッグ クラスメソッドのデバッグ デバッグのベストプラクティス 本番環境での無効化 ロギングとの併用 デバッグ用ヘルパー関数 IDE統合 VS Code PyCharm 注意点 本番コードからの削除 grepで検索して削除 まとめ 参考文献 Pythonのbreakpoint()関数は、コードの実行を一時停止し、インタラクティブなデバッガを起動するための組み込み関数です。Python 3.7以降で導入され、従来のpdb.set_trace()よりも柔軟で使いやすいデバッグ方法を提供します。
デバッグ方法の比較
方法 Python 特徴 推奨度 breakpoint()3.7+ 環境変数で柔軟に制御可能 ⭐⭐⭐ pdb.set_trace()全て 従来の標準的な方法 ⭐⭐ import pdb; pdb.pm()全て 事後デバッグ用 ⭐⭐ IDE デバッガ - GUIで直感的 ⭐⭐⭐
breakpoint関数の基本
基本的な使い方
def calculate_total (items: list ) -> int :
"""商品の合計金額を計算"""
total = 0
for item in items:
price = item[ 'price' ]
quantity = item[ 'quantity' ]
subtotal = price * quantity
breakpoint () # ここで実行が停止
total += subtotal
return total
# 使用例
items = [
{ 'name' : 'りんご' , 'price' : 100 , 'quantity' : 3 },
{ 'name' : 'みかん' , 'price' : 80 , 'quantity' : 5 },
]
result = calculate_total(items)
デバッガが起動したら
> /path/to/script.py( 10 ) calculate_total ()
- > total += subtotal
( Pdb ) p item
{ 'name' : 'りんご', 'price': 100, 'quantity': 3 }
( Pdb ) p subtotal
300
( Pdb ) p total
0
( Pdb ) c # 続行
pdbの基本コマンド
ナビゲーションコマンド
コマンド 省略形 説明 nextn次の行へ(関数内に入らない) steps次の行へ(関数内に入る) continuec次のbreakpointまで実行 returnr現在の関数を抜けるまで実行 untilunt指定行まで実行 quitqデバッガを終了
情報表示コマンド
コマンド 省略形 説明 print exprp expr式の値を表示 pp expr式の値をpretty print listl現在位置周辺のコードを表示 longlistll現在の関数全体を表示 wherewスタックトレースを表示 argsa現在の関数の引数を表示
実行例
def debug_example ():
x = 10
y = 20
breakpoint ()
z = x + y
return z
# 実行すると...
# (Pdb) l # 現在位置のコードを表示
# 1 def debug_example():
# 2 x = 10
# 3 y = 20
# 4 -> breakpoint()
# 5 z = x + y
# 6 return z
# (Pdb) p x # 変数xの値を表示
# 10
# (Pdb) p x + y # 式を評価
# 30
# (Pdb) n # 次の行へ
# > (5)debug_example()
# -> z = x + y
# (Pdb) p z # まだ定義されていない
# *** NameError: name 'z' is not defined
# (Pdb) n # もう一度次へ
# (Pdb) p z # これで定義された
# 30
ブレークポイントの制御
動的なブレークポイント設定
# デバッガ内でブレークポイントを設定
# (Pdb) break 10 # 10行目にブレークポイント
# (Pdb) break function_name # 関数の先頭にブレークポイント
# (Pdb) break file.py:20 # 別ファイルの20行目に
# (Pdb) break 10, x > 5 # 条件付きブレークポイント
# ブレークポイントの確認と削除
# (Pdb) break # 全ブレークポイントを表示
# (Pdb) clear 1 # ブレークポイント1を削除
# (Pdb) disable 1 # ブレークポイント1を無効化
# (Pdb) enable 1 # ブレークポイント1を有効化
条件付きbreakpoint
def process_items (items: list ) -> list :
"""アイテムを処理"""
results = []
for i, item in enumerate (items):
# 特定の条件でのみ停止
if item < 0 :
breakpoint () # 負の値のときだけ調査
results.append(item * 2 )
return results
# 使用例
data = [ 1 , 2 , - 3 , 4 , - 5 ]
process_items(data)
プログラム的な条件付きブレーク
import sys
def conditional_break (condition: bool = True ):
"""条件に応じてbreakpointを呼び出す"""
if condition:
breakpoint ()
def process_data (data: list ):
for item in data:
# デバッグモードのときだけ停止
conditional_break( '--debug' in sys.argv)
print ( f "Processing: { item } " )
環境変数による制御
PYTHONBREAKPOINT環境変数
# デフォルト(pdbを使用)
python script.py
# breakpoint()を無効化
PYTHONBREAKPOINT = 0 python script.py
# ipdbを使用(事前にpip install ipdbが必要)
PYTHONBREAKPOINT = ipdb.set_trace python script.py
# pudbを使用(事前にpip install pudbが必要)
PYTHONBREAKPOINT = pudb.set_trace python script.py
# カスタム関数を使用
PYTHONBREAKPOINT = mymodule.custom_debugger python script.py
プログラム内での制御
import sys
import os
def setup_debug_mode (enable: bool = True ):
"""デバッグモードを設定"""
if enable:
# デフォルトのpdbを使用
os.environ.pop( 'PYTHONBREAKPOINT' , None )
else :
# breakpointを無効化
os.environ[ 'PYTHONBREAKPOINT' ] = '0'
# 使用例
setup_debug_mode( False ) # 本番環境
breakpoint () # 何も起きない
setup_debug_mode( True ) # 開発環境
breakpoint () # pdbが起動
sys.breakpointhookのカスタマイズ
import sys
def custom_breakpoint ( * args, ** kwargs):
"""カスタムブレークポイント処理"""
print ( "=" * 50 )
print ( "デバッグモードに入りました" )
print ( f "引数: args= { args } , kwargs= { kwargs } " )
print ( "=" * 50 )
# 元のpdbを呼び出す
import pdb
pdb.set_trace()
# カスタムフックを設定
sys.breakpointhook = custom_breakpoint
# 使用例
def test_function ():
x = 10
breakpoint () # カスタムメッセージが表示される
return x
test_function()
実践的なデバッグパターン
例外発生箇所の調査
def risky_operation (data: dict ) -> str :
"""例外が発生する可能性のある処理"""
try :
result = data[ 'key' ][ 'nested' ]
return str (result)
except ( KeyError , TypeError ) as e:
# 例外発生時にデバッグ
breakpoint ()
raise
# 使用例
try :
risky_operation({ 'key' : None })
except :
pass
事後デバッグ(Post-mortem debugging)
import pdb
def failing_function ():
x = [ 1 , 2 , 3 ]
return x[ 10 ] # IndexError
# 方法1: tryで囲む
try :
failing_function()
except :
pdb.post_mortem() # 例外発生時点の状態でデバッグ
# 方法2: -mオプション
# python -m pdb script.py
# 例外発生時に自動的にデバッガが起動
ループのデバッグ
def find_anomaly (data: list ) -> list :
"""異常値を検出"""
anomalies = []
for i, value in enumerate (data):
is_anomaly = value > 100 or value < 0
# 異常値を見つけたときだけ停止
if is_anomaly:
print ( f "異常値を検出: index= { i } , value= { value } " )
breakpoint ()
anomalies.append((i, value))
return anomalies
# 使用例
data = [ 10 , 20 , 150 , 30 , - 5 , 40 ]
find_anomaly(data)
再帰関数のデバッグ
def factorial (n: int , depth: int = 0 ) -> int :
"""階乗を計算(デバッグ付き)"""
indent = " " * depth
# 特定の深さで停止
if depth == 3 :
print ( f " { indent } depth=3に到達" )
breakpoint ()
if n <= 1 :
return 1
result = n * factorial(n - 1 , depth + 1 )
return result
# 使用例
factorial( 5 )
クラスメソッドのデバッグ
class DataProcessor :
"""データ処理クラス"""
def __init__ (self, data: list ):
self .data = data
self .processed = False
def process (self) -> list :
"""データを処理"""
results = []
for item in self .data:
# 処理の途中経過を確認
transformed = self ._transform(item)
if transformed is None :
breakpoint () # 変換失敗を調査
results.append(transformed)
self .processed = True
return results
def _transform (self, item):
"""アイテムを変換"""
if isinstance (item, ( int , float )):
return item * 2
return None
# 使用例
processor = DataProcessor([ 1 , 2 , "invalid" , 4 ])
processor.process()
デバッグのベストプラクティス
本番環境での無効化
import os
# 方法1: 環境変数で制御
DEBUG = os.getenv( 'DEBUG' , 'false' ).lower() == 'true'
def debug_break ():
"""デバッグ環境でのみbreakpoint"""
if DEBUG :
breakpoint ()
# 方法2: 設定ファイルで制御
class Config :
DEBUG = False
def safe_breakpoint ():
if Config. DEBUG :
breakpoint ()
ロギングとの併用
import logging
logging.basicConfig( level = logging. DEBUG )
logger = logging.getLogger( __name__ )
def debug_with_logging (data: dict ):
"""ロギングとデバッグを併用"""
logger.debug( f "入力データ: { data } " )
try :
result = process(data)
logger.debug( f "処理結果: { result } " )
return result
except Exception as e:
logger.error( f "エラー発生: { e } " )
breakpoint () # エラー時にデバッグ
raise
def process (data: dict ) -> str :
return data[ 'key' ]
デバッグ用ヘルパー関数
def debug_info ():
"""デバッグ情報を表示するヘルパー"""
import sys
frame = sys._getframe( 1 )
print ( "=" * 60 )
print ( f "ファイル: { frame.f_code.co_filename } " )
print ( f "関数: { frame.f_code.co_name } " )
print ( f "行番号: { frame.f_lineno } " )
print ( f "ローカル変数: { list (frame.f_locals.keys()) } " )
print ( "=" * 60 )
breakpoint ()
# 使用例
def my_function ():
x = 10
y = 20
debug_info() # 詳細情報を表示してからデバッグ開始
return x + y
IDE統合
VS Code
// launch.json
{
"version" : "0.2.0" ,
"configurations" : [
{
"name" : "Python: Current File" ,
"type" : "python" ,
"request" : "launch" ,
"program" : "${file}" ,
"console" : "integratedTerminal" ,
"justMyCode" : false
}
]
}
PyCharm
PyCharmでは、breakpoint()の代わりにGUIでブレークポイントを設定できます。
ただし、breakpoint()も正常に動作し、PyCharmのデバッガと統合されます。
注意点
本番コードからの削除
# 開発時
def process_data (data):
result = transform(data)
breakpoint () # 開発中のデバッグ
return result
# リリース前に削除
def process_data (data):
result = transform(data)
return result
grepで検索して削除
# breakpointの残存を確認
grep -r "breakpoint()" --include= "*.py" src/
# 自動で削除(注意して使用)
sed -i '/breakpoint()/d' ** / * .py
まとめ
操作 方法 デバッグ開始 breakpoint()無効化 PYTHONBREAKPOINT=0次の行へ n関数内へ s続行 c変数表示 p variable終了 q
breakpoint()関数は、Python 3.7以降で推奨されるデバッグ方法です。環境変数による柔軟な制御が可能で、開発・テスト・本番環境それぞれに適した設定ができます。
参考文献