¿Cuál es la mejor manera de analizar los argumentos de línea de comandos?
-
09-06-2019 - |
Pregunta
¿Cuál es la más fácil, tersest, y la mayoría de los flexible método o biblioteca para analizar Python argumentos de línea de comandos?
Solución
Esta respuesta sugiere optparse
cual es apropiado para la edad versiones de Python.Para Python 2.7 o superior, argparse
reemplaza optparse
.Ver esta respuesta para obtener más información.
Como otras personas, señaló, es mejor ir con optparse más de getopt.getopt es casi un uno-a-uno el mapeo de la norma de getopt(3) funciones de la biblioteca C, y no muy fácil de usar.
optparse, mientras que ser un poco más detallado, es mucho mejor estructurado y más simple para ampliar más adelante.
He aquí una típica línea para añadir una opción para su analizador:
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
Casi habla por sí mismo;en el tiempo de procesamiento, va a accept-p o --consulta como opciones, almacenar el argumento en un atributo llamado de consulta y tiene un valor predeterminado si no se especifica.También es auto-documentado en el que se declara el argumento de la ayuda (que será utilizado cuando se ejecuta con -h/--help) con la opción.
Por lo general, usted analizar sus argumentos con:
options, args = parser.parse_args()
Este será, por defecto, analizar el estándar de argumentos pasados al script (sys.argv[1:])
opciones.consulta a continuación, se establece en el valor que se pasa a la secuencia de comandos.
Crear un analizador simplemente haciendo
parser = optparse.OptionParser()
Todos estos son los elementos básicos que necesita.He aquí una completa secuencia de comandos de Python que muestra esto:
import optparse
parser = optparse.OptionParser()
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
options, args = parser.parse_args()
print 'Query string:', options.query
5 líneas de python que muestran los conceptos básicos.
Guardar en sample.py y ejecute una vez con
python sample.py
y una vez con
python sample.py --query myquery
Más allá de eso, usted encontrará que optparse es muy fácil de extender.En uno de mis proyectos, he creado una clase de Comandos que le permite nido subcomandos en un árbol de comandos fácilmente.Utiliza optparse fuertemente a la cadena de comandos juntos.No es algo que fácilmente se puede explicar en unas pocas líneas, pero siéntase libre de navegar en mi repositorio para la clase principal, así como una clase que usa y la opción analizador de
Otros consejos
Otras respuestas no mencionan que argparse
es el camino a seguir para los nuevos Python, pero no se dé ejemplos de uso.La integridad, aquí está un breve resumen de cómo utilizar argparse:
1) Inicializar
import argparse
# Instantiate the parser
parser = argparse.ArgumentParser(description='Optional app description')
2) Agregar Argumentos
# Required positional argument
parser.add_argument('pos_arg', type=int,
help='A required integer positional argument')
# Optional positional argument
parser.add_argument('opt_pos_arg', type=int, nargs='?',
help='An optional integer positional argument')
# Optional argument
parser.add_argument('--opt_arg', type=int,
help='An optional integer argument')
# Switch
parser.add_argument('--switch', action='store_true',
help='A boolean switch')
3) Analizar
args = parser.parse_args()
4) el Acceso
print("Argument values:")
print(args.pos_arg)
print(args.opt_pos_arg)
print(args.opt_arg)
print(args.switch)
5) Compruebe Que Los Valores De
if args.pos_arg > 10:
parser.error("pos_arg cannot be larger than 10")
El uso de
Uso correcto:
$ ./app 1 2 --opt_arg 3 --switch
Argument values:
1
2
3
True
Argumentos incorrectos:
$ ./app foo 2 --opt_arg 3 --switch
usage: convert [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
app: error: argument pos_arg: invalid int value: 'foo'
$ ./app 11 2 --opt_arg 3
Argument values:
11
2
3
False
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
convert: error: pos_arg cannot be larger than 10
Ayuda completa:
$ ./app -h
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
Optional app description
positional arguments:
pos_arg A required integer positional argument
opt_pos_arg An optional integer positional argument
optional arguments:
-h, --help show this help message and exit
--opt_arg OPT_ARG An optional integer argument
--switch A boolean switch
El uso de docopt
Desde 2012 Python tiene una muy fácil, potente y realmente cool módulo para el argumento de análisis llamado docopt.Funciona con Python 2.6 a 3.5 y no necesita instalación (sólo copia).He aquí un ejemplo tomado de la documentación:
"""Naval Fate.
Usage:
naval_fate.py ship new <name>...
naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
naval_fate.py ship shoot <x> <y>
naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
naval_fate.py (-h | --help)
naval_fate.py --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.
"""
from docopt import docopt
if __name__ == '__main__':
arguments = docopt(__doc__, version='Naval Fate 2.0')
print(arguments)
Así es este:2 líneas de código, además de su doc cadena que es esenciales y obtener sus argumentos analizados y están disponibles en su objeto de argumentos.He dicho que es genial, no yo ;-)
Usando python-fuego
Desde 2017 python-fuego tiene otro fresco módulo que puede dar a una interfaz CLI de su código con usted haciendo cero argumento de análisis.He aquí un ejemplo simple de la documentación (este pequeño programa que se expone la función double
a la línea de comandos):
import fire
class Calculator(object):
def double(self, number):
return 2 * number
if __name__ == '__main__':
fire.Fire(Calculator)
Desde la línea de comandos, puede ejecutar:
> calculator.py double 10
20
> calculator.py double --number=15
30
Impresionante ¿verdad?
Yo prefiero Haga clic en.Abstrae la gestión de opciones y permite "(...) la creación de hermosos interfaces de línea de comandos en una forma en que se puede componer con tan poco código según sea necesario".
He aquí un ejemplo de uso:
import click
@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
help='The person to greet.')
def hello(count, name):
"""Simple program that greets NAME for a total of COUNT times."""
for x in range(count):
click.echo('Hello %s!' % name)
if __name__ == '__main__':
hello()
También se genera automáticamente con un formato agradable páginas de ayuda:
$ python hello.py --help
Usage: hello.py [OPTIONS]
Simple program that greets NAME for a total of COUNT times.
Options:
--count INTEGER Number of greetings.
--name TEXT The person to greet.
--help Show this message and exit.
Casi todo el mundo está utilizando getopt
Aquí está el código de ejemplo para el doc :
import getopt, sys
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
output = None
verbose = False
for o, a in opts:
if o == "-v":
verbose = True
if o in ("-h", "--help"):
usage()
sys.exit()
if o in ("-o", "--output"):
output = a
Así, en una palabra, aquí es cómo funciona.
Tienes dos tipos de opciones.Aquellos que están recibiendo los argumentos, y los que son como interruptores.
sys.argv
es bastante parecido a su char** argv
en C.Como en C se salta el primer elemento que es el nombre de su programa y analizar sólo los argumentos : sys.argv[1:]
Getopt.getopt
analizará de acuerdo a la regla que dar en el argumento.
"ho:v"
aquí se describe el corto argumentos : -ONELETTER
.El :
significa que -o
acepta un argumento.
Finalmente ["help", "output="]
describe largo ( argumentos --MORETHANONELETTER
).El =
después de la salida una vez más, significa que la salida acepta uno de los argumentos.
El resultado es una lista de pareja (opción,argumento)
Si una opción no acepta ningún argumento (como --help
aquí) el arg
parte es una cadena vacía.Usted, por lo general, quieren bucle en esta lista y prueba el nombre de la opción como en el ejemplo.
Espero que esto te ayudó.
Uso optparse
el que viene con la biblioteca estándar.Por ejemplo:
#!/usr/bin/env python
import optparse
def main():
p = optparse.OptionParser()
p.add_option('--person', '-p', default="world")
options, arguments = p.parse_args()
print 'Hello %s' % options.person
if __name__ == '__main__':
main()
Fuente: El uso de Python para crear herramientas de línea de comandos de UNIX
Sin embargo, como el de Python 2.7 optparse está obsoleta, véase: ¿Por qué utilizar argparse en lugar de optparse?
Sólo en caso de que usted podría necesitar, esto puede ayudar si usted necesita para agarrar argumentos unicode en Win32 (2K, XP, etc):
from ctypes import *
def wmain(argc, argv):
print argc
for i in argv:
print i
return 0
def startup():
size = c_int()
ptr = windll.shell32.CommandLineToArgvW(windll.kernel32.GetCommandLineW(), byref(size))
ref = c_wchar_p * size.value
raw = ref.from_address(ptr)
args = [arg for arg in raw]
windll.kernel32.LocalFree(ptr)
exit(wmain(len(args), args))
startup()
Ligero argumento de línea de comandos predeterminados
Aunque argparse
es muy grande y es la respuesta correcta para totalmente documentado modificadores de línea de comandos y funciones avanzadas, puede utilizar el argumento de la función por defecto maneja sencillo argumentos posicionales muy simplemente.
import sys
def get_args(name='default', first='a', second=2):
return first, int(second)
first, second = get_args(*sys.argv)
print first, second
El 'nombre' argumento captura el nombre del script y no se utiliza.Prueba de salida se parece a esto:
> ./test.py
a 2
> ./test.py A
A 2
> ./test.py A 20
A 20
Para secuencias de comandos simples donde solo quiero algunos valores por defecto, esto me parece más que suficiente.También puede ser que desee incluir algún tipo de coacción en los valores de retorno de línea de comandos o valores serán todas las cadenas.
Creo que la mejor manera para proyectos más grandes es optparse, pero si usted está buscando una manera fácil, tal vez http://werkzeug.pocoo.org/documentation/script es algo para usted.
from werkzeug import script
# actions go here
def action_foo(name=""):
"""action foo does foo"""
pass
def action_bar(id=0, title="default title"):
"""action bar does bar"""
pass
if __name__ == '__main__':
script.run()
Así que, básicamente, cada una de las funciones action_* está expuesto a la línea de comandos y un buen mensaje de ayuda se genera de forma gratuita.
python foo.py
usage: foo.py <action> [<options>]
foo.py --help
actions:
bar:
action bar does bar
--id integer 0
--title string default title
foo:
action foo does foo
--name string
Yo prefiero optparse a getopt.Es muy declarativa:usted dice que los nombres de las opciones y los efectos que debe tener (por ejemplo, la configuración de un campo booleano), y manos a la espalda un diccionario poblada de acuerdo a sus especificaciones.
consoleargs merece ser mencionado aquí.Es muy fácil de usar.Check it out:
from consoleargs import command
@command
def main(url, name=None):
"""
:param url: Remote URL
:param name: File name
"""
print """Downloading url '%r' into file '%r'""" % (url, name)
if __name__ == '__main__':
main()
Ahora en la consola:
% python demo.py --help
Usage: demo.py URL [OPTIONS]
URL: Remote URL
Options:
--name -n File name
% python demo.py http://www.google.com/
Downloading url ''http://www.google.com/'' into file 'None'
% python demo.py http://www.google.com/ --name=index.html
Downloading url ''http://www.google.com/'' into file ''index.html''
Argparse código puede ser más largo que el actual código de implementación!
Ese es un problema que me encontré con la mayoría popular argumento de opciones de análisis es que si los parámetros son sólo modesta, el código del documento se convierte en desproporcionadamente grande para el beneficio que aportan.
Un relativo recién llegado a la argumentación de análisis de escena (creo) es plac.
Hace algunos reconoció trade-offs con argparse, pero utiliza documentación en línea y simplemente envuelve alrededor de main()
función tipo de función:
def main(excel_file_path: "Path to input training file.",
excel_sheet_name:"Name of the excel sheet containing training data including columns 'Label' and 'Description'.",
existing_model_path: "Path to an existing model to refine."=None,
batch_size_start: "The smallest size of any minibatch."=10.,
batch_size_stop: "The largest size of any minibatch."=250.,
batch_size_step: "The step for increase in minibatch size."=1.002,
batch_test_steps: "Flag. If True, show minibatch steps."=False):
"Train a Spacy (http://spacy.io/) text classification model with gold document and label data until the model nears convergence (LOSS < 0.5)."
pass # Implementation code goes here!
if __name__ == '__main__':
import plac; plac.call(main)
He aquí un método, no una biblioteca, que parece funcionar para mí.
Los objetivos aquí son para ser breves, cada uno de los argumentos analizados por una sola línea, los argumentos de la línea para mejorar la legibilidad, el código es sencillo y no depende de ninguna de módulos especiales (sólo os + sys), advierte sobre la falta o desconocido argumentos correctamente, el uso de un simple para/rango() loop, y funciona a través de python 2.x y 3.x
Se muestran son dos alternar banderas (-d, -v), y dos valores controlados por los argumentos (-i xxx y -o xxx).
import os,sys
def HelpAndExit():
print("<<your help output goes here>>")
sys.exit(1)
def Fatal(msg):
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
sys.exit(1)
def NextArg(i):
'''Return the next command line argument (if there is one)'''
if ((i+1) >= len(sys.argv)):
Fatal("'%s' expected an argument" % sys.argv[i])
return(1, sys.argv[i+1])
### MAIN
if __name__=='__main__':
verbose = 0
debug = 0
infile = "infile"
outfile = "outfile"
# Parse command line
skip = 0
for i in range(1, len(sys.argv)):
if not skip:
if sys.argv[i][:2] == "-d": debug ^= 1
elif sys.argv[i][:2] == "-v": verbose ^= 1
elif sys.argv[i][:2] == "-i": (skip,infile) = NextArg(i)
elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
elif sys.argv[i][:2] == "-h": HelpAndExit()
elif sys.argv[i][:1] == "-": Fatal("'%s' unknown argument" % sys.argv[i])
else: Fatal("'%s' unexpected" % sys.argv[i])
else: skip = 0
print("%d,%d,%s,%s" % (debug,verbose,infile,outfile))
El objetivo de NextArg() es devolver el siguiente argumento, mientras que la comprobación de los datos que faltan, y 'saltar' salta el bucle cuando NextArg() se utiliza, manteniendo la bandera de análisis de abajo a los trazadores de líneas uno.
Yo extendida de Erco método para permitir requiere argumentos posicionales y de argumentos opcionales.Estos deben preceder al -d, -v, etc.argumentos.
De posición y argumentos opcionales se pueden recuperar con PosArg(i) y OptArg(yo, por defecto), respectivamente.Cuando un argumento opcional se encuentra la posición de inicio de la búsqueda de opciones (por ejemplo,-yo) se mueve 1 por delante para evitar que se produzca un 'inesperado' fatal.
import os,sys
def HelpAndExit():
print("<<your help output goes here>>")
sys.exit(1)
def Fatal(msg):
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
sys.exit(1)
def NextArg(i):
'''Return the next command line argument (if there is one)'''
if ((i+1) >= len(sys.argv)):
Fatal("'%s' expected an argument" % sys.argv[i])
return(1, sys.argv[i+1])
def PosArg(i):
'''Return positional argument'''
if i >= len(sys.argv):
Fatal("'%s' expected an argument" % sys.argv[i])
return sys.argv[i]
def OptArg(i, default):
'''Return optional argument (if there is one)'''
if i >= len(sys.argv):
Fatal("'%s' expected an argument" % sys.argv[i])
if sys.argv[i][:1] != '-':
return True, sys.argv[i]
else:
return False, default
### MAIN
if __name__=='__main__':
verbose = 0
debug = 0
infile = "infile"
outfile = "outfile"
options_start = 3
# --- Parse two positional parameters ---
n1 = int(PosArg(1))
n2 = int(PosArg(2))
# --- Parse an optional parameters ---
present, a3 = OptArg(3,50)
n3 = int(a3)
options_start += int(present)
# --- Parse rest of command line ---
skip = 0
for i in range(options_start, len(sys.argv)):
if not skip:
if sys.argv[i][:2] == "-d": debug ^= 1
elif sys.argv[i][:2] == "-v": verbose ^= 1
elif sys.argv[i][:2] == "-i": (skip,infile) = NextArg(i)
elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
elif sys.argv[i][:2] == "-h": HelpAndExit()
elif sys.argv[i][:1] == "-": Fatal("'%s' unknown argument" % sys.argv[i])
else: Fatal("'%s' unexpected" % sys.argv[i])
else: skip = 0
print("Number 1 = %d" % n1)
print("Number 2 = %d" % n2)
print("Number 3 = %d" % n3)
print("Debug = %d" % debug)
print("verbose = %d" % verbose)
print("infile = %s" % infile)
print("outfile = %s" % outfile)