Je suis nouveau à python et je joue actuellement avec lui. J'ai un script qui fait des appels d'API à un appareil. Je voudrais étendre les fonctionnalités et appeler différentes fonctions en fonction des arguments donnés lors de l'appel du script.
Actuellement, j'ai les éléments suivants:
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()
J'ai aussi un
def showtop20():
.....
et
def listapps():
....
Comment puis-je appeler la fonction (et seulement cela) en fonction de l'argument donné? Je ne veux pas courir
if args.showtop20:
#code here
if args.listapps:
#code here
car je veux déplacer les différentes fonctions vers un module plus tard en gardant le fichier exécutable principal propre et bien rangé.
Comme il semble que vous souhaitiez exécuter une et une seule fonction en fonction des arguments fournis, je vous suggère d'utiliser un argument positionnel obligatoire ./prog command
, au lieu d'arguments facultatifs (./prog --command1
ou ./prog --command2
).
donc, quelque chose comme ça devrait le faire:
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()
Il existe de nombreuses façons d'écorcher ce chat. En voici un qui utilise action='store_const'
(Inspiré de l'exemple de sous-analyseur documenté):
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'
Avec un dest
partagé, chaque action place sa fonction (const
) dans le même attribut Namespace. La fonction est invoquée par args.cmd()
.
Et comme dans l'exemple des sous-analyseurs documentés, ces fonctions pourraient être écrites de manière à utiliser d'autres valeurs de Namespace.
args = parse_args()
args.cmd(args)
À des fins de comparaison, voici le cas des sous-analyseurs équivalents:
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'
Comme illustré dans la documentation, les sous-analyseurs vous permettent de définir différents arguments de paramètres pour chacune des commandes.
Et bien sûr, tous ces arguments add
ou instructions d'analyseur peuvent être créés en boucle sur une liste ou un dictionnaire qui associe une clé à une fonction.
Une autre considération importante - quel type d'utilisation et d'aide voulez-vous? Les différentes approches génèrent des messages d'aide très différents.
Si vos fonctions sont "assez simples", essayez le paramètre type
https://docs.python.org/2.7/library/argparse.html#type
type = peut prendre tout appelable qui prend un seul argument de chaîne et renvoie la valeur convertie:
Dans votre exemple (même si vous n'avez pas besoin d'une valeur convertie):
parser.add_argument("--listapps", help="list all available apps",
type=showtop20,
action="store")
Ce script simple:
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()
Va donner:
# ./test.py --listapps test
test
test
test
test
test
test
Au moins d'après ce que vous avez décrit, --showtop20
et --listapps
ressemble plus à des sous-commandes qu'à des options. En supposant que c'est le cas, nous pouvons utiliser des sous-analyseurs pour obtenir le résultat souhaité. Voici une preuve de concept:
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)`