web-dev-qa-db-ja.com

argparseに基づいて関数を呼び出す

私はpythonを初めて使用します。現在、アプライアンスでAPI呼び出しを行うスクリプトがあります。機能を拡張し、指定された引数に基づいてさまざまな関数を呼び出したいと思います。スクリプトを呼び出すとき。

現在、私は以下を持っています:

parser = argparse.ArgumentParser()
parser.add_argument("--showtop20", help="list top 20 by app",
                    action="store_true")
parser.add_argument("--listapps", help="list all available apps",
                    action="store_true")
args = parser.parse_args()

私もいる

def showtop20():
    .....

そして

def listapps():
....

与えられた引数に基づいてどのように関数を呼び出すことができますか?走りたくない

if args.showtop20:
   #code here

if args.listapps:
   #code here

メインの実行可能ファイルをきれいに整頓した後、さまざまな機能をモジュールに移動したいので。

26
f0rd42

与えられた引数に応じて1つだけの関数を実行したいように見えるので、オプションの引数(./prog commandまたは./prog --command1)ではなく、必須の位置引数./prog --command2を使用することをお勧めします。

だから、このような何かがそれを行う必要があります:

FUNCTION_MAP = {'top20' : my_top20_func,
                'listapps' : my_listapps_func }

parser.add_argument('command', choices=FUNCTION_MAP.keys())

args = parser.parse_args()

func = FUNCTION_MAP[args.command]
func()
24
Hannes Ovrén

この猫をスキニングする方法はたくさんあります。ここに_action='store_const'_を使用したものがあります(文書化されたサブパーサーの例から着想を得ています):

_p=argparse.ArgumentParser()
p.add_argument('--cmd1', action='store_const', const=lambda:'cmd1', dest='cmd')
p.add_argument('--cmd2', action='store_const', const=lambda:'cmd2', dest='cmd')

args = p.parse_args(['--cmd1'])
# Out[21]: Namespace(cmd=<function <lambda> at 0x9abf994>)

p.parse_args(['--cmd2']).cmd()
# Out[19]: 'cmd2'
p.parse_args(['--cmd1']).cmd()
# Out[20]: 'cmd1'
_

共有destを使用すると、各アクションはその関数(const)を同じネームスペース属性に入れます。関数はargs.cmd()によって呼び出されます。

また、文書化されたサブパーサーの例のように、これらの関数は、ネームスペースの他の値を使用するように記述できます。

_args = parse_args()
args.cmd(args)
_

比較のために、同等のサブパーサーの場合を次に示します。

_p = argparse.ArgumentParser()
sp = p.add_subparsers(dest='cmdstr')
sp1 = sp.add_parser('cmd1')
sp1.set_defaults(cmd=lambda:'cmd1')
sp2 = sp.add_parser('cmd2')
sp2.set_defaults(cmd=lambda:'cmd2')

p.parse_args(['cmd1']).cmd()
# Out[25]: 'cmd1'
_

ドキュメントに示されているように、サブパーサーを使用すると、コマンドごとに異なるパラメーター引数を定義できます。

そしてもちろん、これらのadd引数またはパーサーステートメントはすべて、キーを関数とペアにするリストまたは辞書のループで作成できます。

別の重要な考慮事項-どのような使用法とヘルプが必要ですか?さまざまなアプローチにより、非常に異なるヘルプメッセージが生成されます。

12
hpaulj

関数が「十分に単純」な場合は、typeパラメーターのアドバンテージを取ります https://docs.python.org/2.7/library/argparse.html#type

type =は、単一の文字列引数を取り、変換された値を返す任意の呼び出し可能オブジェクトを取ることができます。

あなたの例では(変換された値が必要ない場合でも):

parser.add_argument("--listapps", help="list all available apps",
                    type=showtop20,
                    action="store")

この簡単なスクリプト:

import argparse

def showtop20(dummy):
    print "{0}\n".format(dummy) * 5

parser = argparse.ArgumentParser()
parser.add_argument("--listapps", help="list all available apps",
                    type=showtop20,
                    action="store")
args = parser.parse_args()

あげる:

# ./test.py --listapps test
test
test
test
test
test
test
6

少なくともあなたが説明したことから、--showtop20および--listappsはオプションよりもサブコマンドのように聞こえます。この場合、サブパーサーを使用して目的の結果を得ることができます。概念実証は次のとおりです。

import argparse
import sys

def showtop20():
    print('running showtop20')

def listapps():
    print('running listapps')

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

# Create a showtop20 subcommand    
parser_showtop20 = subparsers.add_parser('showtop20', help='list top 20 by app')
parser_showtop20.set_defaults(func=showtop20)

# Create a listapps subcommand       
parser_listapps = subparsers.add_parser('listapps', help='list all available apps')
parser_listapps.set_defaults(func=listapps)

# Print usage message if no args are supplied.

# NOTE: Python 2 will error 'too few arguments' if no subcommand is supplied.
#       No such error occurs in Python 3, which makes it feasible to check
#       whether a subcommand was provided (displaying a help message if not).
#       argparse internals vary significantly over the major versions, so it's
#       much easier to just override the args passed to it.

if len(sys.argv) <= 1:
    sys.argv.append('--help')

options = parser.parse_args()

# Run the appropriate function (in this case showtop20 or listapps)
options.func()

# If you add command-line options, consider passing them to the function,
# e.g. `options.func(options)`
6
Six