ejemplo - optparse python 3
¿Procesando múltiples valores para una sola opción usando getopt/optparse? (7)
A pesar de las afirmaciones de los otros comentarios, esto es posible con vainilla optparse, al menos a partir de python 2.7. Solo necesitas usar action = "append". De la docs :
parser.add_option("-t", "--tracks", action="append", type="int")
Si se ve -t3 en la línea de comandos, optparse hace el equivalente de:
options.tracks = []
options.tracks.append(int("3"))
Si, un poco más tarde, se ve --tracks = 4, lo hace:
options.tracks.append(int("4"))
¿Es posible obtener múltiples valores para una opción usando getopt o optparse, como se muestra en el siguiente ejemplo:
./hello_world -c arg1 arg2 arg3 -b arg4 arg5 arg6 arg7
Tenga en cuenta que el número de valores reales para cada opción (-c, -b) podría ser 1 o 100. No quiero usar: ./hello_world -c "arg1 arg2 arg3" -b "arg4 arg5 arg6 arg7"
Me parece que esto puede no ser posible (y quizás en violación de POSIX), corríjame si me equivoco.
He visto ejemplos donde todas las no opciones al final de la línea ( ./hello_world -c arg1 -b arg1 arg2 arg3
) se pueden recopilar ... pero no para la primera opción múltiple.
Me gustaría que mi aplicación funcionara en una amplia gama de plataformas con diferentes versiones de Python, por lo que no he visto argparser.
Ni getopt ni optparse admiten esto fuera de la caja. Además, en el modo predeterminado (GNU), los argumentos adicionales se tratarán como argumentos intercalados, es decir, estarán disponibles como argumentos sobrantes al final del procesamiento.
La convención sería requerir la mención repetida del mismo argumento, es decir,
./hello_world -c arg1 -c arg2 -c arg3 -b arg4 -b arg5 -b arg6 -b arg7
Esto es apoyado
Si absolutamente quieres que funcione de la manera que especifiques (es decir, tanto -b como -c se extienden hasta el siguiente - argumento o el final de la lista de argumentos), entonces puedes hackear algo junto con optparse. Heredar de OptionParser e invalidar _process_short_opts. Si es una de tus opciones, procesala en la subclase, o reenvía a la clase base.
Otra opción sería definir un separador y procesarlo localmente, como las opciones en el comando de montaje.
Por ejemplo, si puede usarse como separador:
...
args, _ = getopt.getopt(sys.argv[1:],''b:'')
for flag, arg in args:
if flag==''-b'': all_arguments = arg.split('','')
...
$ ./test -b opt1,opt2,opt3
Lo mismo para el espacio! Pero entonces sus usuarios tienen que citarlo correctamente.
$ ./test -b ''opt1 opt2 opt3''
Perdón por llegar tarde a la fiesta, pero resolví esto con optparse usando la bandera de nargs.
parser.add_option(''-c'',''--categories'', dest=''Categories'', nargs=4 )
http://docs.python.org/2/library/optparse.html#optparse.Option.nargs
También vale la pena señalar, que argparse (sugerido por unutbu) ahora es parte de la distribución estándar de Python, mientras que optparse está en desuso.
Puede hacer esto con el parámetro nargs
en argparse
que viene con Python2.7, y descargable here .
Creo que es una de las mejoras agregadas a argparse
que no está en optparse
. Entonces, desafortunadamente, no creo que haya una buena manera de manejar esto con optparse
o getopt
(que es aún más antiguo).
Una solución rápida y sucia podría ser renunciar a optparse/getop/argparse
y simplemente analizar sys.argv
usted mismo.
O, yendo en la dirección opuesta, podría considerar empaquetar una copia congelada de argparse (~ 88K) (renombrado algo como argparse_static
) con su programa, e importarlo de esta manera:
try:
import argparse
except ImportError:
import argparse_static as argparse
De esa manera, el programa usará argparse
si está instalado, y usará argparse_static
si no lo está. Lo mejor de todo es que no tendrá que volver a escribir tanto código como argparse
convierte en estándar.
Sí, se puede hacer con optparse.
Esto es un ejemplo:
./test.py --categories=aaa --categories=bbb --categories ccc arg1 arg2 arg3
que imprime:
arguments: [''arg1'', ''arg2'', ''arg3'']
options: {''categories'': [''aaa'', ''bbb'', ''ccc'']}
Ejemplo de trabajo completo a continuación:
#!/usr/bin/env python
import os, sys
from optparse import OptionParser
from optparse import Option, OptionValueError
VERSION = ''0.9.4''
class MultipleOption(Option):
ACTIONS = Option.ACTIONS + ("extend",)
STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)
def take_action(self, action, dest, opt, value, values, parser):
if action == "extend":
values.ensure_value(dest, []).append(value)
else:
Option.take_action(self, action, dest, opt, value, values, parser)
def main():
PROG = os.path.basename(os.path.splitext(__file__)[0])
long_commands = (''categories'')
short_commands = {''cat'':''categories''}
description = """Just a test"""
parser = OptionParser(option_class=MultipleOption,
usage=''usage: %prog [OPTIONS] COMMAND [BLOG_FILE]'',
version=''%s %s'' % (PROG, VERSION),
description=description)
parser.add_option(''-c'', ''--categories'',
action="extend", type="string",
dest=''categories'',
metavar=''CATEGORIES'',
help=''comma separated list of post categories'')
if len(sys.argv) == 1:
parser.parse_args([''--help''])
OPTIONS, args = parser.parse_args()
print "arguments:", args
print "options:", OPTIONS
if __name__ == ''__main__'':
main()
Más información en http://docs.python.org/library/optparse.html#adding-new-actions
Una más fácil:
make_option(
"-c",
"--city",
dest="cities",
action="append",
default=[],
help="specify cities",
)
La acción de anexar es la solución más fácil para este problema.