Pythonトレースバックを理解する

Pythonトレースバックを理解する

コードで例外が発生すると、Pythonはtracebackを出力します。 トレースバックの出力は、初めて表示する場合や、何を伝えているのかわからない場合、少々圧倒されます。 しかし、Pythonトレースバックには、コードで発生した例外の原因を診断および修正するのに役立つ豊富な情報があります。 Pythonトレースバックが提供する情報を理解することは、優れたPythonプログラマーになるために不可欠です。

このチュートリアルを終了すると、次のことができるようになります。

  • 表示される次のトレースバックを理解する

  • より一般的なトレースバックのいくつかを認識する

  • 例外を処理しながらトレースバックを正常に記録します

Free Bonus:Click here to get our free Python Cheat Sheetは、データ型、辞書、リスト、Python関数の操作など、Python3の基本を示しています。

Pythonトレースバックとは何ですか?

トレースバックは、特定の時点でコード内で行われた関数呼び出しを含むレポートです。 トレースバックは、stack tracestack tracebackbacktraceなど、多くの名前で知られています。 Pythonでは、使用される用語はtracebackです。

プログラムで例外が発生すると、Pythonは現在のトレースバックを出力して、何が問題なのかを知るのに役立ちます。 以下に、この状況を説明する例を示します。

# example.py
def greet(someone):
    print('Hello, ' + someon)

greet('Chad')

ここで、greet()はパラメーターsomeoneで呼び出されます。 ただし、greet()では、その変数名は使用されません。 代わりに、print()呼び出しでsomeonとしてスペルが間違っています。

Note:このチュートリアルは、Pythonの例外を理解していることを前提としています。 慣れていない場合、または単に復習したい場合は、Python Exceptions: An Introductionを確認する必要があります。

このプログラムを実行すると、次のトレースバックが表示されます。

$ python example.py
Traceback (most recent call last):
  File "/path/to/example.py", line 4, in 
    greet('Chad')
  File "/path/to/example.py", line 2, in greet
    print('Hello, ' + someon)
NameError: name 'someon' is not defined

このトレースバック出力には、問題の診断に必要なすべての情報が含まれています。 トレースバック出力の最終行には、発生した例外のタイプと、その例外に関するいくつかの関連情報が示されます。 トレースバックの前の行は、例外が発生する原因となったコードを示しています。

上記のトレースバックでは、例外はNameErrorでした。これは、定義されていない名前(変数、関数、クラス)への参照があることを意味します。 この場合、参照される名前はsomeonです。

この場合の最終行には、問題の修正に役立つ十分な情報が含まれています。 スペルミスである名前someonのコードを検索すると、正しい方向を示します。 ただし、多くの場合、コードははるかに複雑です。

Pythonトレースバックの読み方

Pythonトレースバックには、コードで発生した例外の理由を判断しようとするときに役立つ多くの情報が含まれています。 このセクションでは、トレースバックに含まれるさまざまな情報を理解するために、さまざまなトレースバックを順を追って説明します。

Pythonトレースバックの概要

すべてのPythonトレースバックには、重要なセクションがいくつかあります。 以下の図は、さまざまな部分を強調しています。

An example Python traceback with call-outs.

Pythonでは、トレースバックを下から順に読むのが最善です。

  1. Blue box:トレースバックの最後の行はエラーメッセージ行です。 発生した例外名が含まれます。

  2. Green box:例外名の後にエラーメッセージが表示されます。 通常、このメッセージには、例外が発生する理由を理解するのに役立つ情報が含まれています。

  3. Yellow box:トレースバックのさらに上には、さまざまな関数呼び出しが下から上に移動し、最新のものから最新のものへと移動します。 これらの呼び出しは、呼び出しごとに2行のエントリで表されます。 各呼び出しの最初の行には、ファイル名、行番号、モジュール名などの情報が含まれており、すべてコードの場所を指定しています。

  4. Red underline:これらの呼び出しの2行目には、実行された実際のコードが含まれています。

コマンドラインでコードを実行する場合と、REPLでコードを実行する場合のトレースバック出力には、いくつかの違いがあります。 以下は、REPLで実行された前のセクションの同じコードと、結果のトレースバック出力です。

>>>

>>> def greet(someone):
...   print('Hello, ' + someon)
...
>>> greet('Chad')
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in greet
NameError: name 'someon' is not defined

