47

コマンドラインに -v オプションを追加して、異なる詳細レベルを指定できるようにしたいと考えています。例えば:

$ myprogram.py    
$ myprogram.py -v
$ myprogram.py -vv
$ myprogram.py -v -v -v

それぞれ verbose=0、verbose=1、verbose=2、verbose=3 になります。argparseを使用してそれを達成するにはどうすればよいですか?

必要に応じて、次のように指定することもできます

$ myprogram -v 2
4

8 に答える 8

151

argparse は以下をサポートしますaction='count':

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='count', default=0)

for c in ['', '-v', '-v -v', '-vv', '-vv -v', '-v -v --verbose -vvvv']:
    print(parser.parse_args(c.split()))

出力:

Namespace(verbose=0)
Namespace(verbose=1)
Namespace(verbose=2)
Namespace(verbose=2)
Namespace(verbose=3)
Namespace(verbose=7)

唯一の非常に些細な問題は、引数を使用せずに詳細レベルを 0 ではなく 0 にする場合は、明示的に設定default=0する必要があることです。-vNone

于 2011-12-01T02:35:34.100 に答える
25

nargs='?'これは、(フラグの後に 0 または 1 個の引数を受け入れるため-v) とカスタム アクション (0 または 1 個の引数を処理するため) で行うことができます。

import sys
import argparse

class VAction(argparse.Action):
    def __init__(self, option_strings, dest, nargs=None, const=None, 
                 default=None, type=None, choices=None, required=False, 
                 help=None, metavar=None):
        super(VAction, self).__init__(option_strings, dest, nargs, const, 
                                      default, type, choices, required, 
                                      help, metavar)
        self.values = 0
    def __call__(self, parser, args, values, option_string=None):
        # print('values: {v!r}'.format(v=values))
        if values is None:
            self.values += 1
        else:
            try:
                self.values = int(values)
            except ValueError:
                self.values = values.count('v')+1
        setattr(args, self.dest, self.values)

# test from the command line
parser = argparse.ArgumentParser()
parser.add_argument('-v', nargs='?', action=VAction, dest='verbose')
args = parser.parse_args()
print('{} --> {}'.format(sys.argv[1:], args))

print('-'*80)

for test in ['-v', '-v -v', '-v -v -v', '-vv', '-vvv', '-v 2']:
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', nargs='?', action=VAction, dest='verbose')
    args=parser.parse_args([test])
    print('{:10} --> {}'.format(test, args))

script.py -v -vコマンドラインから実行すると

['-v', '-v'] --> Namespace(verbose=2)
--------------------------------------------------------------------------------
-v         --> Namespace(verbose=1)
-v -v      --> Namespace(verbose=2)
-v -v -v   --> Namespace(verbose=3)
-vv        --> Namespace(verbose=2)
-vvv       --> Namespace(verbose=3)
-v 2       --> Namespace(verbose=2)

print ステートメントのコメントを外して、VActionが何をしているかをよく確認してください。

于 2011-05-20T19:33:38.453 に答える
15

質問の最初の部分は で処理できますappend_constそれ以外の場合は、 unutbu による優れた回答で示唆されているように、カスタム アクションの作成に行き詰まっている可能性があります。

import argparse

ap = argparse.ArgumentParser()
ap.add_argument('-v', action = 'append_const', const = 1)

for c in ['', '-v', '-v -v', '-vv', '-vv -v']:
    opt = ap.parse_args(c.split())
    opt.v = 0 if opt.v is None else sum(opt.v)
    print opt

出力:

Namespace(v=0)
Namespace(v=1)
Namespace(v=2)
Namespace(v=2)
Namespace(v=3)
于 2011-05-20T19:44:26.913 に答える
4

unutbu の回答を拡張して、 --quiet/-q の組み合わせの処理を含むカスタム アクションを次に示します。これは Python3 でテストされています。Python >=2.7 で使用することは大したことではありません。

