_nargs='*'
_は可変数の引数を処理するのに十分だと思いました。どうやらそうではなく、私はこのエラーの原因を理解していません。
コード:
_p = argparse.ArgumentParser()
p.add_argument('pos')
p.add_argument('foo')
p.add_argument('--spam', default=24, type=int, dest='spam')
p.add_argument('vars', nargs='*')
p.parse_args('1 2 --spam 8 8 9'.split())
_
結果の名前空間はNamespace(pos='1', foo='2', spam='8', vars=['8', '9'])
になるはずです。代わりに、argparseは次のエラーを返します。
_usage: prog.py [-h] [--spam SPAM] pos foo [vars [vars ...]]
error: unrecognized arguments: 9 8
_
基本的に、argparseはこれらの追加の引数をどこに置くべきかを知りません...なぜですか?
関連するPythonバグは Issue 15112 です。
_
argparse: nargs='*'
_定位置引数は、オプションと別の定位置が先行する場合、項目を受け入れません。
Argparseが_['1', '2', '--spam', '8', '8', '9']
_を解析するとき、最初に_['1','2']
_をできるだけ多くの位置引数と一致させようとします。引数のパターンマッチング文字列は_AAA*
_:pos
およびfoo
にそれぞれ1つの引数、およびvars
にゼロの引数(_*
_はZERO_OR_MOREを意味します)。
_['--spam','8']
_は、_--spam
_引数によって処理されます。 vars
はすでに_[]
_に設定されているため、_['8','9']
_を処理するものは何もありません。
argparse
へのプログラミング変更は、_0
_引数文字列がパターンを満たしている場合をチェックしますが、解析されるoptionals
がまだあります。次に、その_*
_引数の処理を延期します。
最初に _parse_known_args
_ で入力を解析し、次に別の呼び出しでremainder
を処理することで、これを回避できる場合があります _parse_args
_ .
issue 14191 で位置間のオプションを散在させる完全な自由を得るために、optionals
だけで_parse_known_args
_を使用することを提案します。位置のみを知っている_parse_args
_によって。そこで投稿した_parse_intermixed_args
_関数は、_argparse.py
_コード自体を変更せずに、ArgumentParser
サブクラスに実装できます。
サブパーサーの処理方法は次のとおりです。私は _parse_known_intermixed_args
_ 関数を取り、表示のために単純化してから、パーサーの_parse_known_args
_関数にしましたサブクラス。再帰を避けるために追加のステップを踏まなければなりませんでした。
最後に、サブパーサーアクションの__parser_class
_を変更したので、各サブパーサーはこの代替_parse_known_args
_を使用します。代わりに、サブクラス__SubParsersAction
_を使用し、おそらく___call__
_を変更します。
_from argparse import ArgumentParser
def parse_known_intermixed_args(self, args=None, namespace=None):
# self - argparse parser
# simplified from http://bugs.python.org/file30204/test_intermixed.py
parsefn = super(SubParser, self).parse_known_args # avoid recursion
positionals = self._get_positional_actions()
for action in positionals:
# deactivate positionals
action.save_nargs = action.nargs
action.nargs = 0
namespace, remaining_args = parsefn(args, namespace)
for action in positionals:
# remove the empty positional values from namespace
if hasattr(namespace, action.dest):
delattr(namespace, action.dest)
for action in positionals:
action.nargs = action.save_nargs
# parse positionals
namespace, extras = parsefn(remaining_args, namespace)
return namespace, extras
class SubParser(ArgumentParser):
parse_known_args = parse_known_intermixed_args
parser = ArgumentParser()
parser.add_argument('foo')
sp = parser.add_subparsers(dest='cmd')
sp._parser_class = SubParser # use different parser class for subparsers
spp1 = sp.add_parser('cmd1')
spp1.add_argument('-x')
spp1.add_argument('bar')
spp1.add_argument('vars',nargs='*')
print parser.parse_args('foo cmd1 bar -x one 8 9'.split())
# Namespace(bar='bar', cmd='cmd1', foo='foo', vars=['8', '9'], x='one')
_
簡単な解決策:pos
およびfoo
を指定する前に、--spam
フラグを指定します。
p = argparse.ArgumentParser()
p.add_argument('pos')
p.add_argument('foo')
p.add_argument('--spam', default=24, type=int, dest='spam')
p.add_argument('vars', nargs='*')
p.parse_args('--spam 8 1 2 8 9'.split())
変数引数を指定した後に--spam
フラグを置いた場合も同じことが言えます。
p = argparse.ArgumentParser()
p.add_argument('pos')
p.add_argument('foo')
p.add_argument('--spam', default=24, type=int, dest='spam')
p.add_argument('vars', nargs='*')
p.parse_args('1 2 8 9 --spam 8'.split())
編集:それが価値があるものについては、*
を+
に変更するとエラーも修正されるようです。
p = argparse.ArgumentParser()
p.add_argument('pos')
p.add_argument('foo')
p.add_argument('--spam', default=24, type=int, dest='spam')
p.add_argument('vars', nargs='+')
p.parse_args('1 2 --spam 8 8 9'.split())