ファイル名の代わりに"<stdin>"を取得することに注意してください。 これは、標準入力を介してコードを入力したので理にかなっています。 また、実行されたコード行はトレースバックに表示されません。

Note:他のプログラミング言語でスタックトレースを表示することに慣れている場合は、Pythonトレースバックの外観と比較して大きな違いに気付くでしょう。 他のほとんどの言語は、例外を一番上に表示してから、上から下へ、最近の呼び出しから最も新しいものへと呼び出します。

すでに述べましたが、繰り返しますが、Pythonトレースバックは下から上に読む必要があります。 これは非常に便利です。トレースバックが印刷され、端末(またはトレースバックを読んでいるところ)が通常出力の最後になり、トレースバックを読み始めるのに最適な場所が得られるからです。

特定のトレースバックウォークスルー

特定のトレースバック出力を調べることで、トレースバックがどのような情報を提供するかをより深く理解し、確認することができます。

以下のコードは、Pythonトレースバックが提供する情報を説明するために、次の例で使用されています。

# greetings.py
def who_to_greet(person):
    return person if person else input('Greet who? ')

def greet(someone, greeting='Hello'):
    print(greeting + ', ' + who_to_greet(someone))

def greet_many(people):
    for person in people:
        try:
            greet(person)
        except Exception:
            print('hi, ' + person)

ここで、who_to_greet()は値personを取り、それを返すか、代わりに値を返すように要求します。

次に、greet()は、挨拶する名前、someone、およびオプションのgreeting値を取り、print()を呼び出します。 who_to_greet()は、渡されたsomeone値でも呼び出されます。

最後に、greet_many()peopleのリストを反復処理し、greet()を呼び出します。 greet()を呼び出すことによって発生した例外がある場合、簡単なバックアップグリーティングが出力されます。

このコードには、正しい入力が提供されている限り例外が発生するバグはありません。

greetings.pyの下部にgreet()への呼び出しを追加し、予期しないキーワード引数(たとえば、greet('Chad', greting='Yo'))を指定すると、次のトレースバックが得られます。

$ python example.py
Traceback (most recent call last):
  File "/path/to/greetings.py", line 19, in 
    greet('Chad', greting='Yo')
TypeError: greet() got an unexpected keyword argument 'greting'

この場合も、Pythonトレースバックを使用して、出力を上に移動して後方に作業するのが最善です。 トレースバックの最終行から、例外がTypeErrorであることがわかります。 コロンの後のすべての例外タイプに続くメッセージは、いくつかの素晴らしい情報を提供します。 greet()が予期しないキーワード引数で呼び出されたことを示しています。 不明な引数名も与えられます:greting

上に移動すると、例外が発生した行を確認できます。 この場合、greetings.pyの下部に追加したのはgreet()呼び出しです。

次の行には、コードが存在するファイルへのパス、コードが見つかるファイルの行番号、およびそのモジュールが含まれています。 この場合、コードは他のPythonモジュールを使用していないため、ここに<module>が表示されます。これは、これが実行中のファイルであることを意味します。

別のファイルと別の入力を使用すると、トレースバックが問題を見つけるために正しい方向を指し示していることがわかります。 フォローしている場合は、バグのあるgreet()呼び出しをgreetings.pyの下部から削除し、次のファイルをディレクトリに追加します。

# example.py
from greetings import greet

greet(1)

ここでは、前のモジュールgreetings.pyをインポートし、そこからgreet()を使用する別のPythonファイルを設定しました。 example.pyを実行すると、次のようになります。

$ python example.py
Traceback (most recent call last):
  File "/path/to/example.py", line 3, in 
    greet(1)
  File "/path/to/greetings.py", line 5, in greet
    print(greeting + ', ' + who_to_greet(someone))
TypeError: must be str, not int

この場合に発生する例外は再びTypeErrorですが、今回のメッセージは少し役に立ちません。 これは、コードのどこかで文字列を処理することを期待していたが、整数が与えられたことを示しています。

上に移動すると、実行されたコード行が表示されます。 次に、コードのファイルと行番号。 ただし、今回は、<module>の代わりに、実行されていた関数の名前greet()を取得します。

次に実行されるコード行に移動すると、問題のあるgreet()呼び出しが整数で渡されていることがわかります。

