2017-02-19 2 views
4

私はさまざまなarg名で自分のプログラムを呼び出す上流システムを持っています。例:argparseでの可変arg名の使用

foo --xyz1 10 --xyz2 25 --xyz3 31 

私はargparsingの結果をxyz = [10、25、31]にしたいと思います。

私のargsの名前は共通の接頭辞を持っていますが、残念ながら少なくとも順序が異なる別の数値接尾辞とは異なる必要があります。私もargsの固定数を持っていません。

これをargparseでモデル化する方法はありますか?組み込み機能のいくつかの組み合わせを介して利用可能なもの、またはカスタムパーサーの処理をオーバーライド/プルーインすることによって可能です。

+1

'action = 'append''は、' --xyz'フラグを再利用させ、指定された順序で値を収集します。 '--xyz 10 --xyz 25 --xyz 31' – hpaulj

+0

私はさまざまなarg名を使う必要があります。システムの別の部分からの要件です。ですから、私は--xyz1、--xyz2、--xyz3などを扱う必要があります。 –

+0

これらの変数名キーの多くはありますか?このような3、または100? – hpaulj

答えて

3

私はこれを達成するために前処理のビットをお勧めします:

コード:テストするために

def get_xyz_cmd_line(xyz_cmd_line): 
    # build a generator to iterate the cmd_line 
    cmd_line_gen = iter(xyz_cmd_line) 

    # we will separate the xyz's from everything else 
    xyz = [] 
    remaining_cmd_line = [] 

    # go through the command line and extract the xyz's 
    for opt in cmd_line_gen: 
     if opt.startswith('--xyz'): 
      # grab the opt and the arg for it 
      xyz.append((opt, cmd_line_gen.next())) 
     else: 
      remaining_cmd_line.append(opt) 

    # sort the xyz's and return all of them as -xyz # -xyz # ... 
    return list(it.chain(*[ 
     ('--xyz', x[1]) for x in sorted(xyz)])) + remaining_cmd_line 

import argparse 
import itertools as it 

parser = argparse.ArgumentParser(description='Get my Option') 
parser.add_argument('--an_opt', metavar='N', type=int, 
        help='An option') 
parser.add_argument('--xyz', metavar='N', type=int, action='append', 
        help='An option') 

cmd_line = "--an_opt 1 --xyz1 10 --xyz3 31 --xyz2 25 ".split() 
args = parser.parse_args(get_xyz_cmd_line(cmd_line)) 
print(args) 

出力:

Namespace(an_opt=1, xyz=[10, 25, 31]) 

使用するには:

を名目上の代わりに固定cmd_lineの上記の例のように、これはのようなものを使って呼び出されます:

args = parser.parse_args(get_xyz_cmd_line(sys.argv[1:])) 

UPDATE:あなたが必要な場合は--xyz = 31(=セパレータ):

次に変更する必要があります:

# grab the opt and the arg for it 
xyz.append((opt, cmd_line_gen.next())) 

へ:

if '=' in opt: 
    xyz.append(tuple(opt.split('=', 1))) 
else: 
    # grab the opt and the arg for it 
    xyz.append((opt, cmd_line_gen.next())) 
+0

私はあなたの解決策が好きです。なぜなら、私のために(内部の実装の詳細に依存して投稿されたので)です。しかし、引数の定義を追加するコンポーネントとparse_argsを呼び出すユーザーがあるので、私はそれを使うことができるかどうかはまだ分かりません。ユーザーに知らせたくないのための前処理。派生したargparserとカスタムアクションでは、このシナリオはユーザーの介入なしに実行されます。 –

1

は、ここで私はまた、スティーブン・ラウフの答えのように(私は答えとしてそれをマークしますけれども、私は、参照(迅速かつ汚いバージョン)のためにやったことだ - ESP。私は)私の解決策のための内部実装の詳細を使用するので:

class CustomArgumentsParser(argparse.ArgumentParser): 

    def _parse_optional(self, arg_string): 
    suffix_index = arg_string.find(':') 
    if suffix_index < 0: 
     return super(CustomArgumentParser, self)._parse_optional(arg_string) 

    original_arg_string = arg_string 
    suffix = arg_string[suffix_index + 1:] 
    arg_string = arg_string[0:suffix_index] 

    option_tuple = super(CustomArgumentParser, self)._parse_optional(arg_string) 
    if not option_tuple: 
     return option_tuple 

    action, option_string, explicit_arg = option_tuple 
    if isinstance(action, BuildListAction): 
     return action, suffix, explicit_arg 
    else: 
     self.exit(-1, message='Unknown argument %s' % original_arg_string) 


class BuildListAction(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(BuildListAction, self).__init__(
     option_strings=option_strings, 
     dest=dest, 
     nargs=nargs, 
     const=const, 
     default=default, 
     type=type, 
     choices=choices, 
     required=required, 
     help=help, 
     metavar=metavar) 

    def __call__(self, parser, namespace, values, option_string=None): 
    index = int(option_string) - 1 

    list = getattr(namespace, self.dest) 
    if list is None: 
     list = [] 
     setattr(namespace, self.dest, list) 

    if index >= len(list): 
     list.extend([self.default] * (index + 1 - len(list))) 
    list[index] = values 

使用法:

argparser = CustomArgumentsParser() 
argparser.add_argument('--xyz', type=int, action=BuildListAction) 

注 - これは、フォーム--xyzの引数サポートしています、2 ..:1、--xyzをこれは元の質問とは少し異なります。

関連する問題