4

デバッグ出力を印刷するために、関数の周りにたくさんの印刷物が散らばっていることがあります。このデバッグ出力を切り替えるために、私はこれを思いつきました:

def f(debug=False): 
    print = __builtins__.print if debug else lambda *p: None

または、デバッグ メッセージとは別に何かを出力する必要がある場合は、デバッグ メッセージdprint用の関数を作成します。

問題は、が呼び出され、関数呼び出しが遅いことが知られているためdebug=False、このprintステートメントがコードを大幅に遅くすることです。lambda *p: None

だから、私の質問は次のとおりです。コードのパフォーマンスに影響を与えないように、これらすべてのデバッグ出力を効率的に無効にするより良い方法はありますか?


すべての答えは、loggingモジュールを使用していないことに関するものです。これは注目に値しますが、これは、コードを大幅に遅くする関数呼び出しを回避する方法に関する質問には答えません。ステートメントを含む行printまたはその他の方法)))。これらの回答が示唆するのは、さらに遅くなるはずの にprint置き換えることです。logging.debugこの質問は、それらの関数呼び出しを完全に取り除くことに関するものです。

loggingの代わりにを使用してみましたがlambda *p: None、当然のことながら、コードはさらに遅くなりました。


おそらく誰かが、これらのプリントが 25 の速度低下を引き起こしたコードを見たいと思うでしょう: http://ideone.com/n5PGu

loggingそして、私はモジュールに対して何も持っていません。ハックせずに常に堅牢なソリューションに固執することは良い習慣だと思います。しかし、これらのハックを 20 行の 1 回限りのコード スニペットで使用した場合、犯罪にはならないと思います。


print制限ではありませんが、提案として、関数のソース コードからいくつかの行 (たとえば で始まる行) を削除して、再コンパイルすることは可能でしょうか? 以下の回答でこのアプローチを説明しました。その解決策についてコメントをいただきたいのですが、この問題を解決するための他のアプローチを歓迎します。

4

5 に答える 5

5

logging代わりにモジュールを使用する必要があります。http://docs.python.org/library/logging.htmlを参照してください

次に、必要に応じてログ レベルを設定し、さまざまな件名についてログを記録する複数のロガー オブジェクトを作成できます。

import logging
#set your log level
logging.basicConfig(level=logging.DEBUG)
logging.debug('This is a log message')

あなたの場合: print ステートメントを log ステートメントに置き換えるだけです。

import logging
print = __builtins__.print if debug else logging.debug

ログレベルをデバッグに設定した場合、関数は何でも出力するようになりました

logging.basicConfig(level=logging.DEBUG)

しかしプラスとして、他のすべてのロギング機能を上で使用できます!logging.error('error!')

于 2012-08-31T22:34:51.010 に答える
3

Ned Batchelderはコメントに次のように書いています。

スローダウンは、デバッグ関数への引数の計算にあると思われます。これらの計算を回避する方法を探す必要があります。Python の前処理は単なる気晴らしです。

format結果の文字列がログに記録されるかどうかに関係なく、メソッドを使用して文字列をフォーマットすることによって実際にスローダウンが引き起こされるため、彼は正しいです。

そのため、ログが発生しない場合は、文字列の書式設定を延期して無視する必要があります。dprintこれは、関数をリファクタリングするかlog.debug、次の方法で使用することによって実現できます。

log.debug('formatted message: %s', interpolated_value)

printメッセージがログに記録されない場合、ログに記録されるか破棄されるかに関係なく常にフォーマットされるとは異なり、メッセージはフォーマットされません。

log.debug延期された書式設定に関する解決策は、 Martijn Pietersに提供さ れました

于 2012-09-01T17:10:59.083 に答える
1

別の解決策として、すべての呼び出しのコードを動的に編集fして削除することが考えられます。drpintしかし、この解決策は使用することを強くお勧めしません:

あなたは正しいです、決してこれに頼るべきではありません。まず、Python はソースレベルの変換用に設計された言語ではないため、有効なコードを不当に壊さずに comment_1 などの変換プログラムを作成することは困難です。第二に、このハックはあらゆる種類の状況で壊れます。たとえば、メソッドを定義するとき、ネストされた関数を定義するとき、Cython で使用されるとき、inspect.getsource が何らかの理由で失敗したときなどです。Python は十分に動的であるため、その動作をカスタマイズするためにこの種のハックは実際には必要ありません。

このアプローチに慣れたい人のために、このアプローチのコードを次に示します。

from __future__ import print_function

DEBUG = False

def dprint(*args,**kwargs):
    '''Debug print'''
    print(*args,**kwargs)

_blocked = False
def nodebug(name='dprint'):
    '''Decorator to remove all functions with name 'name' being a separate expressions'''
    def helper(f):      
        global _blocked
        if _blocked:
            return f

        import inspect, ast, sys

        source = inspect.getsource(f)        
        a = ast.parse(source) #get ast tree of f

        class Transformer(ast.NodeTransformer):
            '''Will delete all expressions containing 'name' functions at the top level'''
            def visit_Expr(self, node): #visit all expressions
                try:
                    if node.value.func.id == name: #if expression consists of function with name a
                        return None #delete it
                except(ValueError):
                    pass
                return node #return node unchanged
        transformer = Transformer()
        a_new = transformer.visit(a)
        f_new_compiled = compile(a_new,'<string>','exec')

        env = sys.modules[f.__module__].__dict__
        _blocked = True
        try:
            exec(f_new_compiled,env)
        finally:
            _blocked = False
        return env[f.__name__]         
    return helper


@nodebug('dprint')        
def f():
    dprint('f() started')
    print('Important output')
    dprint('f() ended')
    print('Important output2')


f()

詳細:関数コードの一部をオンザフライで置き換える

于 2012-09-01T12:30:10.467 に答える
0

ハックとして、はい、それは機能します。(そして、これらのラムダの no-ops がアプリのボトルネックになる可能性はまったくありません。)

loggingただし、モジュールを使用して適切にログを記録する必要があります。

これを行う方法の基本的な例については、http://docs.python.org/howto/logging.html#logging-basic-tutorialを参照してください。

于 2012-08-31T22:33:28.580 に答える
0

間違いなく Python のログモジュールを使用する必要があります。これは非常に実用的で、アプリケーションのログ レベルを変更できます。例:

>>> import logging
>>> logging.basicConfig(level=logging.DEBUG)
>>> logging.debug('Test.')
DEBUG:root:Test.
于 2012-08-31T22:35:23.833 に答える