例外が発生した後、別のコードがその例外をキャッチし、例外が発生することもあります。 このような状況では、Pythonはすべての例外トレースバックを受信した順に出力し、再び最後に発生した例外のトレースバックで終了します。

これは少しわかりにくいので、例を示します。 greetings.pyの下部にgreet_many()への呼び出しを追加します。

# greetings.py
...
greet_many(['Chad', 'Dan', 1])

これにより、3人全員に挨拶が印刷されます。 ただし、このコードを実行すると、複数のトレースバックが出力される例が表示されます。

$ python greetings.py
Hello, Chad
Hello, Dan
Traceback (most recent call last):
  File "greetings.py", line 10, in greet_many
    greet(person)
  File "greetings.py", line 5, in greet
    print(greeting + ', ' + who_to_greet(someone))
TypeError: must be str, not int

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "greetings.py", line 14, in 
    greet_many(['Chad', 'Dan', 1])
  File "greetings.py", line 12, in greet_many
    print('hi, ' + person)
TypeError: must be str, not int

上記の出力でDuring handlingで始まる強調表示された行に注意してください。 すべてのトレースバックの間に、この行が表示されます。 そのメッセージは非常に明確で、コードが前の例外を処理しようとしていたときに別の例外が発生しました。

Note:以前の例外トレースバックを表示するPythonの機能がPython3で追加されました。 Python 2では、最後の例外のトレースバックのみを取得します。

整数でgreet()を呼び出したとき、前の例外を見たことがあります。 挨拶する人のリストに1を追加したので、同じ結果が期待できます。 ただし、関数greet_many()は、greet()呼び出しをtryおよびexceptブロックにラップします。 greet()で例外が発生した場合に備えて、greet_many()はデフォルトのグリーティングを出力したいと考えています。

greetings.pyの関連部分は、ここで繰り返されます。

def greet_many(people):
    for person in people:
        try:
            greet(person)
        except Exception:
            print('hi, ' + person)

したがって、整数入力が正しくないためにgreet()TypeErrorになると、greet_many()はその例外を処理し、簡単な挨拶を出力しようとします。 ここで、コードは最終的に別の同様の例外になります。 まだ文字列と整数を追加しようとしています。

トレースバックのすべての出力を見ると、例外の本当の原因が何かを確認するのに役立ちます。 最終的な例外が発生し、その結果のトレースバックが表示される場合でも、何が問題なのかがまだわからないことがあります。 そのような場合、通常、前の例外に移動すると、根本的な原因をよりよく理解できます。

Pythonの一般的なトレースバックとは何ですか?

プログラムで例外が発生したときにPythonトレースバックを読み取る方法を知っていると、プログラミングの際に非常に役立ちますが、一般的なトレースバックのいくつかを知っていると、プロセスを高速化できます。

以下に、遭遇する可能性のあるいくつかの一般的な例外、それらが発生する理由とその意味、およびトレースバックで見つけることができる情報を示します。

AttributeError

AttributeErrorは、その属性が定義されていないオブジェクトの属性にアクセスしようとすると発生します。 Pythonドキュメントでは、この例外がいつ発生するかを定義しています。

属性の参照または割り当てが失敗したときに発生します。 (Source)

AttributeErrorが発生する例を次に示します。

>>>

>>> an_int = 1
>>> an_int.an_attribute
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'int' object has no attribute 'an_attribute'

AttributeErrorのエラーメッセージ行は、特定のオブジェクトタイプ(この場合はint)にアクセスされた属性(この場合はan_attribute)がないことを示しています。 エラーメッセージ行のAttributeErrorを確認すると、アクセスしようとした属性とその修正先をすばやく特定するのに役立ちます。

ほとんどの場合、この例外が発生するということは、おそらく期待していたタイプではないオブジェクトを操作していることを示しています。

>>>

>>> a_list = (1, 2)
>>> a_list.append(3)
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'tuple' object has no attribute 'append'

上記の例では、a_list.append()というメソッドを持つlist型であると予想している場合があります。 AttributeError例外を受け取り、.append()を呼び出そうとしたときに発生したことを確認すると、期待していたタイプのオブジェクトを処理していない可能性があります。

多くの場合、これは、関数またはメソッド呼び出しからオブジェクトが返されることを期待していて、最終的にタイプNoneのオブジェクトになる場合に発生します。 この場合、エラーメッセージ行はAttributeError: 'NoneType' object has no attribute 'append'と表示されます。

