これは私がまとめた簡単なハックであり、始めるのに妥当な場所かもしれません:
import argparse
class PositionalAction(argparse.Action):
def __call__(self,parser,namespace,values,option_string=None):
lst = getattr(namespace,self.dest)
lst.append(values)
parser.last_positional_values = lst
all_positional = getattr(namespace,'all_positional',[])
all_positional.append(lst)
namespace.all_positional = all_positional
class AssociateAction(argparse.Action):
def __call__(self,parser,namespace,values,option_string=None):
try:
parser.last_positional_values.append(values)
except AttributeError:
pass
parser = argparse.ArgumentParser()
parser.add_argument('-o',action=AssociateAction,dest=argparse.SUPPRESS)
junk,unknown = parser.parse_known_args()
for i,_ in enumerate(unknown):
parser.add_argument('arg%d'%i,action=PositionalAction,default=[])
print parser.parse_args()
そして、ここでそれが実行されています:
temp $ python test1.py foo -o 1 bar -o 2 baz qux -o 4
Namespace(all_positional=[['foo', '1'], ['bar', '2'], ['baz'], ['qux', '4']], arg0=['foo', '1'], arg1=['bar', '2'], arg2=['baz'], arg3=['qux', '4'])
この問題にはいくつかの課題があります。まず、任意の数の位置引数を受け入れたい - argparse はそれを好まない。argparse は、何を期待するかを事前に知りたがっています。解決策は、パーサーを作成してコマンドラインを解析することですが、既知の引数のみを解析するように argparse に指示することです (この場合、非位置-o
引数はすべてサイレントに解析されますが、「位置」引数は解析されません)。 parse_known_args
の形式でタプルを返すため、これに最適です(namespace_of_parsed_stuff, uknown_args)
。これで、未知の引数がわかりました。parse_args を満足させるには、パーサーごとに位置引数を追加するだけです。
では、カスタム アクションは実際に何をしているのでしょうか。位置引数が (2 番目のパスで) 見つかった場合、デフォルト (リスト) を取得し、そのリストに値を追加します (以降、「値」リストと呼びます)。次に、「値」リストへの参照を使用してパーサーを変更します。名前空間から「all_positional」リストも取得します。その属性がない場合は、空のリストを取得します。「値」リストを「all_positional」リストに追加し、名前空間に戻します。
ここで、-o
フラグをヒットすると、パーサーを調べて「値」リストを取得し、そのリストに追加の値を追加します。パーサーにまったく触れずに同じことを行うことができます...(見ることができますnamespace.all_positional[-1]
-それは と同じリストparser.last_positional_values
です)。