2009-06-22 10 views
11

Con Perl de Getopt::Long puede definir fácilmente las opciones de línea de comandos que tienen un número variable de argumentos:Con el módulo optparse de Python, ¿cómo se crea una opción que toma una cantidad variable de argumentos?

foo.pl --files a.txt    --verbose 
foo.pl --files a.txt b.txt c.txt --verbose 

¿Hay una manera de hacer esto directamente con el módulo de Python optparse? Por lo que puedo decir, el atributo de opción nargs se puede usar para especificar un número fijo de argumentos de opciones, y no he visto otras alternativas en la documentación.

+1

Especifique los nombres de archivo mediante argumentos, no mediante la opción: 'foo.pl a.txt b.txt c.txt --verbose' Los nombres de archivo se pondrían en args en este caso. – jfs

+0

Si --files define las entradas, este enfoque no es recomendable. –

Respuesta

8

Creo que optparse no es compatible con lo que necesita (no directamente - como notó, ¡puede hacerlo si está dispuesto a hacer todo el trabajo extra de una devolución de llamada! -). También podría hacerlo más simplemente con la extensión de terceros argparse, que sí admite números de argumentos variables (y también agrega varios otros prácticos bits de funcionalidad).

This URL documentos argparse 's add_argument - que pasan nargs='*' permite la opción de tomar cero o más argumentos, '+' permite que tome uno o más argumentos, etc.

+4

'argparse' está en Python 2.7+ http://docs.python.org/library/argparse.html – jfs

+2

Sí, pero si aún no puede actualizar a 2.7 (lanzado antes de ayer), el paquete de terceros es sigue siendo un regalo del cielo! -) –

9

Mi error: acabo de encontrar este Callback Example 6.

+4

Esta es definitivamente la mejor respuesta para la pregunta exacta; argparse es mucho mejor, pero no siempre se puede usar fácilmente: ej. en un comando de administración de Django. – Stefano

2

¿No sería mejor con esto?

foo.pl --files a.txt,b.txt,c.txt --verbose 
+1

No. Definitivamente no. Por ejemplo, esto prohibiría expansiones de shell como 'foo.py * .txt'. – Constantinius

+0

No creo que merezca un -1, podría ser una solución válida en algunos casos, como la lista de coma flotante en el enlace de documentación anterior. Tal vez el tono de cuestionamiento está un poco apagado (pero qué sé ...). – dhill

+0

@Constantinius - La expansión de la carcasa no siempre es deseable. Si se trata de un gran número de archivos de entrada, puede alcanzar un límite de longitud de línea de comando arbitrario (dinámico por el hecho de que se reduce en función del tamaño de su entorno), en cuyo caso, es mejor utilizar el método bsd_glob de perl glob para hacer la expansión después de haber recibido los argumentos. Normalmente proporciono varios archivos/patrones globales dentro de comillas, delimitados por espacios. – hepcat72

20

Esto me tomó un poco de tiempo para averiguarlo, pero puede utilizar la acción de devolución de llamada a sus opciones para hacer esto. Verifica cómo capturo un número arbitrario de argumentos en el indicador "--file" en este ejemplo.

from optparse import OptionParser, 

def cb(option, opt_str, value, parser): 
     args=[] 
     for arg in parser.rargs: 
       if arg[0] != "-": 
         args.append(arg) 
       else: 
         del parser.rargs[:len(args)] 
         break 
     if getattr(parser.values, option.dest): 
       args.extend(getattr(parser.values, option.dest)) 
     setattr(parser.values, option.dest, args) 

parser=OptionParser() 
parser.add_option("-q", "--quiet", 
     action="store_false", dest="verbose", 
     help="be vewwy quiet (I'm hunting wabbits)") 
parser.add_option("-f", "--filename", 
     action="callback", callback=cb, dest="file") 

(options, args) = parser.parse_args() 

print options.file 
print args 

El único efecto secundario es que obtiene sus args en una lista en lugar de tupla. Pero eso podría arreglarse fácilmente, para mi caso particular de uso, una lista es deseable.

+0

En realidad, prefiero el ejemplo en el documento python como se muestra en la respuesta FMc: http://stackoverflow.com/a/1025230/422670 – Stefano

+1

Los dos son funcionalmente equivalentes, excepto que el código de ejemplo también permite que valores como "-1" sean analizado como args para la bandera, que es una buena característica, supongo, para algunos casos de uso. –

+0

de hecho, permite números negativos (también me gusta que viene directamente de los documentos oficiales :)) – Stefano

0

Aquí hay una manera: Tome la cadena de generación de fileLst en forma de cadena y luego usar http://docs.python.org/2/library/glob.html hacer la expansión uf esto podría no funcionar sin escapar del *

En realidad, tiene una mejor manera: pitón myprog.py -V -l 1000 /home/dominic/radar/*.json < - Si es tu línea de comandos

analizador, opta = parse_args()

inFileLst = parser.largs

1

Recientemente tuve este problema: estaba en Python 2.6 y necesitaba una opción para tomar una cantidad variable de argumentos. He intentado utilizar la solución de Dave, pero descubrí que no funcionaría sin nargs también establecer explícitamente a 0.

def arg_list(option, opt_str, value, parser): 
    args = set() 
    for arg in parser.rargs: 
     if arg[0] == '-': 
      break 
     args.add(arg) 
     parser.rargs.pop(0) 
    setattr(parser.values, option.dest, args) 

parser=OptionParser() 
parser.disable_interspersed_args() 
parser.add_option("-f", "--filename", action="callback", callback=arg_list, 
        dest="file", nargs=0) 

(options, args) = parser.parse_args() 

El problema era que, por defecto, una nueva opción añadida por add_options se supone que tiene nargs = 1 y cuando nargs> 0 OptionParser sacará objetos de rargs y los asignará al valor antes de llamar a cualquier devolución de llamada. Por lo tanto, para las opciones que no especifiquen nargs, los rargs siempre estarán desactivados en uno para cuando se llame su devolución de llamada.

Esta devolución de llamada se puede utilizar para cualquier cantidad de opciones, solo tiene que llamar a callback_args para llamar a la función en lugar de setattr.

+0

este funciona para mí con un pequeño cambio: "if arg [0] == '-':" –

Cuestiones relacionadas