Chapter 09

デバッグ方法

printデバッグから卒業しよう!

プログラムを書いて問題があったとき必要なのがデバッグですね。私はいつも問題が起こったとき、問題ありそうなところで print(xxx)として、気になるものを一つずつ中身を確認していました。「きっともっと良いやり方あるのだろうな」とは思いつつも、ずっとその先に進めずにいました。そんな方多いのではないでしょうか?

そんな方に朗報です。VS Codeエディタには高性能なデバッグ機能が付いているので、以下のようなことが簡単にできます。

  • クリック一発でのプログラムの実行
  • エラーの詳細な情報の確認
  • ソースコードの特定の行で、1行ずつ実行しながら全ての変数の値の変化を確認

これで、バグをとるデバッグ作業の効率が大幅に向上したり、今まで発見できなかったバグの原因が追求できるようになること間違い無しです。

Pythonのデバッグ

拡張機能に関しては、今回はPythonの拡張機能のみを追加して下さい。拡張機能のメニューで「Python」で検索して、InstallとReloadをするだけです。本書の拡張機能の章も参照ください。

次に、適当なプログラムを書いて保存しておきます。今回は、以下のようないかにも入門書に出てきそうなコードを使います。

x = 'hello world'
print(x)

次に、下図の通り、VS Codeのデバッグメニューを開いて、create a launch.json fileを選択します。

続いて、下図のように「Python File」を選択します。

これにより、launch.jsonというファイルが、.vscodeというフォルダ以下に生成されます。このファイルは、デバッグを実行するときに実行されるプログラムの設定を記載した内容となっています。デフォルトでは、以下の通り開いているPythonファイルをデバッグする設定となっています。まずは、このままの内容でデバッグを行います。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal"
        }
    ]
}

デバッグに際して、ブレイクポイントを設定しましょう。下図のように2行目のprint(x)の左側をクリックするとすると、赤丸が表示されます。これがブレイクポイントです。詳細な説明は省きますが、プログラムで詳しく調べたい箇所に設定するのが一般的な使い方です。

いよいよデバッグを実行します。左上の緑の右矢印をクリックするか「F5」ボタンで実行できます。以下のようにデバッグが開始されます。

画面が小さく見づらいかもしれませんが、左の画面のVARIABLESという欄に、x: 'hello world'と表示されています。このようにデバッグ画面には、設定された変数の中身が全て自動的に表示されます。

今まで、問題が起こったら、気になる変数の中身をいちいちprintして表示して確認していた人は多いのではないのでしょうか?VS Codeでデバッグを行えばそのような苦痛からは解放されます。また、コードを修正したら、わざわざコマンドを打たなくても、F5を押すだけでプログラムを実行してデバッグできます。

これだけでも、大幅にデバッグが捗りそうですね。VS Code万歳!

実際に自分が書いたプログラムをデバッグしてみる

サンプルが簡単過ぎるので、次は過去に自分が作った画像処理のプログラムでデバッグを実行してみます。画像処理のプログラムといっても、画像のリサイズをするだけの簡単なものです。プログラムは以下となります。

# -*- coding: utf-8 -*-
import cv2
import sys

def resize(src, w_ratio, h_ratio):
    height = src.shape[0]
    width = src.shape[1]
    dst = cv2.resize(src,((int)(width/100*w_ratio),(int)(height/100*h_ratio)))
    return dst

if __name__ == '__main__':
    param = sys.argv
    if (len(param) != 4):
        print ("Usage: $ python " + param[0] + " sample.jpg wide_ratio height_ratio")
        quit()

    # open image file
    try:
        input_img = cv2.imread(param[1])
    except:
        print ('faild to load %s' % param[1])
        quit()

    if input_img is None:
        print ('faild to load %s' % param[1])
        quit()

    w_ratio = int(param[2])
    h_ratio = int(param[3])

    output_img = resize(input_img, w_ratio, h_ratio)
    cv2.imwrite(param[1], output_img)

元ファイル: https://raw.githubusercontent.com/karaage0703/python-image-processing/master/resize.py

OpenCVなどのライブラリを使用するので、予めPythonのライブラリ等の環境のセットアップが必要です。Pythonの仮想環境のセットアップに関しては以下記事参照ください。

