デバッグのみに印刷ステートメントを使用する


109

最近、Pythonで多くのコーディングを行っています。また、これまでに使用したことがないデータを使用したり、これまでにない式を使用したり、巨大なファイルを処理したりしています。これにより、多くの印刷ステートメントを記述して、問題がないかどうかを確認し、失敗した箇所を特定しました。しかし、一般的に、それほど多くの情報を出力することは良い習慣ではありません。デバッグしたい場合にのみ印刷ステートメントを使用し、印刷しない場合はスキップする方法を教えてください。

回答:


161

このloggingモジュールには、必要なものがすべて揃っています。最初は過剰に見えるかもしれませんが、必要な部品のみを使用してください。を使用logging.basicConfigしてログレベルを切り替えることをお勧めしますstderr、単純なログ方法debuginfowarningerrorcritical

import logging, sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logging.debug('A debug message!')
logging.info('We processed %d records', len(processed_records))

5
また、私のようにこのモジュールのインストールに問題があった場合に備えて。ロギングは標準ライブラリの一部です-仮想環境を使用している場合でもpipをインストールする必要はありません
Amr

エラーの出力のみを行い、メッセージのデバッグを行わないように、ロギングのレベルをどのように設定しますか?
Eduardo Pignatelli

@EduardoPignatelli levelは、basicConfig呼び出しでに設定しlogging.ERRORます。
マットジョイナー

これはjupyter lab 1.2.6では機能しないと思います。ログレベルは一度設定でき、再設定を使用しlogging.basicConfig(stream=sys.stderr, level=logging.ERROR)ても効果はありません。カーネルを再起動して新しいレベルを設定することは機能しますが、それは私にとっての回避策です。
Eduardo Pignatelli

@EduardoPignatelliあなたはこれについて別の質問をする必要があります。しかし、おそらくルートロガーのレベルを直接変更する必要があるでしょう、jupyterはおそらくあなたの前にbasicConfigを呼び出しています。
マットジョイナー

28

これを行う簡単な方法は、ロギング関数を呼び出すことです。

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

次に、の値を変更して、DEBUGログの有無にかかわらずコードを実行できます。

標準loggingモジュールには、このためのより複雑なメカニズムがあります。


5
長い目で見れば、提供されたロギングモジュールを使用する方が、独自のロールモジュールを使用するよりもおそらく複雑です(より複雑に見えます)。
mgiuca

11
本当ですが、自分でどうやって自分自身を動かすことができるかを理解することには価値があります。
グレッグヒューギル2011

1
確かに。上記は、logging(非常に単純なレベルで)どのように機能するかについての良い考えです。
mgiuca

これは、awsラムダに使用するものです。
crsuarezf

21

ログを使用する印刷する代わりに組み込みライブラリモジュールを使用します。

Loggerオブジェクトを作成し(たとえばlogger)、その後、デバッグ印刷を挿入するたびに、次のように入力します。

logger.debug("Some string")

logger.setLevelプログラムの開始時にを使用して、出力レベルを設定できます。DEBUGに設定すると、すべてのデバッグが出力されます。INFO以上に設定すると、すぐにすべてのデバッグが消えます。

また、さまざまなレベル(INFO、WARNING、ERROR)で、より深刻なものをログに記録することもできます。


12

まず、Pythonのロギングフレームワークの推薦を2番目に紹介します。ただし、使用方法には少し注意してください。具体的には、ロギングフレームワークに変数を展開させます。自分では行わないでください。たとえば、代わりに:

logging.debug("datastructure: %r" % complex_dict_structure)

あなたがすることを確認してください:

logging.debug("datastructure: %r", complex_dict_structure)

最初のバージョンは似ているように見えますが、無効になっている場合でも repr()のコストが発生するためです。2番目のバージョンはこれを回避します。同様に、自分でロールする場合は、次のようにすることをお勧めします。

def debug_stdout(sfunc):
    print(sfunc())

debug = debug_stdout

次を介して呼び出されます:

debug(lambda: "datastructure: %r" % complex_dict_structure)

これも、次のようにして無効にした場合のオーバーヘッドを回避します。

def debug_noop(*args, **kwargs):
    pass

debug = debug_noop

これらの文字列を計算するオーバーヘッドは、1)計算にコストがかかるか、2)デバッグステートメントが、たとえばn ^ 3ループなどの途中にない限り、おそらく問題ではありません。それについて私が何かを知っているとは限りません。



7

他の人については知りませんが、「グローバル定数」DEBUG)を定義してから、の場合にのみ出力されるグローバル関数(debug(msg))を定義するのに慣れていました。msgDEBUG == True

次に、次のようなデバッグステートメントを記述します。

debug('My value: %d' % value)

...それから私は単体テストを取り上げ、これを二度とやったことはありません!:)


ユニットテストha。さて、それはそれから拾われる別のことです:(
crazyaboutliv

1
単体テストを思いとどまらせたくありません-それは不可欠です。しかし、デバッグ手法としても、ログの代わりになるとは思いません。物事をすばやくテストするために、私はまだたくさんの印刷をしています。
mgiuca

@crazyaboutliv-適切に行われた単体テストは素晴らしいです。見てい本章てきぱき用のPythonにダイビングのを、簡潔な、簡単にフォロープレゼンテーション
MAC

@mgiuca-私も簡単に印刷print()していますが、テストに合格するために必要なレベルまでコードを引き上げるのはほんの数回です。あちこちで膨大な量になることはありませんprint()。ロギングもクールです!:)
Mac

2
@mac現在、リンクには明示的な「www」が必要なようです。現在、ここでホストされています
culix 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.