Python {Article104}

ようこそ「Python」へ...

Pythonのプログラムをデバッグするには [Python, Debugging]

ここではPythonのプログラムをデバッグする方法について解説します。 Pythonのプログラムに不具合(バグ)があるときは、通常print()などでデバッグ情報を表示させてバグ(bug)を見つけます。 ここでは3種類の方法でバグを見つける方法を紹介します。

この記事ではMicrosoftのVisual Studio Code(VS Code)を使用していますが、Jupyter NotebookなどのツールでもOKです。 説明文の左側に図の画像が表示されていますが縮小されています。 画像を拡大するにはマウスを画像上に移動してクリックします。 画像が拡大表示されます。拡大された画像を閉じるには右上の[X]をクリックします。 画像の任意の場所をクリックして閉じることもできます。
click image to zoom!
図A:
click image to zoom!
図B:
click image to zoom!
図C:
click image to zoom!
図D:


Pythonのプログラムをデバッグするには

  1. Pythonで絵文字を表示するプログラムを作成する

    Visual Studio Code(VS Code)を起動したら新規ファイルを作成して行1-10を入力(コピペ)します。 行1-3では関数「main()」を定義しています。 行2では絵文字を表示する件数を入力させています。 行3では関数「print_emoji()」を呼び出しています。

    行5-7では関数「print_emoji()」を定義しています。 行6-7のforループでは絵文字を引数で指定した件数分表示しています。 ちなみにこのコードにはバグがあります。詳細は図1で解説します。

    行9-10では関数「main()」を呼び出しています。
    def main():
        number = int(input("What's number: "))
        print_emoji(number)
    
    def print_emoji(n):
        for i in range(n):
            print('😄' * i)
    
    if __name__ == '__main__':
        main()

    click image to zoom!
    図1
    図1は実行結果です。 「What's number」で「3」を入力しているので本来絵文字が3件表示されるべきなのですがバグがあるので2件しか表示されていません。


  2. Pythonの「print()」でデバッグ情報を表示する

    ここでは前出のプログラムのバグを見つけるために行7の「print(i, end=' ')」を追加します。
    def main():
        number = int(input("What's number: "))
        print_emoji(number)
    
    def print_emoji(n):
        for i in range(n):
            print(i, end=' ')
            print('😄' * i)
    
    if __name__ == '__main__':
        main()

    click image to zoom!
    図2
    図2は実行結果です。 行10(図2)のprintでは変数「i」の値が「0, 1, 2」と3件表示されています。 行11(図2)の「 print('😄' * i)」ではiの値が「0」のため絵文字が表示されないことが判明しました。 このバグは「 print('😄' * (i + 1))」のように修正すれば正常に動作します。


  3. Pythonのライブラリ「logging」でデバッグ情報を表示する

    ここではPythonのライブラリ「logging」を使用してデバッグ情報を表示します。 行1ではPythonのライブラリを取り込んでいます。 行5ではloggingのbasicConfig()メソッドでログの書式を設定しています。 ここではログ情報として「levelname」+「message」を表示するように設定しています。 さらに「levelname」を緑色で表示するようにしています。 loggingの詳細については「記事(Article103)」で解説しています。 行12ではloggingのdebug()メソッドでデバッグ情報を表示しています。 ここでは変数「i」の値を表示しています。
    import logging
    
    def main():
        # logging.basicConfig(format=':%(levelname)s: %(message)s', level=logging.DEBUG)    
        logging.basicConfig(format='\033[92m%(levelname)s\033[0m %(message)s', level=logging.DEBUG)     
        # logging.basicConfig(format='\033[92m%(levelname)s\033[0m %(message)s', level=logging.CRITICAL)    
        number = int(input("What's number: "))
        print_emoji(number)
    
    def print_emoji(n):
        for i in range(n):
            logging.debug(f"i={i}")            
            print('😄' * i)
    
    if __name__ == '__main__':
        main()

    click image to zoom!
    図3
    図3は実行結果です。 デバッグ情報として「DEBUG i=0」が表示されています。 変数「i」の値が「0」なので絵文字が2件しか表示されないことが判明しました。


  4. プログラムのバグ(bug)を修正して再実行して見る

    ここでは行13を「 print('😄' * (i + 1))」のように修正してバグを取り除いています。 さらに行6を追加してデバッグ情報が表示されないようにしています。 loggingのbasicConfig()メソッドの引数「level=」に「logging.CRITICAL」を設定すると、 行12のloggingのdebug()メソッドで表示したデバッグ情報は無効になります。 つまり、表示されないようになります。
    import logging
    
    def main():
        # logging.basicConfig(format=':%(levelname)s: %(message)s', level=logging.DEBUG)    
        # logging.basicConfig(format='\033[92m%(levelname)s\033[0m %(message)s', level=logging.DEBUG)     
        logging.basicConfig(format='\033[92m%(levelname)s\033[0m %(message)s', level=logging.CRITICAL)    
        number = int(input("What's number: "))
        print_emoji(number)
    
    def print_emoji(n):
        for i in range(n):
            logging.debug(f"i={i}")            
            print('😄' * (i + 1))
    
    if __name__ == '__main__':
        main()

    click image to zoom!
    図4
    図4は実行結果です。 バグが取り除かれて絵文字が3件表示されています。 さらにデバッグ情報も表示されなくなりました。 このようにlogging.debug()を使用するとコードを削除することなしに、デバッグ情報を無効にすることができます。


  5. Visual Studio Code(VS Code)のデバッグ機能を使用してデバッグする

    ここではVS Codeのデバッガーを使用してデバッグする方法を説明します。 前出のプログラムはバグのある状態に戻しています。 行7の「print('😄' * i)」にバグがあります。 VS Codeでデバッグする手順については図5-1~図5-7で説明します。
    def main():
        number = int(input("What's number: "))
        print_emoji(number)
    
    def print_emoji(n):
        for i in range(n):    
            print('😄' * i)
    
    if __name__ == '__main__':
        main()

    click image to zoom!
    図5-1
    行24(図5-1)の行番号の左をクリックしてブレークポイントを設定します。 すると赤の「●」が表示されます。 この状態で「Run and Debug」のアイコンをクリックしてデバッガー起動します。


    click image to zoom!
    図5-2
    「Run and Debug」の文字が表示されたらクリックして起動します。


    click image to zoom!
    図5-3
    行24(図5-3)の「●」が「▶」に変わります。 そしてデバッガーを操作するナビゲーションボタンが表示されます。 さらに画面の左側には「VARIABLES」が表示されて変数の値が見れる状態になります。 この状態でナビゲーションボタンから[Step Into]ボタンをクリックして続行します。


    click image to zoom!
    図5-4
    行16(図5-4)に矢印(ブレークポイント)が移動します。 この状態でナビゲーションボタンから[Step Over]ボタンをクリックして続行します。


    click image to zoom!
    図5-5
    行16(図5-5)が実行されてTERMINALウィンドウに「What's number:」が表示されたら「3」を入力して[Enter]を押します。 ブレークポイントが行17(図5-5)に移動したらナビゲーションボタンから[Step Into]ボタンをクリックして続行します。


    click image to zoom!
    図5-6
    行20(図5-6)にブレークポイントが移動したらナビゲーションボタンから[Step Into]ボタンをクリックして続行します。


    click image to zoom!
    図5-7
    行21(図5-7)のprint()が実行されてブレークポイントが行20(図5-7)に移動します。 この状態で左側の「VARIABLES」に表示されている変数「i」の値をチェックします。 ここでは「0」になっています。これで絵文字が表示されないことが判明しました。 「print('😄' * i) が print()」になる。 バグが判明したのでナビゲーションボタンから[Stop]ボタンをクリックしてデバッガーを終了させます。