https://karaage.hatenadiary.jp/entry/2016/04/04/073000

仮想環境などを使い、複数のPython環境がある場合は、VS Codeで使用するPythonを選択する必要があります。左下の「Python xxx」と記載されている箇所をクリックします(xxx の箇所は環境によって異なります)。

すると、以下のようにセットアップされているPython環境がずらっと表示されますので、適切な環境を選択しましょう。

また、今回使用するプログラムは、対象のファイルや、リサイズするサイズを引数として必要とするプログラムになっています。具体的には、以下のような形で実行しないと、プログラムのエラー処理ですぐ終了してしまいます。

$ python resize.py test.jpg 50 50

そのような場合はlaunch.jsonファイルを修正します。具体的には、以下のようにPython: resizeという新たなconfigurationsを追加します。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal"
        },
        {
            "name": "Python: resize",
            "type": "python",
            "request": "launch",
            "program": "resize.py",
            "console": "integratedTerminal",
            "args" : ["test.jpg", "50", "50"]
        }
    ]
}

ここで、argsオプションで引数の指定を追加するのがポイントです。

これで、デバッグのConfiguration(デバッグメニューの緑の矢印の右側のウィンドウ)に、設定した「Python: resize」が追加されますので選択してください。これによりresize.pyのデバッグがF5一発で可能となります。

早速デバッグしてみましょう。プログラムの開始部分(param = sys.argv部分) にブレイクポイントを設定して、argvの引数に先ほど設定した引数が入力されていることが確認できます。

続いて、デバッグメニューの下矢印(Step Into)を実行すると、1行ずつデバッグが進みます。

画面細かく見づらいですが、今回のような画像処理プログラムだと、例えばinput_imgといういかにも画像っぽい名前の変数が、どのような型で、どんなサイズなのかから、その生値まで、1つずつprintしなくても自動的に全て表示され、確認することが可能です。

これでprintデバッグから卒業できそうですね!

C++のデバッグ

今回はPythonを例として取り上げましたが、他の言語でも基本的には同じです。ただし、実行する前にビルドが必要なC++のようなコンパイラ言語だと、一手間必要です。C++を使いこなすような人は、自分でできてしまいそうですが、参考になりそうなサイトをいくつか紹介します。

Mac の Visual Studio Codeで C/C++ をデバッグするまで(OSX10.11.6, VSCode1.4.0)

【初心者向け】VSCodeでC++のデバッグができるまで

Visual Studio CodeでC++のデバック環境を手に入れる

基本的には、最低限やることは以下2つで、Pythonと考え方は同じです。

  • ターミナル等でデバッグオプションをつけてビルドする(ex: $ g++ -g test.cpp
  • launch.json の"program" オプションに生成された実行ファイルのパスを指定

C++のようなコンパイラ言語の場合は、いちいちターミナルでビルドするのも面倒です。その場合は、VS Codeでtask.jsonというファイルを設定することで、VS Code上でデバッグオプションをつけたビルドも可能となります。task.jsonの設定方法は、環境によって異なりますので上記の参考サイト等を参考に設定下さい。

気が向いたらもうちょっと詳しく書きます。

まとめ

VS Codeでデバッグをする基本的な方法に関してまとめました。これでprintデバッグから卒業できた!と思います…デバッグに関しては、なかなか独学だと必要性を感じることが少なく、身につけ辛いですし。複雑なデバッグ方法だと、一度覚えても、肝心なときに忘れてしまっていたりして結局printデバッグに逆戻りしてしまったりします。

デバッグ方法は身につけると、バグの修正時だけでなく、通常の開発も効率化しレベルアップできると思います。また、デバッグの表示画面をみると、コンピュータの中でどのようなことが起こっているかが可視化されるのでプログラムへの理解も深まるのではないかなと感じました。

VS Codeを使うことで、簡単かつ効率的にデバッグを行うことができると思いますので、今までなかなかデバッグをできなかった人は一度試してみることをお勧めいたします。

参考リンク

VS CodeでPythonコードのデバッグも楽々!!

VS Code で Python をデバッグする環境構築(+ NumPy, SciPy, Matplotlib を実行する環境構築)

VSCodeでデバッガに引数を渡す方法(Python)