ブレークポイント - python デバッグ




IPythonによるステップバイステップのデバッグ (9)

(2016年5月28日更新)EmacsでのRealGUDの使用

Emacsの誰かのために、 github.com/rocky/emacs-dbgr/issues/96は、OPで記述されたすべてのものを達成する方法を示しています。

  1. Emacsの新しい重要なデバッガで、任意のデバッガ( ipdbを含む)で動作できるRealGUDと呼ばれています。
  2. Emacsパッケージはisend-mode

これら2つのパッケージの組み合わせは非常に強力で、OPに記述されている動作を正確に再現することができます。

ipdb用のRealGUD に関するwiki記事の詳細。

元の答え:

このスレッドで言及されているものを含め、Pythonのデバッグにさまざまな方法を試した後、PythonとIPythonをデバッグするための私の好みの方法の1つは、組み込みシェルです。

カスタム組み込みIPythonシェルを定義する:

スクリプトの次の行をPYTHONPATHに追加して、 ipsh()メソッドを使用できるようにします。

import inspect

# First import the embed function
from IPython.terminal.embed import InteractiveShellEmbed
from IPython.config.loader import Config

# Configure the prompt so that I know I am in a nested (embedded) shell
cfg = Config()
prompt_config = cfg.PromptManager
prompt_config.in_template = 'N.In <\\#>: '
prompt_config.in2_template = '   .\\D.: '
prompt_config.out_template = 'N.Out<\\#>: '

# Messages displayed when I drop into and exit the shell.
banner_msg = ("\n**Nested Interpreter:\n"
"Hit Ctrl-D to exit interpreter and continue program.\n"
"Note that if you use %kill_embedded, you can fully deactivate\n"
"This embedded instance so it will never turn on again")   
exit_msg = '**Leaving Nested interpreter'

# Wrap it in a function that gives me more context:
def ipsh():
    ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg)

    frame = inspect.currentframe().f_back
    msg   = 'Stopped at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame)

    # Go back one level! 
    # This is needed because the call to ipshell is inside the function ipsh()
    ipshell(msg,stack_depth=2)

次に、コード内で何かをデバッグしたいときは、オブジェクト検査などが必要な場所にipsh()を置きます。たとえば、以下のmy_functionをデバッグしたいとします。

それを使う:

def my_function(b):
  a = b
  ipsh() # <- This will embed a full-fledged IPython interpreter
  a = 4

次のいずれかの方法でmy_function(2)を呼び出します。

  1. Unixシェルからこの関数を呼び出すPythonプログラムを実行するか
  2. または、IPythonから直接呼び出す

私がどのように呼び出すかにかかわらず、インタプリタはipsh()という行で停止します。 完了したら、 Ctrl-Dを実行して、Pythonが実行を再開します(変数の更新があれば)。 通常のIPythonのIPythonシェル(上記のケース2)からコードを実行すると、新しいIPythonシェルが呼び出されたシェルの中にネストされますが、これは完全にうまくいきますが、認識しておくとよいでしょう。 いずれにしても、インタプリタがipshの位置で停止すると、 aの値を検査し( 2 )、定義されている関数とオブジェクトを確認することができます。

問題:

上記のソリューションを使用すると、コード内でどこでもPythonを停止させ、本格的なIPythonインタプリタに入れることができます。 残念ながら、スクリプトを呼び出すとブレークポイントを追加したり削除したりすることはできません。非常にイライラします。 私の意見では、これはIPythonがPython用の優れたデバッグツールにならないようにする唯一の方法です。

あなたが今できるベスト:

回避策は、PythonインタプリタにIPythonシェル( breakpoint )を起動させたい異なる場所にipsh()を先験的に配置することです。 Ctrl-DCtrl-D 、現在の組み込みIPythonシェルを終了し、インタプリタがipsh()次の呼び出しを呼び出すたびに再び停止して、別のあらかじめ定義されたハードコーディングされた "ブレークポイント"を "ジャンプ"できます。

このルートを「デバッグモード」を終了し、後続のブレークポイントをすべて無視する方法の1つは、 ipshell.dummy_mode = Trueを使用して、上で作成したipshellオブジェクトの後続のインスタンス化をPythonが無視するようにすることです。

