10

私のPythonコードは、たとえば次のように(デバッグ|プロファイリング|トレースなど)に使用される多くの関数呼び出しとインターレースされています。

import logging

logging.root.setLevel(logging.DEBUG)
logging.debug('hello')
j = 0
for i in range(10):
    j += i
    logging.debug('i %d j %d' % (i,j))
print(j)
logging.debug('bye')

これらのリソースを消費する関数をコードから#defineしたいと思います。c相当のようなもの

#define logging.debug(val)

はい、ログモジュールのログレベルメカニズムを使用して、設定されたログレベルより下のログをマスクできることを知っています。しかし、Pythonインタープリターに関数をスキップさせる一般的な方法を求めています(あまり実行しない場合でも実行に時間がかかります)

1つのアイデアは、コメントアウトしたい関数を空の関数に再定義することです。

def lazy(*args): pass
logging.debug = lazy

上記のアイデアはまだ関数を呼び出しており、他の無数の問題を引き起こす可能性があります

4

9 に答える 9

17

Python にはプリプロセッサがありませんが、Python ソースを外部プリプロセッサを介して実行して同じ効果を得ることができます。たとえばsed "/logging.debug/d"、すべてのデバッグ ログ コマンドを取り除きます。ただし、これはあまり洗練されたものではありません。メイン スクリプトを実行する前に、すべてのモジュールをプリプロセッサで実行し、おそらく処理された .py ファイルの新しいディレクトリ ツリーを作成するために、ある種のビルド システムが必要になります。

あるいは、すべてのデバッグ ステートメントをif __debug__:ブロックに入れると、Python を -O (最適化) フラグで実行すると最適化されます。

余談ですが、 dis モジュールを使用してコードをチェックし、最適化されていることを確認しました。両方あることを発見しました

if __debug__: doStuff()

if 0: doStuff()

最適化されていますが、

if False: doStuff()

ではありません。これは、False が通常の Python オブジェクトであり、実際に次のように実行できるためです。

>>> False = True
>>> if False: print "Illogical, captain"
Illogical, captain

これは言語の欠陥のように思えます-うまくいけば、Python 3で修正されます.

編集:

これは Python 3 で修正されました: True または False に代入するとSyntaxError が返されるようになりました。True と False は Python 3 では定数であるため、if False: doStuff()最適化されていることを意味します。

>>> def f():
...     if False: print( "illogical")
... 
>>> dis.dis(f)
  2           0 LOAD_CONST               0 (None) 
              3 RETURN_VALUE         
于 2010-01-05T14:33:39.680 に答える
1

まあ、トリックを行う独自の単純なプリプロセッサをいつでも実装できます。または、さらに良いことに、既存のものを使用できます。http://code.google.com/p/preprocess/と言います。

于 2010-01-05T15:13:02.987 に答える
0

モジュールスコープの変数を使用しますか?

from config_module import debug_flag

この「変数」を使用して、ロギング機能へのアクセスをゲートします。を使用してロギング機能をゲートするloggingモジュールを自分で作成します。debug_flag

于 2010-01-05T13:14:12.407 に答える
0

私は 'if __debug_' ソリューションが好きですが、それをすべての呼び出しの前に置くのは少し気を散らして醜いです。私はこれと同じ問題を抱えていましたが、ソース ファイルを自動的に解析し、ロギング ステートメントをパス ステートメントに置き換える (そしてロギング ステートメントのコピーをコメント化した) スクリプトを作成することで、それを克服しました。この変換を元に戻すこともできます。

本番環境で不要なログ ステートメントが多数あり、パフォーマンスに影響を与えている場合に、新しいコードを本番環境にデプロイするときに使用します。

ここでスクリプトを見つけることができます: http://dound.com/2010/02/python-logging-performance/

于 2010-02-07T21:32:12.743 に答える
0

Python は C とは異なる方法で動作するため、関数の呼び出しを完全に回避することは不可能だと思います。 #define は、コードがコンパイルされる前に、プリコンパイラで行われます。Python では、そのようなことはありません。

作業環境でデバッグの呼び出しを完全に削除したい場合は、実行前に実際にコードを変更することが唯一の方法だと思います。実行前のスクリプトを使用すると、デバッグ行をコメント化/コメント解除できます。

このようなもの:

ファイル logging.py

#Main module
def log():
    print 'logging'

def main():
    log()
    print 'Hello'
    log()

ファイル call_log.py

import re
#To log or not to log, that's the question
log = True

#Change the loging
with open('logging.py') as f:
    new_data = []
    for line in f:
       if not log and re.match(r'\s*log.*', line):
         #Comment
         line = '#' + line
       if log and re.match(r'#\s*log.*', line):
         #Uncomment
         line = line[1:]
       new_data.append(line)

#Save file with adequate log level
with open('logging.py', 'w') as f:
   f.write(''.join(new_data))


#Call the module
import logging
logging.main()

もちろん、特に多くのモジュールがあり複雑な場合は問題がありますが、関数の呼び出しを絶対に回避する必要がある場合は使用できます。

于 2010-01-05T14:16:22.613 に答える
0

何もしない関数を定義する、つまり

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

次に、取り除きたいすべての関数を関数 ala でオーバーロードするだけです。

logging.debug = nuzzing
于 2010-01-05T23:38:09.417 に答える
-1

関数呼び出しをスキップすることはできません。ただし、これらを空として再定義することもできます。たとえば、同じインターフェイスを提供するが空の関数を持つ別のログ オブジェクトを作成することによってです。

しかし、最もクリーンなアプローチは、優先度の低いログメッセージを無視することです (あなたが提案したように):

logging.root.setLevel(logging.CRITICAL)
于 2010-01-05T14:53:59.850 に答える