15

いくつかの異なるコマンドをサポートする比較的単純な Python スクリプトを作成しています。さまざまなコマンドがさまざまなオプションをサポートしており、argparse によって解析されたオプションを、指定されたコマンドの正しいメソッドに渡すことができるようにしたいと考えています。

使用文字列は次のようになります。

usage: script.py [-h]

            {a, b, c}
            ...
script.py: error: too few arguments

適切なメソッドを簡単に呼び出すことができます。

def a():
    ...

def b():
    ...

def c():
    ...

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.set_defaults(method = a)
    ...

    arguments = parser.parse_args()
    arguments.method()

ただし、これらのメソッドに引数を渡す必要があり、それらはすべて異なる引数のセットを受け入れます。

現在、次のNamespaceように、argparse によって返されたオブジェクトを渡すだけです。

 def a(arguments):
     arg1 = getattr(arguments, 'arg1', None)
     ...

これは少しぎこちなく、dict通常のパラメーターとしてではなく、または名前空間として引数を渡す必要があるため、メソッドを再利用するのが少し難しくなります。

何らかの方法でパラメーターを使用してメソッドを定義し (通常の関数と同じように)、適切なパラメーターを渡しながら動的に呼び出すことができるようにしたいと考えています。そのようです:

def a(arg1, arg2):
    ...

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.set_defaults(method = a)
    ...

    arguments = parser.parse_args()
    arguments.method() # <<<< Arguments passed here somehow

何か案は?

4

3 に答える 3

7

私は非常に良い解決策を見つけました:

import argparse

def a(arg1, arg2, **kwargs):
    print arg1
    print arg2

if __name__ == "__main__":
        parser = argparse.ArgumentParser()
        parser.set_defaults(method = a)
        parser.add_argument('arg1', type = str)
        parser.add_argument('arg2', type = str)

        arguments = parser.parse_args()
        arguments.method(**vars(arguments))

もちろん、メソッドの引数が argparse が使用する引数の名前と衝突する場合は小さな問題がありますが、これは Namespace オブジェクトを渡して を使用するよりも好ましいと思いますgetattr

于 2011-09-14T08:50:15.193 に答える
2

サブコマンドが提供する機能を実現しようとしている可能性があります: http://docs.python.org/dev/library/argparse.html#sub-commands

于 2011-09-07T15:12:46.757 に答える
0

これがどれほど実用的かはわかりませんが、inspectを使用することで、次のように関数の不要な **kwargs パラメータを除外できます。

import argparse
import inspect


def sleep(seconds=0):
    print "sleeping", seconds, "seconds"

def foo(a, b=2, **kwargs):
    print "a=",a
    print "b=",b
    print "kwargs=",kwargs

parser = argparse.ArgumentParser()

subparsers = parser.add_subparsers(title="subcommand")

parser_sleep = subparsers.add_parser('sleep')
parser_sleep.add_argument("seconds", type=int, default=0)
parser_sleep.set_defaults(func=sleep)

parser_foo = subparsers.add_parser('foo')
parser_foo.add_argument("-a", type=int, default=101)
parser_foo.add_argument("-b", type=int, default=201)
parser_foo.add_argument("--wacky", default=argparse.SUPPRESS)
parser_foo.set_defaults(func=foo)

args = parser.parse_args()

arg_spec = inspect.getargspec(args.func)
if arg_spec.keywords:
    ## convert args to a dictionary
    args_for_func = vars(args)
else:
    ## get a subset of the dictionary containing just the arguments of func
    args_for_func = {k:getattr(args, k) for k in arg_spec.args}

args.func(**args_for_func)

例:

$ python test.py sleep 23
sleeping 23 seconds

$ python test.py foo -a 333 -b 444
a= 333
b= 444
kwargs= {'func': <function foo at 0x10993dd70>}

$ python test.py foo -a 333 -b 444 --wacky "this is wacky"
a= 333
b= 444
kwargs= {'func': <function foo at 0x10a321d70>, 'wacky': 'this is wacky'}

楽しむ!

于 2013-12-19T22:47:07.387 に答える