ImportError

ImportErrorは、importステートメントで問題が発生したときに発生します。 インポートしようとしているモジュールが見つからない場合、またはモジュールに存在しないモジュールから何かをインポートしようとすると、この例外またはそのサブクラスModuleNotFoundErrorが発生します。 Pythonドキュメントでは、この例外がいつ発生するかを定義しています。

importステートメントにモジュールのロードに問題がある場合に発生します。 from ... importの「リストから」の名前が見つからない場合にも発生します。 (Source)

ImportErrorModuleNotFoundErrorが発生する例を次に示します。

>>>

>>> import asdf
Traceback (most recent call last):
  File "", line 1, in 
ModuleNotFoundError: No module named 'asdf'
>>> from collections import asdf
Traceback (most recent call last):
  File "", line 1, in 
ImportError: cannot import name 'asdf'

上記の例では、存在しないモジュールasdfをインポートしようとすると、ModuleNotFoundErrorになることがわかります。 存在するモジュールcollectionsから、存在しないものasdfをインポートしようとすると、ImportErrorになります。 トレースバックの下部にあるエラーメッセージ行は、インポートできなかったものを示しています。どちらの場合もasdfです。

IndexError

list or a tupleのようにシーケンスからインデックスを取得しようとすると、IndexErrorが発生しますが、シーケンス内にインデックスが見つかりません。 Pythonドキュメントでは、この例外がいつ発生するかを定義しています。

シーケンスの添え字が範囲外の場合に発生します。 (Source)

IndexErrorを上げる例を次に示します。

>>>

>>> a_list = ['a', 'b']
>>> a_list[3]
Traceback (most recent call last):
  File "", line 1, in 
IndexError: list index out of range

IndexErrorのエラーメッセージ行は、優れた情報を提供しません。 out of rangeであるシーケンス参照があり、シーケンスのタイプ(この場合はlist)であることがわかります。 通常、その情報と残りのトレースバックを組み合わせることで、問題の修正方法をすばやく特定するのに十分です。

KeyError

IndexErrorと同様に、マッピングにないキー(通常はdict)にアクセスしようとすると、KeyErrorが発生します。 これをIndexErrorと考えてください。ただし、dictionariesの場合です。 Pythonドキュメントでは、この例外がいつ発生するかを定義しています。

マッピング(辞書)キーが既存のキーのセットで見つからない場合に発生します。 (Source)

KeyErrorが発生する例を次に示します。

>>>

>>> a_dict['b']
Traceback (most recent call last):
  File "", line 1, in 
KeyError: 'b'

KeyErrorのエラーメッセージ行には、見つからなかったキーが表示されます。 これはあまり続けることではありませんが、残りのトレースバックと組み合わせると、通常は問題を修正するのに十分です。

KeyErrorの詳細については、Python KeyError Exceptions and How to Handle Themを参照してください。

NameError

NameErrorは、変数、モジュール、クラス、関数、またはコードで定義されていないその他の名前を参照した場合に発生します。 Pythonドキュメントでは、この例外がいつ発生するかを定義しています。

ローカル名またはグローバル名が見つからない場合に発生します。 (Source)

以下のコードでは、greet()はパラメーターpersonを取ります。 しかし、関数自体では、そのパラメーターのスペルがpersnに間違っています。

>>>

>>> def greet(person):
...     print(f'Hello, {persn}')
>>> greet('World')
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in greet
NameError: name 'persn' is not defined

NameErrorトレースバックのエラーメッセージ行に、欠落している名前が示されています。 上記の例では、渡された関数の変数またはパラメーターのスペルが間違っています。

スペルを間違えたパラメータの場合も、NameErrorが発生します。

>>>

>>> def greet(persn):
...     print(f'Hello, {person}')
>>> greet('World')
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in greet
NameError: name 'person' is not defined

ここでは、何も間違ったことをしていないように見えるかもしれません。 トレースバックで実行および参照された最後の行は適切に見えます。 このような状況に陥った場合は、コードを調べて、person変数が使用および定義されている場所を探す必要があります。 ここで、パラメーター名のスペルが間違っていることがすぐにわかります。

SyntaxError

SyntaxErrorは、コードに誤ったPython構文がある場合に発生します。 Pythonドキュメントでは、この例外がいつ発生するかを定義しています。

