Функция вызова на основе argparse
Я новичок в python и сейчас играю с ним.
У меня есть script, который выполняет некоторые вызовы API для устройства. Я хотел бы расширить функциональность и вызвать разные функции на основе аргументов, которые вызывают при вызове script.
В настоящее время у меня есть следующее:
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
поскольку я хочу переместить различные функции в модуль позже, чтобы сохранить основной исполняемый файл в чистоте и порядке.
Ответы
Ответ 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()
Ответ 2
Есть много способов скинирования этой кошки. Здесь используется 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
могут быть созданы в цикле над некоторым списком или словарем, который соединяет ключ с функцией.
Еще одно важное соображение - какое использование и помощь вы хотите? Различные подходы генерируют очень разные справочные сообщения.
Ответ 3
Если ваши функции "достаточно просты", возьмите adventage параметра 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")
Этот простой script:
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
Ответ 4
По крайней мере, из того, что вы описали, --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)`