9

GNU getopt と、それを使用するコマンド ライン ツールを使用すると、オプションと引数を交互に並べることができます。 -Getopt )。Perl の Getopt::Long モジュールもこれをサポートしています (qw(:config gnu_getopt) を使用)。argparse は、並べ替えオプションをサポートしていないようです (または言及していません)。

arg/opt の順序に関連する SO の質問はたくさんありますが、この質問に答えるものはないようです。

ユース ケースは、GNU sort のような典型的なコマンド ライン シグネチャです。

sort [opts] [files]

1) オプションとファイルが並べ替えられ、2) ファイル リストには 0 個以上の引数が含まれる場合があります。

例えば:

import argparse
p = argparse.ArgumentParser();
p.add_argument('files',nargs='*',default=['-']);
p.add_argument('-z',action='store_true')

p.parse_args(['-z','bar','foo']) # ok
p.parse_args(['bar','foo','-z']) # ok
p.parse_args(['bar','-z','foo']) # not okay
usage: ipython [-h] [-z] [files [files ...]]

私はもう試した:

  • p.parse_known_args -- 文句を言いませんが、実際には並べ替えもしませんし、無効なオプションのように見える引数 (例えば、上記の --bogus や -b) についても躊躇しません。
  • p.add_argument('files',nargs=argparse.REMAINDER) -- 位置引数の前でない限り、オプション -z がファイルに含まれます
  • p.add_argument('files',nargs='*',action='append');

上記の GNU ソート プロトタイプに近いものを実装したいと考えています。ファイルごとに指定できるフラグ (例: -f file1 -f file2) には興味がありません。

4

3 に答える 3

4

引数リストを一度に1つ(オプション、位置引数)のペアでデコードする簡単なソリューションを次に示します。

import argparse

class ExtendAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        items = getattr(namespace, self.dest, None)
        if items is None:
            items = []
        items.extend(values)
        setattr(namespace, self.dest, items)

parser = argparse.ArgumentParser()
parser.add_argument('files', nargs='*', action=ExtendAction)
parser.add_argument('-z', action='store_true')
parser.add_argument('-v', action='count')
parser.add_argument('args_tail', nargs=argparse.REMAINDER)

def interleaved_parse(argv=None):
    opts = parser.parse_args(argv)
    optargs = opts.args_tail
    while optargs:
        opts = parser.parse_args(optargs, opts)
        optargs = opts.args_tail
    return opts

print(interleaved_parse('-z bar foo'.split()))
print(interleaved_parse('bar foo -z'.split()))
print(interleaved_parse('bar -z foo'.split()))
print(interleaved_parse('-v a -zv b -z c -vz d -v'.split()))

出力:

Namespace(args_tail=[], files=['bar', 'foo'], v=None, z=True)
Namespace(args_tail=[], files=['bar', 'foo'], v=None, z=True)
Namespace(args_tail=[], files=['bar', 'foo'], v=None, z=True)
Namespace(args_tail=[], files=['a', 'b', 'c', 'd'], v=4, z=True)

注: 他の非フラグ引数 (単一nargs='*'の引数と引数以外args_tail) でこれを使用しようとしないでください。パーサーは の以前の呼び出しを認識しないparse_argsため、これらのフラグ以外の引数に間違った値を格納します。nargs='*'回避策として、を使用した後に引数を手動で解析できますinterleaved_parse

于 2012-08-16T11:24:22.613 に答える
3

argparse のドキュメントで、並べ替えができるかできないかを述べている決定的なものは何も見たことがありません。順列が失敗したあなた自身の観察と、次のドキュメントの引用に基づいて、それはできないと結論付けます。

  1. ' getopt 'という明示的な名前のモジュールが既に存在します。

    注 このgetoptモジュールは、コマンド ライン オプション用のパーサーであり、その API は、Cgetopt()関数のユーザーが使い慣れるように設計されています。Cgetopt()関数に慣れていないユーザーや、より少ないコードを記述してより適切なヘルプとエラー メッセージを取得したいユーザーは、argparse代わりにモジュールの使用を検討する必要があります。

  2. getopt のデフォルトでさえ順列しません。より明示的に定義された次の名前のメソッドがありgnu_getopt()ます。

    この関数はgetopt()、GNU スタイルのスキャン モードがデフォルトで使用されることを除いて、 と同様に機能します。これは、オプションと非オプションの引数が混在している可能性があることを意味します。

  3. getopt のドキュメントでは、上記の argparse への参照は、以下を含めることでさらに誇張されています。

    argparse次のモジュールを使用すると、より少ないコードでより多くの情報を提供するヘルプとエラー メッセージを使用して、同等のコマンド ライン インターフェイスを生成できることに注意してください 。

繰り返しますが、決定的なものは何もありませんが、私にとっては、getopt と argparse の間には、argparse を支持/支持するドキュメントがあり、非常に鋭い分裂が見られます。

これは、テストgnu_getop()を満足させる whichを使用した例です。-z [file [file]]

>>> args = 'file1 -z file2'.split()
>>> args
['file1', '-z', 'file2']
>>> opts, args = getopt.gnu_getopt(args, 'z')
>>> opts
[('-z', '')]
>>> args
['file1', 'file2']

編集 1: argparse を使用して自分自身を並べ替える

リンク先の「Using Getopt」ページの「permute」の定義に触発されて、

デフォルトでは、スキャン中にargvの内容を並べ替えて、最終的にすべての非オプションが最後になるようにします。

引数文字列を に渡す前に並べ替えるのはどうparse_args()ですか?

import argparse

p = argparse.ArgumentParser();
p.add_argument('files',nargs='*',default=['-']);
p.add_argument('-z',action='store_true')

独自のローリング:

import re

def permute(s, opts_ptn='-[abc]'):
    """Returns a permuted form of arg string s using a regular expression."""
    opts = re.findall(opts_ptn, s)
    args = re.sub(opts_ptn, '', s)
    return '{} {}'.format(' '.join(opts), args).strip()

>>> p.parse_args(permute('bar -z foo', '-[z]').split())
Namespace(files=['bar', 'foo'], z=True)

getopt の活用:

import getopt

def permute(s, opts_ptn='abc'):
    """Returns a permuted form of arg string s using `gnu_getop()'."""
    opts, args = getopt.gnu_getopt(s.split(), opts_ptn)
    opts = ' '.join([''.join(x) for x in opts])
    args = ' '.join(args)
    return '{} {}'.format(opts, args).strip()

>>> p.parse_args(permute('bar -z foo', 'z').split())
Namespace(files=['bar', 'foo'], z=True)
于 2012-04-09T07:41:36.043 に答える