パーサーが構文エラーを検出すると発生します。 (Source)

以下の問題は、関数定義行の最後にあるはずのコロンが欠落していることです。 Python REPLでは、この構文エラーはEnterキーを押すとすぐに発生します。

>>>

>>> def greet(person)
  File "", line 1
    def greet(person)
                    ^
SyntaxError: invalid syntax

SyntaxErrorのエラーメッセージ行は、コードの構文に問題があったことを示しているだけです。 上記の行を調べると、問題のある行と、通常は問題のある場所を指す^(キャレット)が表示されます。 ここでは、関数のdefステートメントにコロンがありません。

また、SyntaxErrorトレースバックでは、通常の最初の行Traceback (most recent call last):が欠落しています。 これは、Pythonがコードを解析しようとしたときにSyntaxErrorが発生し、行が実際に実行されていないためです。

TypeError

TypeErrorは、整数に文字列を追加しようとしたり、長さがnでないオブジェクトでlen()を呼び出したりするなど、コードがそれを実行できないオブジェクトで何かを実行しようとすると発生します。定義されていません。 Pythonドキュメントでは、この例外がいつ発生するかを定義しています。

不適切なタイプのオブジェクトに操作または関数が適用されると発生します。 (Source)

以下は、TypeErrorが発生するいくつかの例です。

>>>

>>> 1 + '1'
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> '1' + 1
Traceback (most recent call last):
  File "", line 1, in 
TypeError: must be str, not int
>>> len(1)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: object of type 'int' has no len()

TypeErrorを上げる上記の例はすべて、異なるメッセージを含むエラーメッセージ行になります。 それらのそれぞれは、何が間違っているかを通知するという非常に良い仕事をします。

最初の2つの例では、文字列と整数を一緒に追加しようとします。 ただし、それらは微妙に異なります。

  • 1つ目は、strintに追加しようとすることです。

  • 2つ目は、intstrに追加しようとしています。

エラーメッセージの行には、これらの違いが反映されています。

最後の例では、intlen()を呼び出そうとします。 エラーメッセージ行は、intではそれができないことを示しています。

ValueError

ValueErrorは、オブジェクトの値が正しくない場合に発生します。 これは、インデックスの値がシーケンスの範囲内にないために発生するIndexErrorと考えることができます。より一般的なケースでは、ValueErrorのみが使用されます。 Pythonドキュメントでは、この例外がいつ発生するかを定義しています。

操作または関数が正しい型であるが不適切な値の引数を受け取り、その状況がIndexErrorなどのより正確な例外によって記述されていない場合に発生します。 (Source)

ValueErrorが発生する2つの例を次に示します。

>>>

>>> a, b, c = [1, 2]
Traceback (most recent call last):
  File "", line 1, in 
ValueError: not enough values to unpack (expected 3, got 2)
>>> a, b = [1, 2, 3]
Traceback (most recent call last):
  File "", line 1, in 
ValueError: too many values to unpack (expected 2)

これらの例のValueErrorエラーメッセージ行は、値の問題が何であるかを正確に示しています。

  1. 最初の例では、多くの値をアンパックしようとしています。 エラーメッセージの行には、3つの値をアンパックすることを期待していましたが、2つの値が得られたことが示されています。

  2. 2番目の例の問題は、取得する値が多すぎて、それらを展開するのに十分な変数がないことです。

トレースバックをどのように記録しますか?

例外とその結果のPythonトレースバックを取得するということは、その対処方法を決定する必要があることを意味します。 通常、コードを修正することが最初のステップですが、予期しない入力や間違った入力に問題がある場合があります。 コードでこれらの状況に対応するのは良いことですが、トレースバックをログに記録して他のことを行うことで、例外を沈黙させたり隠したりするのも理にかなっています。

Pythonのトレースバックを黙らせる必要がある、より現実的なコードの例を次に示します。 この例では、requests libraryを使用しています。 あなたはPython’s Requests Library (Guide)でそれについてもっと知ることができます:

# urlcaller.py
import sys
import requests

response = requests.get(sys.argv[1])

print(response.status_code, response.content)

このコードはうまくいきます。 コマンドライン引数としてURLを指定してこのスクリプトを実行すると、URLが呼び出され、応答からHTTPステータスコードとコンテンツが出力されます。 応答がHTTPエラーステータスの場合でも機能します。