私が読んだことから、Pythonでコードをデバッグするには2つの方法があります:

  • pdbipdbような伝統的なデバッガをipdb 。 これは、 continueためのcstep-over nstep-over sためsなどのコマンドをサポートしますcontinue 、オブジェクト検査に非常に役立つIPythonシェルに直接アクセスすることはできません。

  • あなたのコードにIPythonシェルをembeddingによってIPythonを使用する。 あなたはfrom ipython import embed 、あなたのコードでembed()を使うことができます。 あなたのプログラム/スクリプトがembed()ステートメントにヒットすると、あなたはIPythonシェルにドロップされます。 これにより、オブジェクトの完全な検査と、すべてのIPython製品を使用したPythonコードのテストが可能になります。 しかし、 embed()を使用するときは、便利なキーボードショートカットを使用してコードをステップバイステップで実行することはできません。

両方の世界のベストを組み合わせる方法はありますか? すなわち

  1. 便利なpdb / ipdbキーボードショートカットを使用してコードを段階的に実行できるようになります。
  2. そのようなステップ(例えば、あるステートメント)で、本格的なIPythonシェルにアクセスしてください。

MATLABのように IPythonのデバッグ:

このタイプの「拡張デバッギング」の例は、ユーザーが常に MATLABエンジン/シェルにフルアクセスできるMATLABにあり、コードをステップバイステップで実行したり、条件付きブレークポイントを定義したりすることができます。私が他のユーザーと議論したことは、MATLABからIPythonに移行する際に人々が最も忘れるデバッグ機能です。

Emacsや他のエディタでのIPythonのデバッグ:

質問をあまりにも具体的にしたくないのですが、私は主にEmacsで作業していますので、この機能を使用する方法があるのだろうかと思います。 理想的には 、Emacs(またはエディタ)は、プログラマーがコードのどこにでもブレークポイントを設定し、インタプリタまたはデバッガと通信して、選択した場所で停止させ、その場所で完全なIPythonインタプリタを呼び出すことができれば理想的です。


"!"の接頭辞 あなたがpdbに入力するコマンドへのシンボルは、IPythonシェルで何かをするのと同じ効果を持つようです。 これは、特定の関数、または変数名のヘルプにアクセスするために機能します。 たぶん、これはある程度あなたを助けるでしょう。 例えば、

ipdb> help(numpy.transpose)
*** No help on (numpy.transpose)

しかし!help(numpy.transpose)はnumpy.transposeのヘルプページを表示します。 同様に変数名の場合、変数lがあり、pdbに "l"と入力するとコードがリストされますが、!lはlの値を出力します。


@ gaborousの答えが非難されているようです

新しいアプローチは次のように思われます:

from IPython.core import debugger
debug = debugger.Pdb().set_trace

def buggy_method():
    debug()

EmacsのIPython-shellとpdb.set_trace()で設定したブレークポイントの中から実行すると効果があります。

python-mode.el、Mx ipython RETなどでチェック


Python 3.2からは、 interactコマンドがあり、完全なpython / ipythonコマンド・スペースにアクセスできます。


embed()コンソールでexit()と入力すると、コードは続行され、次のembed()行に移動します。


このヒントを試しましたか?

それとも、ipythonを使って呼び出しても良いでしょう:

from IPython.Debugger import Tracer; debug_here = Tracer()

あなたはちょうど使用することができます

debug_here()

ブレークポイントを設定したいときはいつでも


Pyzo IDEには、OPと似た機能があります。 デバッグモードで起動する必要はありません。 MATLABと同様に、コマンドはシェルで実行されます。 いくつかのソースコード行にブレークポイントを設定すると、IDEはそこでの実行を停止し、通常のIPythonコマンドもデバッグして発行することができます。

しかし、別のブレークポイントを設定しない限り、step-intoは(まだ?)うまく動作していないようです(つまり、1行で停止してから別の関数にステップインします)。

それでも、MATLABから来て、これは私が見つけた最高の解決策のようです。


質問に対する正しい、簡単な、クールで正確な答えは、%runマクロを-dフラグとともに使用することです。

In [4]: run -d myscript.py
NOTE: Enter 'c' at the ipdb>  prompt to continue execution.        
> /cygdrive/c/Users/mycodefolder/myscript.py(4)<module>()
      2                                                            
      3                        
----> 4 a=1                                            
      5 b=2




pdb