web-dev-qa-db-ja.com

getopt / optparseを使用して1つのオプションの複数の値を処理しますか?

以下の例に示すように、getoptまたはoptparseを使用して1つのオプションの複数の値をフェッチすることは可能ですか?

./hello_world -c arg1 arg2 arg3 -b arg4 arg5 arg6 arg7

各オプション(-c、-b)の実際の値の数は1または100のいずれかになる可能性があることに注意してください。使用したくない:./hello_world -c "arg1 arg2 arg3" -b "arg4 arg5 arg6 arg7"

これは可能ではないかもしれません(おそらくPOSIXに違反しています)。私が間違っている場合は修正してください。

行末にすべての非オプションがある例を見ました(./hello_world -c arg1 -b arg1 arg2 arg3)は収集できますが、複数のオプションの最初のものではありません。

アプリをPythonバージョンが異なるさまざまなプラットフォームで動作するようにしたいので、argparserは調べていません。

27
Open Grieves

はい、optparseで実行できます。

これは例です:

./test.py --categories=aaa --categories=bbb --categories ccc arg1 arg2 arg3

印刷する:

arguments: ['arg1', 'arg2', 'arg3']
options: {'categories': ['aaa', 'bbb', 'ccc']}

以下の完全に機能する例:

#!/usr/bin/env python

import os, sys
from optparse import OptionParser
from optparse import Option, OptionValueError

VERSION = '0.9.4'

class MultipleOption(Option):
    ACTIONS = Option.ACTIONS + ("extend",)
    STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
    TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
    ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)

    def take_action(self, action, dest, opt, value, values, parser):
        if action == "extend":
            values.ensure_value(dest, []).append(value)
        else:
            Option.take_action(self, action, dest, opt, value, values, parser)


def main():
    PROG = os.path.basename(os.path.splitext(__file__)[0])
    long_commands = ('categories')
    short_commands = {'cat':'categories'}
    description = """Just a test"""
    parser = OptionParser(option_class=MultipleOption,
                          usage='usage: %prog [OPTIONS] COMMAND [BLOG_FILE]',
                          version='%s %s' % (PROG, VERSION),
                          description=description)
    parser.add_option('-c', '--categories', 
                      action="extend", type="string",
                      dest='categories', 
                      metavar='CATEGORIES', 
                      help='comma separated list of post categories')

    if len(sys.argv) == 1:
        parser.parse_args(['--help'])

    OPTIONS, args = parser.parse_args()
    print "arguments:", args
    print "options:", OPTIONS

if __name__ == '__main__':
    main()

詳細については http://docs.python.org/library/optparse.html#adding-new-actions をご覧ください。

14
Richard Gomes

他のコメントの主張にもかかわらず、これは、少なくともpython 2.7の時点で、Vanilla optparseで可能です。必要なのはaction = "append"だけです。 docs

parser.add_option("-t", "--tracks", action="append", type="int")

コマンドラインで-t3が表示された場合、optparseは以下と同等のことを行います。

options.tracks = []
options.tracks.append(int("3"))

少し後で--tracks = 4が表示される場合は、次のようになります。

options.tracks.append(int("4"))
9
user3597804

パーティーに遅れて申し訳ありませんが、argsフラグを使用してoptparseでこれを解決しました。

parser.add_option('-c','--categories', dest='Categories', nargs=4 )

http://docs.python.org/2/library/optparse.html#optparse.Option.nargs

Argparse(unutbuが推奨)が標準のpython=ディストリビューションに含まれるようになりましたが、optparseは非推奨になりました。

8

これを行うには、Python2.7に付属するnargsargparseパラメータを使用し、ダウンロード可能 here を使用します。

argparseにはないoptparseに追加された改善点の1つだと思います。したがって、残念ながら、optparseまたはgetopt(さらに古い)を使用してこれを処理する素晴らしい方法はないと思います。

すばやく簡単な解決策は、optparse/getop/argparseを省略して、自分でsys.argvを解析することです。

または、反対の方向に進むと、argparse(〜88K)の凍結コピー(argparse_staticのような名前に変更)をプログラムでパッケージ化し、次のようにインポートすることを検討できます。

try:
    import argparse
except ImportError:
    import argparse_static as argparse

このように、プログラムは、インストールされている場合はargparseを使用し、インストールされていない場合はargparse_staticを使用します。何よりも、argparseが標準になるため、多くのコードを書き直す必要がありません。

5
unutbu

Getoptもoptparseも、そのままではこれをサポートしていません。さらに、デフォルト(GNU)モードでは、追加の引数は散在した引数として扱われます。つまり、処理の最後に残りの引数として使用できるようになります。

慣習では、同じ議論について繰り返し言及する必要があります。

./hello_world -c arg1 -c arg2 -c arg3 -b arg4 -b arg5 -b arg6 -b arg7

これはサポートされます。

絶対に指定した方法で機能させたい場合(つまり、-bと-cの両方が次の-引数または引数リストの最後まで拡張する)、optparseに基づいて何かをハックできます。 OptionParserから継承し、_process_short_optsをオーバーライドします。それがオプションの1つである場合は、サブクラスで処理します。それ以外の場合は、基本クラスに転送します。

5

別のオプションは、mountコマンドのオプションのように、セパレータを定義してローカルで処理することです。

たとえば、,をセパレーターとして使用できます。

...
args, _ = getopt.getopt(sys.argv[1:],'b:')
for flag, arg in args:
  if flag=='-b': all_arguments = arg.split(',')
...

$ ./test -b opt1,opt2,opt3

スペースも同じ!しかし、ユーザーはそれを適切に引用する必要があります。

$ ./test -b 'opt1 opt2 opt3'
4
estani

より簡単なもの:

make_option(
    "-c",
    "--city",
    dest="cities",
    action="append",
    default=[],
    help="specify cities",
)

追加アクション は、この問題の最も簡単な解決策です。

3
Diego Navarro