web-dev-qa-db-ja.com

--verboseまたは-vオプションをスクリプトに実装する方法は?

--verbose または -vいくつかのツールから。これを自分のスクリプトやツールに実装したい。

私は配置することを考えました:

if verbose:
    print ...

ユーザーが-vオプション、変数verboseTrueに設定され、テキストが印刷されます。

これは正しいアプローチですか、それとももっと一般的な方法がありますか?

追加:引数の解析を実装する方法を求めていません。私はそれがどのように行われるかを知っている。私は特に冗長オプションにのみ興味があります。

77
Aufwind

私の提案は、関数を使用することです。ただし、ifを関数に配置するのではなく、これを実行したいと思うかもしれませんが、次のようにします。

_if verbose:
    def verboseprint(*args):
        # Print each argument separately so caller doesn't need to
        # stuff everything to be printed into a single string
        for arg in args:
           print arg,
        print
else:   
    verboseprint = lambda *a: None      # do-nothing function
_

(はい、ifステートメントで関数を定義できます。条件が真の場合にのみ定義されます!)

Python 3を使用している場合、printは既に関数です(または2.xでprintを関数として使用する場合) _from __future__ import print_function_)を使用すると、さらに簡単になります。

_verboseprint = print if verbose else lambda *a, **k: None
_

この方法では、verboseフラグを常にテストする代わりに、冗長モードがオフの場合(ラムダを使用)、関数は何もしないと定義されます。

ユーザーがプログラムの詳細モード実行中を変更できる場合、これは間違ったアプローチになります(関数にifが必要になります)が、コマンドラインフラグを使用して設定する場合は、一度だけ決定する必要があります。

次に使用しますverboseprint("look at all my verbosity!", object(), 3) "verbose"メッセージを出力したいときはいつでも。

93
kindall

loggingモジュールを使用します。

import logging as log
…
args = p.parse_args()
if args.verbose:
    log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
    log.info("Verbose output.")
else:
    log.basicConfig(format="%(levelname)s: %(message)s")

log.info("This should be verbose.")
log.warning("This is a warning.")
log.error("This is an error.")

これらはすべて自動的にstderrに移動します。

% python myprogram.py
WARNING: This is a warning.
ERROR: This is an error.

% python myprogram.py -v
INFO: Verbose output.
INFO: This should be verbose.
WARNING: This is a warning.
ERROR: This is an error.

詳細については、 Python Docs および tutorials をご覧ください。

53
Profpatsch

@kindallの答えを構築して単純化するために、私が通常使用するものを次に示します。

v_print = None
def main()
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', '--verbosity', action="count", 
                        help="increase output verbosity (e.g., -vv is more than -v)")

    args = parser.parse_args()

    if args.verbosity:
        def _v_print(*verb_args):
            if verb_args[0] > (3 - args.verbosity):
                print verb_args[1]  
    else:
        _v_print = lambda *a: None  # do-nothing function

    global v_print
    v_print = _v_print

if __== '__main__':
    main()

これにより、スクリプト全体で次の使用方法が提供されます。

v_print(1, "INFO message")
v_print(2, "WARN message")
v_print(3, "ERROR message")

スクリプトは次のように呼び出すことができます。

% python verbose-tester.py -v
ERROR message

% python verbose=tester.py -vv
WARN message
ERROR message

% python verbose-tester.py -vvv
INFO message
WARN message
ERROR message

いくつかのメモ:

  1. 最初の引数はエラーレベルであり、2番目はメッセージです。 3のマジックナンバーは、ロギングの上限を設定しますが、簡単にするために妥協案として受け入れます。
  2. v_printをプログラム全体で機能させたい場合は、グローバルでジャンクを実行する必要があります。面白くありませんが、誰かにもっと良い方法を見つけるように挑戦します。
11
mlissner

スクリプトで行うことは、実行時に「verbose」オプションが設定されているかどうかを確認し、ログレベルをデバッグに設定することです。設定されていない場合は、infoに設定します。この方法では、コード全体に「if verbose」チェックがありません。

9
jonesy

私のプロジェクトの ロギングコード から virtualenv を盗みました。 virtualenv.pymain()を見て 初期化方法 コードにlogger.notify()logger.info()logger.warn()など。実際に出力を出すメソッドは、virtualenvが-v-vv-vvv、または-qのどれで呼び出されたかによって決まります。

2

冗長フラグをチェックするvprintと呼ばれる関数がある場合は、よりクリーンになります。次に、オプションの冗長性が必要な場所で、独自のvprint関数を呼び出すだけです。

2
Lee-Man

グローバル変数は、おそらくsys.argvからのargparseで設定され、プログラムが冗長であるかどうかを表します。次に、冗長性がオンの場合、関数が実行される限り、標準入力がヌルデバイスに迂回されるようにデコレータを作成できます。

import os
from contextlib import redirect_stdout
verbose = False

def louder(f):
    def loud_f(*args, **kwargs):
        if not verbose:
            with open(os.devnull, 'w') as void:
                with redirect_stdout(void):
                    return f(*args, **kwargs)
        return f(*args, **kwargs)
    return loud_f

@louder
def foo(s):
    print(s*3)

foo("bar")

この答えは this code ;に触発されています。実際、プログラムでモジュールとして使用するだけでしたが、理解できないエラーが発生したため、その一部を修正しました。

このソリューションの欠点は、loggingとは異なり、冗長性がバイナリであるため、プログラムの冗長性をさらに微調整できることです。また、allprint呼び出しは迂回されますが、これは望ましくない可能性があります。

1
Daniel Diniz

@ kindallの解決策 はmy Pythonバージョン3.5では動作しません。@ stylesは、理由が追加のオプションkeywords引数。したがって、Python 3のわずかに洗練されたバージョンは次のようになります。

if VERBOSE:
    def verboseprint(*args, **kwargs):
        print(*args, **kwargs)
else:
    verboseprint = lambda *a, **k: None # do-nothing function
1
stefanct

私が必要なのは、オブジェクト(obj)を出力する関数ですが、グローバル変数の詳細がtrueの場合にのみ、それ以外は何もしません。

グローバルパラメータ "verbose"をいつでも変更できるようにしたいです。私にとってシンプルさと読みやすさは非常に重要です。したがって、次の行が示すように進めます。

ak@HP2000:~$ python3
Python 3.4.3 (default, Oct 14 2015, 20:28:29) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> verbose = True
>>> def vprint(obj):
...     if verbose:
...         print(obj)
...     return
... 
>>> vprint('Norm and I')
Norm and I
>>> verbose = False
>>> vprint('I and Norm')
>>> 

グローバル変数「verbose」もパラメータリストから設定できます。

0
user377367