Python Language
Análisis de argumentos de línea de comandos
Buscar..
Introducción
La mayoría de las herramientas de línea de comandos se basan en argumentos pasados al programa en su ejecución. En lugar de solicitar una entrada, estos programas esperan que se establezcan datos o indicadores específicos (que se convierten en valores booleanos). Esto permite que tanto el usuario como otros programas ejecuten el archivo Python pasándole los datos a medida que se inician. Esta sección explica y demuestra la implementación y el uso de los argumentos de la línea de comandos en Python.
Hola mundo en argparse
El siguiente programa dice hola al usuario. Toma un argumento posicional, el nombre del usuario, y también se le puede decir el saludo.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('name',
help='name of user'
)
parser.add_argument('-g', '--greeting',
default='Hello',
help='optional alternate greeting'
)
args = parser.parse_args()
print("{greeting}, {name}!".format(
greeting=args.greeting,
name=args.name)
)
$ python hello.py --help
usage: hello.py [-h] [-g GREETING] name
positional arguments:
name name of user
optional arguments:
-h, --help show this help message and exit
-g GREETING, --greeting GREETING
optional alternate greeting
$ python hello.py world
Hello, world!
$ python hello.py John -g Howdy
Howdy, John!
Para más detalles por favor lea la documentación argparse .
Ejemplo básico con docopt.
docopt convierte el argumento de la línea de comando analizando en su cabeza. En lugar de analizar los argumentos, simplemente escriba la cadena de uso para su programa, y docopt analiza la cadena de uso y la utiliza para extraer los argumentos de la línea de comandos.
"""
Usage:
script_name.py [-a] [-b] <path>
Options:
-a Print all the things.
-b Get more bees into the path.
"""
from docopt import docopt
if __name__ == "__main__":
args = docopt(__doc__)
import pprint; pprint.pprint(args)
Ejecuciones de muestra:
$ python script_name.py
Usage:
script_name.py [-a] [-b] <path>
$ python script_name.py something
{'-a': False,
'-b': False,
'<path>': 'something'}
$ python script_name.py something -a
{'-a': True,
'-b': False,
'<path>': 'something'}
$ python script_name.py -b something -a
{'-a': True,
'-b': True,
'<path>': 'something'}
Estableciendo argumentos mutuamente excluyentes con argparse
Si quieres que dos o más argumentos sean mutuamente excluyentes. Puede utilizar la función argparse.ArgumentParser.add_mutually_exclusive_group()
. En el siguiente ejemplo, pueden existir foo o bar, pero no ambos al mismo tiempo.
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-f", "--foo")
group.add_argument("-b", "--bar")
args = parser.parse_args()
print "foo = ", args.foo
print "bar = ", args.bar
Si intenta ejecutar el script especificando los argumentos --foo
y --bar
, el script se quejará con el mensaje a continuación.
error: argument -b/--bar: not allowed with argument -f/--foo
Usando argumentos de línea de comando con argv
Cada vez que se invoca un script de Python desde la línea de comandos, el usuario puede proporcionar argumentos de línea de comandos adicionales que se pasarán al script. Estos argumentos estarán disponibles para el programador de la variable del sistema sys.argv
( "argv" es un nombre tradicional utilizado en la mayoría de los lenguajes de programación, y significa "arg ument v ector").
Por convención, el primer elemento de la lista sys.argv
es el nombre de la secuencia de comandos de Python, mientras que el resto de los elementos son los tokens que el usuario pasa al invocar la secuencia de comandos.
# cli.py
import sys
print(sys.argv)
$ python cli.py
=> ['cli.py']
$ python cli.py fizz
=> ['cli.py', 'fizz']
$ python cli.py fizz buzz
=> ['cli.py', 'fizz', 'buzz']
Aquí hay otro ejemplo de cómo usar argv
. Primero eliminamos el elemento inicial de sys.argv porque contiene el nombre del script. Luego combinamos el resto de los argumentos en una sola oración, y finalmente imprimimos esa oración antes del nombre del usuario que ha iniciado sesión (para que emule un programa de chat).
import getpass
import sys
words = sys.argv[1:]
sentence = " ".join(words)
print("[%s] %s" % (getpass.getuser(), sentence))
El algoritmo comúnmente utilizado cuando se analiza "manualmente" un número de argumentos no posicionales es iterar sobre la lista sys.argv
. Una forma es repasar la lista y resaltar cada elemento de la misma:
# reverse and copy sys.argv
argv = reversed(sys.argv)
# extract the first element
arg = argv.pop()
# stop iterating when there's no more args to pop()
while len(argv) > 0:
if arg in ('-f', '--foo'):
print('seen foo!')
elif arg in ('-b', '--bar'):
print('seen bar!')
elif arg in ('-a', '--with-arg'):
arg = arg.pop()
print('seen value: {}'.format(arg))
# get the next value
arg = argv.pop()
Mensaje de error del analizador personalizado con argparse
Puede crear mensajes de error del analizador de acuerdo con las necesidades de su script. Esto es a través de la función argparse.ArgumentParser.error
. El siguiente ejemplo muestra la secuencia de comandos imprimiendo un uso y un mensaje de error a stderr
cuando se --foo
pero no --bar
.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--foo")
parser.add_argument("-b", "--bar")
args = parser.parse_args()
if args.foo and args.bar is None:
parser.error("--foo requires --bar. You did not specify bar.")
print "foo =", args.foo
print "bar =", args.bar
Asumiendo que el nombre de su script es sample.py, y ejecutamos: python sample.py --foo ds_in_fridge
El guión se quejará con lo siguiente:
usage: sample.py [-h] [-f FOO] [-b BAR]
sample.py: error: --foo requires --bar. You did not specify bar.
Agrupación conceptual de argumentos con argparse.add_argument_group ()
Cuando crea un argparse ArgumentParser () y ejecuta su programa con '-h', recibe un mensaje de uso automático que explica con qué argumentos puede ejecutar su software. De forma predeterminada, los argumentos posicionales y los argumentos condicionales están separados en dos categorías, por ejemplo, aquí hay un pequeño script (example.py) y el resultado cuando ejecuta python example.py -h
.
import argparse
parser = argparse.ArgumentParser(description='Simple example')
parser.add_argument('name', help='Who to greet', default='World')
parser.add_argument('--bar_this')
parser.add_argument('--bar_that')
parser.add_argument('--foo_this')
parser.add_argument('--foo_that')
args = parser.parse_args()
usage: example.py [-h] [--bar_this BAR_THIS] [--bar_that BAR_THAT]
[--foo_this FOO_THIS] [--foo_that FOO_THAT]
name
Simple example
positional arguments:
name Who to greet
optional arguments:
-h, --help show this help message and exit
--bar_this BAR_THIS
--bar_that BAR_THAT
--foo_this FOO_THIS
--foo_that FOO_THAT
Hay algunas situaciones en las que desea separar sus argumentos en secciones conceptuales adicionales para ayudar a su usuario. Por ejemplo, es posible que desee tener todas las opciones de entrada en un grupo y todas las opciones de formato de salida en otro. El ejemplo anterior se puede ajustar para separar los --foo_*
de los --bar_*
así.
import argparse
parser = argparse.ArgumentParser(description='Simple example')
parser.add_argument('name', help='Who to greet', default='World')
# Create two argument groups
foo_group = parser.add_argument_group(title='Foo options')
bar_group = parser.add_argument_group(title='Bar options')
# Add arguments to those groups
foo_group.add_argument('--bar_this')
foo_group.add_argument('--bar_that')
bar_group.add_argument('--foo_this')
bar_group.add_argument('--foo_that')
args = parser.parse_args()
Que produce esta salida cuando se ejecuta python example.py -h
:
usage: example.py [-h] [--bar_this BAR_THIS] [--bar_that BAR_THAT]
[--foo_this FOO_THIS] [--foo_that FOO_THAT]
name
Simple example
positional arguments:
name Who to greet
optional arguments:
-h, --help show this help message and exit
Foo options:
--bar_this BAR_THIS
--bar_that BAR_THAT
Bar options:
--foo_this FOO_THIS
--foo_that FOO_THAT
Ejemplo avanzado con docopt y docopt_dispatch
Al igual que con docopt, con [docopt_dispatch] creas tu --help
en la variable __doc__
de tu módulo de punto de entrada. Allí, se llama dispatch
con la cadena doc como argumento, para que pueda ejecutar el analizador sobre él.
Una vez hecho esto, en lugar de manejar manualmente los argumentos (que por lo general terminan en una estructura ciclomática alta de / else), lo dejas para enviar, dando solo la forma en que quieres manejar el conjunto de argumentos.
Esto es para lo que es el decorador dispatch.on
: le da el argumento o la secuencia de argumentos que deberían desencadenar la función, y esa función se ejecutará con los valores coincidentes como parámetros.
"""Run something in development or production mode.
Usage: run.py --development <host> <port>
run.py --production <host> <port>
run.py items add <item>
run.py items delete <item>
"""
from docopt_dispatch import dispatch
@dispatch.on('--development')
def development(host, port, **kwargs):
print('in *development* mode')
@dispatch.on('--production')
def development(host, port, **kwargs):
print('in *production* mode')
@dispatch.on('items', 'add')
def items_add(item, **kwargs):
print('adding item...')
@dispatch.on('items', 'delete')
def items_delete(item, **kwargs):
print('deleting item...')
if __name__ == '__main__':
dispatch(__doc__)