連載
» 2018年06月05日 05時00分 公開

VS CodeでPythonコードのデバッグも楽々!!Visual Studio Codeで始めるPythonプログラミング(3/4 ページ)

[かわさきしんじ,Insider.NET編集部]

ブレークポイントと[デバッグ]ビューの各種ウィンドウを利用したステップ実行

 本稿の冒頭では、関数fib1と関数fib2とで出力結果が異なることを示した。「0番目のフィボナッチ数」を「0」とするか「1」とするかの差なので、あまり気にする必要もないのだが、ここでは関数fib1と同様な結果が得られるようにしてみよう。そのためには、関数fib2の動作を検証する必要がある。そこで、関数fib2の本体(の先頭)にブレークポイントを設定しよう。これには、ブレークポイントを設定したい行の左端をマウスでクリックする。

ブレークポイントの設定 ブレークポイントの設定

 ブレークポイントを設定すると、その行の左端に赤い円が表示されるとともに、[デバッグ]ビューの[ブレークポイント]ウィンドウには設定したブレークポイントが追加される。チェックボックスのオン/オフで、ブレークポイントを有効/無効に切り替えられるので、「このブレークポイントを解除したくはないけれど、差し当たってのデバッグでは不要」といったときには無効にしておこう。

 ブレークポイントを設定したら、[デバッグの開始]ボタンをクリックして、デバッグ実行を開始する。先ほど、stopOnEntry項目をtrueにしたので、一度実行が中断するが、そのまま[続行]ボタンをクリックしよう。すると、先ほど設定したブレークポイントで実行が中断する。

関数fib2を呼び出したところで実行が中断した 関数fib2を呼び出したところで実行が中断した

 ここで最初に注目しておきたいのは、[デバッグ]ビューの[変数]ウィンドウと[コール スタック]ウィンドウの2つだ。前者にはこの関数で定義されるローカル変数の値と、関数に渡された実引数の値が表示されている。ローカル変数は定義前なので「undefined」であり、パラメーターnに渡された実引数の値は「0」となっている。

[変数]ウィンドウ [変数]ウィンドウ

 これはforループで0〜9の範囲の整数x(range(10))に対して「fib2(x)」のようにして、関数fib2を呼び出しているからだ。ということが、[デバッグ]ビューの[コール スタック]ウィンドウを見ると分かる。

[コール スタック]ウィンドウ [コール スタック]ウィンドウ

 このウィンドウには、関数の呼び出しスタックが表示される。ここでは、このPythonモジュールから関数fib2が呼び出されたことが分かる。各項目をクリックすることで、エディタでは対応する行にカーソルが移動するので、呼び出された関数と、それを呼び出した位置の関係が一目で把握できるはずだ。

 では、ステップオーバーをしてみよう。これにより、変数n0と変数n1に初期値となる0と1がそれぞれ代入される。変数の値は、エディタ上でマウスカーソルを合わせればポップアップされる(もちろん、[変数]ウィンドウを見ても分かる)。

変数の値も簡単にポップアップ表示できる(赤枠内) 変数の値も簡単にポップアップ表示できる(赤枠内)

 さらにステップオーバーを進める。ここでは[ステップ オーバー]ボタンを一度押しただけで、「return n1」行にカーソルが進んでしまった。

ステップオーバーにより、for文のボディーが実行されずに次の行まで進んでしまった ステップオーバーにより、for文のボディーが実行されずに次の行まで進んでしまった

 これは「for cnt in range(n)」の「range(n)」に指定しているnが0だからだ。試しに、「デバッグコンソール」で「range(0)」がどうなるかを見てみよう。まず、[デバッグ]ビューの上部にある[デバッグ コンソール]ボタンをクリックするか、統合ターミナルで[デバッグ コンソール]タブを選択する(上の画像では[…]をクリックすると、これが表示される)。

デバッグコンソールを表示したところ デバッグコンソールを表示したところ

 デバッグコンソールには、これまでのプログラムの出力が表示されている。と同時に、一番下には入力を受け付ける部分があるので、ここに「range(0)」や「[x for x in range(0)]」などと入力してみよう。

デバッグコンソールでのちょっとしたPythonコードのテスト デバッグコンソールでのちょっとしたPythonコードのテスト

 特に「[x for x in range(0)]」の実行結果を見ると分かるが、つまり、range(0)に対して反復処理を行おうにも要素は取り出せないので、for文のボディーは実行されていない。そして、「return n1」が次に実行される行となったということだ。

 このときの変数n1の値は「1」であり、0番目のフィボナッチ数が「1」になったということだ。詳細は割愛するが、これを修正するには次のようなコードにすればよい(変更前にデバッグ実行を終わらせておこう)。意味論的には「return n0」「return n1」の方が適切かもしれない。

def fib2(n):
  n0, n1 = 0, 1
  if n == 0:
    return 0
  if n == 1:
    return 1
  for cnt in range(n-1):
    n0, n1 = n1, n0 + n1
  return n1

変更後の関数fib2

 単にパラメーターnの値が0なら(0番目のフィボナッチ数を求めているのなら)「0」を、nの値が1なら(1番目のフィボナッチ数を求めているのなら)「1」を返すようにして、後はこれまでと同様にループでn番目のフィボナッチ数を求めるようにしているだけだ。

 コードを修正したら、再度デバッグ実行を開始する。ステップオーバーを何度か繰り返していると、関数fib2の呼び出しまで処理が移動することもあるが構わず実行を繰り返していこう。関数fib2に渡される値が「2」になったところで、forループに処理が進むようになる。ここでステップオーバーをすると、画面は次のようになる。

for文のボディーに実行が移ったところ for文のボディーに実行が移ったところ

 for文ではフィボナッチ数を計算しているが、ここで「ウォッチ式」ウィンドウを使ってみよう。例えば、「n0, n1 = n1, n0 + n1」という代入文では各変数の値はすぐに分かる(ポップアップしてくれる)。だが、「n0 + n1」という式の値は即座には分からない。こうしたときに[ウォッチ式]にこの式を追加するとよい。具体的には、その部分を範囲選択して、右クリックし、コンテキストメニューから[デバッグ: ウォッチに追加]を選択する。

[ウォッチ式]ウィンドウへの式の追加 [ウォッチ式]ウィンドウへの式の追加

 すると、[ウォッチ式]に範囲選択した部分が編集可能な状態で追加される。必要があれば、式の内容を編集して[Enter]キーを押すと、その式の値を監視可能になる。

[ウォッチ式]ウィンドウに追加された式 [ウォッチ式]ウィンドウに追加された式

 式の内容は、式に含まれる項が不可視のときにはエラーとなる。以下に例を示す。これは関数fib2を呼び出す側に制御が移ったところなので、「n0 + n1」というウォッチ式を監視できなくなっているところだ。

スコープ外なのでNameErrorとなっているところ スコープ外なのでNameErrorとなっているところ

 もちろん、このような簡単な計算はデバッグコンソールでも可能だ(画像は割愛)。

 このように、VS CodeとPython拡張機能は、Pythonコードのデバッグに役立つ多くの機能を提供してくれている。本稿では取り上げなかったが、ブレークポイントで実行を中断する際の「条件」を指定することも可能だ。通常時は動作に問題がないが、「変数の値が特定の値のときにだけ失敗する」といった場合には、このような「条件付きブレークポイント」が役に立つはずだ。

 おっと、変数cntが未使用という問題(pylintによる警告)が残っていた。これについては、Pythonプログラマーの皆さんならご存じの通り、変数の名前を「_」にするだけでよい。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。