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


94

私は知っています --verbose-vいくつかのツールからまたはそれこれを自分のスクリプトやツールのいくつかに実装したいと思います。

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

if verbose:
    print ...

私のソースコードを通じて、ユーザーが -vオプションと、変数verboseがに設定されTrue、テキストが印刷されるます。

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

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


9
ロギングモジュールを使用して、デフォルトでログレベルINFOを設定し、-verboseが渡されたときにデバッグするのはなぜですか?言語ですでに利用可能なものを再実装しないことをお勧めします...
Tim

3
@ティム、私は同意するが、ロギングモジュールはかなり痛い。
mlissner 2013

回答:


106

私の提案は、関数を使用することです。しかし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ステートメントで。条件がtrueの場合にのみ定義されます!)

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

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

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

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

次に、たとえばverboseprint("look at all my verbosity!", object(), 3)「冗長」メッセージを出力するときに使用します。


1
さらに良いことに、print関数として実行します。多くの引数を受け入れます。print(*args)3.xおよびfor arg in args: print arg,2.x と同様に実装できます。主な利点は、明示的なstr呼び出し/フォーマットおよび連結を行わずに、1つのメッセージ内で文字列や他のタイプのものを混合できることです。

print arg,行の終わりに使用されるコンマは何ですか?
SamK

これは、実験的に、またはドキュメントを確認することで簡単に判断できますが、通常は印刷される改行が抑制されます。
キンダル

5
Pythonの3印刷機能は、完全に印刷の機能を再現するので、オプションのキーワード引数を取る:def verboseprint(*args, **kwargs): print(*args, **kwargs)
lstyls

61

使用する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ドキュメントチュートリアルをご覧ください


8
ここのPython Docsのとおり、プログラムの通常の実行で出力を印刷するだけでよい場合は、ロギングを使用しないでください。OPが望んでいるように見えます。
SANDeveloper 2016

1
これは基本的な問題には問題ないようですが、多くの* nixコマンドは複数レベルの冗長性(-v -v -vなど)もサポートしているため、この方法では面倒になる可能性があります。
TextGeek

12

@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 __name__ == '__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プログラム全体で作業したい場合は、グローバルでジャンクを実行する必要があります。面白くないですが、もっといい方法を見つけるように誰かに挑戦します。

1
INFOとWARNのロギングモジュールを使用しないのはなぜですか?-v使用時にインポートします。現在のソリューションでは、すべてがstderrではなくstdoutにダンプされます。そして、あなたは通常、すべてのエラーをユーザーに中継したいと思いませんか?
Profpatsch 2013年

2
ええ、それは公平な点です。ロギングには、私が避けようとしていた認識上のオーバーヘッドがありますが、おそらくそれは「正しい」ことです。過去に私を悩ませたばかりです...
mlissner '14

9

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


2

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



2

@kindallのソリューションは、Pythonバージョン3.5では機能しません。@stylesは彼のコメントで、理由は追加のオプションのキーワード引数であることを正しく述べています。したがって、Python 3の少し洗練されたバージョンは次のようになります。

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

1

プログラムを冗長にする必要があるかどうかを表すグローバル変数(おそらくargparsefrom sys.argvで設定される)が存在する可能性があります。次に、冗長性がオンの場合、関数が実行される限り、標準入力がnullデバイスに転送されるようにデコレータを作成できます。

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")

この答えはこのコードに触発されています。実際には、プログラムのモジュールとして使用するつもりでしたが、理解できないエラーが発生したため、一部を変更しました。

このソリューションの欠点は、とは異なり、冗長性がバイナリloggingであるため、プログラムの冗長性をより細かく調整できることです。また、すべての print呼び出しが迂回されるため、望ましくない場合があります。


0

私が必要としているのは、オブジェクト(obj)を出力する関数ですが、グローバル変数verboseが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"もパラメータリストから設定できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.