$ python urlcaller.py https://httpbin.org/status/200
200 b''
$ python urlcaller.py https://httpbin.org/status/500
500 b''

ただし、取得するためにスクリプトに指定されたURLが存在しないか、ホストサーバーがダウンしている場合があります。 このような場合、このスクリプトはキャッチされないConnectionError例外を発生させ、トレースバックを出力します。

$ python urlcaller.py http://thisurlprobablydoesntexist.com
...
During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "urlcaller.py", line 5, in 
    response = requests.get(sys.argv[1])
  File "/path/to/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "/path/to/requests/api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "/path/to/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/path/to/requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "/path/to/requests/adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='thisurlprobablydoesntexist.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -2] Name or service not known',))

ここでのPythonトレースバックは非常に長くなる可能性がありますが、他の多くの例外が発生し、最終的にConnectionErrorrequests自体によって発生します。 最後の例外のトレースバックを上に移動すると、問題はすべて、urlcaller.pyの5行目からコードで始まっていることがわかります。

問題のある行をtry and except blockでラップする場合、適切な例外をキャッチすると、スクリプトはより多くの入力で引き続き機能します。

# urlcaller.py
...
try:
    response = requests.get(sys.argv[1])
except requests.exceptions.ConnectionError:
    print(-1, 'Connection Error')
else:
    print(response.status_code, response.content)

上記のコードでは、tryおよびexceptブロックでelse句を使用しています。 Pythonのこの機能に慣れていない場合は、Python Exceptions: An Introductionelse句のセクションを確認してください。

これで、ConnectionErrorが発生するURLを使用してスクリプトを実行すると、ステータスコードの-1とコンテンツConnection Errorが出力されます。

$ python urlcaller.py http://thisurlprobablydoesntexist.com
-1 Connection Error

これはとてもうまくいきます。 ただし、ほとんどの実際のシステムでは、例外とその結果のトレースバックを黙らせるだけでなく、トレースバックを記録する必要があります。 トレースバックを記録することにより、プログラムの何が問題になっているのかをより深く理解できます。

Note: Pythonのロギングシステムの詳細については、Logging in Pythonを確認してください。

loggingパッケージをインポートし、ロガーを取得し、そのロガーでtryおよび%((t3)sおよびexceptブロック。 最終的なスクリプトは、次のコードのようになります。

# urlcaller.py
import logging
import sys
import requests

logger = logging.getLogger(__name__)

try:
    response = requests.get(sys.argv[1])
except requests.exceptions.ConnectionError as e:
    logger.exception()
    print(-1, 'Connection Error')
else:
    print(response.status_code, response.content)

これで、問題のあるURLに対してスクリプトを実行すると、予期された-1Connection Errorが出力されますが、トレースバックもログに記録されます。

$ python urlcaller.py http://thisurlprobablydoesntexist.com
...
  File "/path/to/requests/adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='thisurlprobablydoesntexist.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -2] Name or service not known',))
-1 Connection Error

デフォルトでは、Pythonはログメッセージを標準エラー(stderr)に送信します。 これは、トレースバック出力をまったく抑制していないようです。 ただし、stderrをリダイレクトしているときに再度呼び出すと、ログシステムが機能していることがわかり、後で使用できるようにログを保存できます。

$ python urlcaller.py http://thisurlprobablydoesntexist.com 2> my-logs.log
-1 Connection Error

結論

Pythonトレースバックには、Pythonコードで何が問題なのかを見つけるのに役立つ素晴らしい情報が含まれています。 これらのトレースバックは少し威圧的に見えるかもしれませんが、それを分解して表示しようとしているものを確認すると、非常に役立ちます。 行ごとにいくつかのトレースバックを実行すると、含まれている情報をよりよく理解でき、それらを最大限に活用できます。

コードの実行時にPythonトレースバック出力を取得することは、コードを改善する機会です。 Pythonがあなたを助けようとする1つの方法です。

Pythonトレースバックの読み方がわかったので、トレースバック出力で通知されている問題を診断するためのいくつかのツールと手法についてさらに学ぶことができます。 Pythonの組み込みtraceback moduleを使用して、トレースバックを操作および検査できます。 tracebackモジュールは、トレースバック出力をさらに活用する必要がある場合に役立ちます。 Pythonコードのいくつかのtechniques for debuggingについてさらに学ぶことも役に立ちます。