argparse est un package utile pour créer des scripts de ligne de commande avec des arguments optionnels en python. C'est un package pratique, mais j'ai fait des dizaines de fois pour faire des arguments fermement avec des fonctions et les réécrire avec argparse, et j'étais motivé par l'idée que ce travail était inutile. Alors automatisons-le.
On m'a dit dans le commentaire que je faisais la même chose que click, et je pensais avoir réinventé à nouveau la roue pendant un moment, mais quand j'ai essayé d'utiliser click, il semble que c'est différent, alors je vais l'ajouter .. La fonction de click est que la définition des options et des arguments écrits par argparse peut être distribuée à chaque fonction en tant que décorateur, et les arguments de la fonction ne sont pas automatiquement enregistrés comme options. Après tout, au lieu de add_argument, écrivez simplement @ click.option et le contenu que vous écrivez ne change pas beaucoup. Cela ne veut pas dire que le clic est mauvais, c'est un but différent. Click est un excellent package en termes d'organisation et d'écriture et d'amélioration de la lisibilité. Cependant, cette fois, je l'ai écrit à peu près dans le but "d'enregistrer automatiquement tous les arguments de la fonction créée en tant qu'arguments de ligne de commande!", Donc la considération suivante peut encore être utile pour un script simple mais variable. inconnue··. Au contraire, j'ai essayé d'utiliser Click et j'ai trouvé de nombreuses fonctions qui pourraient être utiles dans d'autres scènes, donc je résumerai le contenu séparément la prochaine fois.
Un package appelé inspect est utilisé pour l'analyse des arguments de fonction. Puisque j'utilise python2.7, j'utilise l'ancien getargspec, mais pour python3, utilisez getfullargspec.
from inspect import getargspec
def func(aaa=1, bbb="a", ccc=[1,2,3,]):
pass
args, varargs, keywords, defaults = getargspec(func)
print 'args: ', args
print 'varargs', varargs
print 'keywords: ', keywords
print 'defaults: ', defaults
Lorsque j'exécute ce qui précède, j'obtiens la sortie suivante:
args: ['aaa', 'bbb', 'ccc']
varargs None
keywords: None
defaults: (1, 'a', [1, 2, 3])
Utilisez ces informations pour enregistrer automatiquement les options argparse.
from inspect import getargspec
def func(aaa=1, bbb="a", ccc=[1,2,3,]):
pass
args, varargs, keywords, defaults = getargspec(func)
import argparse
parser = argparse.ArgumentParser()
for arg, default in zip(args, defaults):
parser.add_argument(
'--' + arg,
default=default,
type=type(default)
)
print parser.parse_args()
Faire ce qui précède vous donnera l'objet d'espace de noms suivant:
Namespace(aaa=1, bbb='a', ccc=[1, 2, 3])
En fait, dans le cas ci-dessus, la correspondance avec des arguments de longueur variable n'est pas suffisante. Vous trouverez ci-dessous le code qui ajoute la prise en charge des arguments de longueur variable, bien que ce soit un peu plus long.
from inspect import getargspec
def func(aaa=1, bbb="a", ccc=[1,2,3,]):
pass
args, varargs, keywords, defaults = getargspec(func)
import argparse
parser = argparse.ArgumentParser()
for arg, default in zip(args, defaults):
if type(default) is tuple or type(default) is list:
parser.add_argument(
'--' + arg,
default=default,
type=type(default),
nargs='+'
)
else:
parser.add_argument(
'--' + arg,
default=default,
type=type(default)
)
Plus précisément, si l'argument est une liste ou un tapple, ajoutez l'argument nargs à add_argument.
Dans le cas d'un argument de valeur booléenne, la valeur est déterminée de manière unique lorsqu'elle n'est pas la valeur par défaut, il est donc courant de spécifier l'acronyme disable, enable au lieu de spécifier True, False pour en faire une option qui ne prend pas de valeur. .. En incluant cette correspondance, cela devient comme suit.
from inspect import getargspec
def func(aaa=1, bbb="a", ccc=[1,2,3,], ddd=True, eee=False):
pass
args, varargs, keywords, defaults = getargspec(func)
import argparse
parser = argparse.ArgumentParser()
for arg, default in zip(args, defaults):
if type(default) is tuple or type(default) is list:
parser.add_argument(
'--' + arg,
default=default,
type=type(default),
nargs='+'
)
elif type(default) is bool and default:
parser.add_argument(
'--disable_' + arg,
dest=arg,
default=default,
action="store_false"
)
elif type(default) is bool and not default:
parser.add_argument(
'--enable_' + arg,
dest=arg,
default=default,
action="store_true"
)
else:
parser.add_argument(
'--' + arg,
default=default,
type=type(default)
)
Enfin, les arguments qui n'ont pas de valeurs par défaut sont également pris en charge. Cependant, gardez à l'esprit que cet argument est reconnu comme une chaîne car son type est inconnu.
from inspect import getargspec
def func(x, aaa=1, bbb="a", ccc=[1,2,3,], ddd=True, eee=False):
pass
args, varargs, keywords, defaults = getargspec(func)
print 'args: ', args
print 'varargs', varargs
print 'keywords: ', keywords
print 'defaults: ', defaults
parser = argparse.ArgumentParser()
while len(args) > len(defaults):
l = list(defaults)
l.insert(0, None)
defaults = tuple(l)
for arg, default in zip(args, defaults):
if default is None:
parser.add_argument(dest=arg)
elif type(default) is tuple or type(default) is list:
parser.add_argument(
'--' + arg,
default=default,
type=type(default),
nargs='+'
)
elif type(default) is bool and default:
parser.add_argument(
'--disable_' + arg,
dest=arg,
default=default,
action="store_false"
)
elif type(default) is bool and not default:
parser.add_argument(
'--enable_' + arg,
dest=arg,
default=default,
action="store_true"
)
else:
parser.add_argument(
'--' + arg,
default=default,
type=type(default)
)
print parser.parse_args()
En utilisant inspect et argparse, il était possible de définir automatiquement l'argument de la fonction sur l'argument d'argparse. La version finale du code est jointe ci-dessous.
extract_arguments.py
#!/usr/bin/env python
import argparse
from inspect import getargspec
def set_arguments(parser, func):
args, varargs, keywords, defaults = getargspec(func)
print 'args: ', args
print 'varargs', varargs
print 'keywords: ', keywords
print 'defaults: ', defaults
while len(args) > len(defaults):
l = list(defaults)
l.insert(0, None)
defaults = tuple(l)
for arg, default in zip(args, defaults):
if default is None:
parser.add_argument(dest=arg)
elif type(default) is tuple or type(default) is list:
parser.add_argument(
'--' + arg,
default=default,
type=type(default),
nargs='+'
)
elif type(default) is bool and default:
parser.add_argument(
'--disable_' + arg,
dest=arg,
default=default,
action="store_false"
)
elif type(default) is bool and not default:
parser.add_argument(
'--enable_' + arg,
dest=arg,
default=default,
action="store_true"
)
else:
parser.add_argument(
'--' + arg,
default=default,
type=type(default)
)
return parser
def func(x, aaa=1, bbb="a", ccc=[1,2,3,], ddd=True, eee=False):
pass
parser = argparse.ArgumentParser()
parser = set_arguments(parser, func)
print parser.parse_args()
Voici les décorateurs pour plus de commodité.
register_arguments.py
#!/usr/bin/env python
import argparse
from inspect import getargspec
def register_arguments(parser, func):
args, varargs, keywords, defaults = getargspec(func)
while len(args) > len(defaults):
l = list(defaults)
l.insert(0, None)
defaults = tuple(l)
for arg, default in zip(args, defaults):
if default is None:
parser.add_argument(dest=arg)
elif type(default) is tuple or type(default) is list:
parser.add_argument(
'--' + arg,
default=default,
type=type(default),
nargs='+'
)
elif type(default) is bool and default:
parser.add_argument(
'--disable_' + arg,
dest=arg,
default=default,
action="store_false"
)
elif type(default) is bool and not default:
parser.add_argument(
'--enable_' + arg,
dest=arg,
default=default,
action="store_true"
)
else:
parser.add_argument(
'--' + arg,
default=default,
type=type(default)
)
return parser
def register_argparse(parser):
def wrapper(f):
register_arguments(parser, f)
return f
return wrapper
if __name__ == '__main__':
parser = argparse.ArgumentParser()
@register_argparse(parser)
def func(x, aaa=1, bbb="a", ccc=[1,2,3,], ddd=True, eee=False):
pass
print parser.parse_args()
Lorsque ce qui précède est exécuté, la sortie suivante est sortie.
$ python ./register_argments.py a
Namespace(aaa=1, bbb='a', ccc=[1, 2, 3], ddd=True, eee=False, x='a')
Recommended Posts