class ActionVerbose(argparse.Action):
    def __call__(self, parser, args, values, option_string=None):
        #print(parser, args, values, option_string)
        # Obtain previously set value in case this option call is incr/decr only
        if args.verbose == None:
            base = 0
        else:
            base = args.verbose
        # One incr/decr is determined in name of option in use (--quiet/-q/-v/--verbose)
        option_string = option_string.lstrip('-')
        if option_string[0] == 'q':
            incr = -1
        elif option_string[0] == 'v':
            incr = 1
        else:
            raise argparse.ArgumentError(self,
                                         'Option string for verbosity must start with v(erbose) or q(uiet)')
        # Determine if option only or values provided
        if values==None:
            values = base + incr
        else:
            # Values might be an absolute integer verbosity level or more 'q'/'v' combinations
            try:
                values = int(values)
            except ValueError:
                values = values.lower()
                if not re.match('^[vq]+$', values):
                    raise argparse.ArgumentError(self,
                                                 "Option string for -v/-q must contain only further 'v'/'q' letters")
                values = base + incr + values.count('v') - values.count('q')
        setattr(args, self.dest, values)
    @classmethod
    def add_to_parser(cls,
                      parser, dest='verbose', default=0,
                      help_detail='(0:errors, 1:info, 2:debug)'):
        parser.add_argument('--verbose', nargs='?', action=ActionVerbose, dest=dest, metavar='level',
                            default=default,
                            help='Increase or set level of verbosity {}'.format(help_detail))
        parser.add_argument('-v',        nargs='?', action=ActionVerbose, dest=dest, metavar='level',
                            help='Increase or set level of verbosity')
        parser.add_argument('--quiet',   nargs='?', action=ActionVerbose, dest=dest, metavar='level',
                            help='Decrease or set level of verbosity')
        parser.add_argument('-q',        nargs='?', action=ActionVerbose, dest=dest, metavar='level',
                            help='Decrease or set level of verbosity')

--verbose-v-q、の 4 つのオプション ハンドラすべてを設定するために使用できる便利なクラス メソッドがあります--quiet。次のように使用します。

parser = argparse.ArgumentParser()
ActionVerbose.add_to_parser(parser, default=defaults['verbose'])
# add more arguments here with: parser.add_argument(...)
args = parser.parse_args()

これらの引数を持つスクリプトを使用すると、次のことができます。

./script -vvvvvv -v 4 -v 0 -v -vvv --verbose --quiet 2 -v qqvvqvv

このコマンド ラインargs.verboseでは、4.

  • 指定された数値を持つ任意のものは、その指定された数値 (=冗長レベル)-v/-q/--verbose/--quietのハードで絶対的なセットです。args.verbose
  • 数字のない-v/--verboseものは、そのレベルの増分です。
  • 数値のない-q/--quietものは、そのレベルの減少です。
  • いずれかがすぐに追加の文字で-v/-qフォローアップされる可能性があり、結果のレベルは次のとおりです。v/qthe old level + sum(count('v')) - sum(count('q'))
  • 全体のデフォルトは 0 です

カスタム アクションは、別の動作が必要な場合に備えて、かなり簡単に変更できるはずです。--quietたとえば、 anyがレベルを 0 または -1 にリセットすることを好む人もいます。このために、 と の add_argumentからnargsを削除し、さらにset にハードコードします。-q--quietvalue = 0 if option_string[0] == 'q'

使用方法が間違っている場合、適切なパーサー エラーが適切に出力されます。

./script -vvvvvv -v 4 -v 0 -v -vvv --verbose --quiet 2 -v qqvvqvav
usage: script [-h] [--verbose [level]]
              [-v [level]] [--quiet [level]] [-q [level]]
script: error: argument -v: Option string for -v/-q must contain only further 'v'/'q' letters
于 2012-08-28T09:03:47.380 に答える
2

argparseappend複数の引数を指定できるアクションをサポートします。http://docs.python.org/library/argparse.htmlを確認し、「 」を検索してくださいappend

于 2011-05-20T19:29:26.353 に答える
0

最初に提案された方法は、混乱する可能性が高くなります。詳細レベルごとに異なるオプション名を使用するか、1 つの詳細フラグの後にオプションで詳細レベルの数値インジケータを指定すると、ユーザーが混乱する可能性が低くなり、詳細レベルをより柔軟に割り当てることができます。

于 2011-05-21T02:40:47.143 に答える
0

別の方法を思いつきました。OPの要求と完全には一致しません、私の要件を満たし、共有する価値があると思いました.

相互に排他的なグループを使用して、短いオプションの数をカウントするか、長いオプションの整数値を格納します。

import argparse

parser = argparse.ArgumentParser()
verbosity_group = parser.add_mutually_exclusive_group()
verbosity_group.add_argument(
  '-v',
  action='count',
  dest='verbosity',
  help='Turn on verbose output. Use more to turn up the verbosity level'
)
verbosity_group.add_argument(
  '--verbose',
  action='store',
  type=int,
  metavar='N',
  dest='verbosity',
  help='Set verbosity level to `N`'
)
parser.set_defaults(
  verbosity=0
)
parser.parse_args()
parser.parse_args([])
# Namespace(verbosity=0)
parser.parse_args(['-v', '-vv'])
# Namespace(verbosity=3)
parser.parse_args(['--verbose=4'])
# Namespace(verbosity=4)
parser.parse_args(['--verbose'])
# error: argument --verbose: expected one argument

ご覧のとおり、単一の char オプションを「積み重ねる」ことができ、長いオプション名を使用して値を明示的に設定できます。欠点は、長いオプションをスイッチとして使用できないことです (最後の例では例外が生成されます)。

于 2020-05-08T11:18:34.573 に答える