2012-06-30 27 views
5

Me gustaría asociar argumentos posicionales con el "estado del argumento" que existe cuando se producen. Por ejemplo, la siguiente línea de comandos:¿Puede argparse asociar argumentos posicionales con argumentos con nombre?

script.py -m 1 foo -r 2 bar -r 7 baz -m 6 quux 

debe producir las siguientes asociaciones:

foo: m=1, r=0 (default value for r) 
bar: m=1, r=2 
baz: m=1, r=7 
quux: m=6, r=7 

se puede hacer esto con el módulo argparse?

+0

¿El conjunto de "estados de argumento" es constante? p.ej. ¿sabes de antemano si solo '('foo', 'bar', 'baz', 'quux' ...) alguna vez se utilizarán? ¿O el usuario puede poner lo que quiera siempre que lo desee? – mgilson

+0

@mgnilson - Cualquier cosa donde quieran; lo que estoy viendo es una lista de nombres de archivos y opciones de procesamiento. Basado en el manejo de argumentos posicionales de 'argparse', estoy pensando que esto no se puede hacer sin una acción personalizada que rompa el modelo, que es con lo que estoy jugando actualmente. –

+0

Estaba pensando en acciones personalizadas también, pero eso es complicado porque argparse parece suponer que todos los argumentos posicionales se dan juntos. El único remedio es usar 'nargs = '*'' en todas partes y luego dentro de todas tus acciones verificar para asegurarte de que tienes el número correcto. (que parece frágil en el mejor de los casos). Por supuesto, esto se vuelve mucho más fácil si se permite: '-m 1 -f foo -r 2 -f bar -r 7 -f baz -m 6 -f quux' – mgilson

Respuesta

1

Esto puede no ser útil para usted, pero este problema parece ser más fácil si puede dividir sys.argv en partes - Esencialmente, debe ser capaz de averiguar qué piezas se supone que son argumentos "posicionales" (no es realmente posicional ya que, como dices, pueden ocurrir en cualquier lugar) y qué piezas se supone que son algún tipo de argumento. En el siguiente ejemplo, lo configuré para que funcione con su ejemplo, pero podría fácilmente dividir sys.argv en archivos, o en cierto tipo de archivo. La función condition depende de usted para escribir. El resto (con suerte) será autoexplicativo.

import argparse 
import sys 
import copy 
import os 

def split_list(lst,condition): 
    current=[] 
    out=[current] 
    for arg in lst: 
     current.append(arg) 
     if(condition(arg)): 
      current=[] 
      out.append(current) 

    return out 


parser=argparse.ArgumentParser() 
parser.add_argument('-m',action='store') 
parser.add_argument('-r',default='0',action='store') 
#pieces=split_list(sys.argv[1:],os.path.isfile) 
pieces=split_list(sys.argv[1:],lambda x: x in ('foo','bar','baz','quux')) 
options={} #use collections.OrderedDict if order matters -- or some more suitable data structure. 
default=argparse.Namespace() 
for args in pieces: 
    if(not args): 
     continue 
    ns=copy.deepcopy(default) 
    default=parser.parse_args(args[:-1],namespace=ns) 
    options[args[-1]]=default 

print (options) 
+0

¡Interesante idea! Cambiar la lambda a 'x [0]! =" - "' debería funcionar para dividir los argumentos eficazmente (creo que la sintaxis básica que propongo hace que no sea razonable aceptar nombres de archivo comenzando con '-' de todos modos). Déjame jugar con esto. –

+0

@BenBlank cambiar la lambda a 'no x.startswith ('-')' fue mi primer pensamiento también, pero falla en su ejemplo de prueba ya que '1' no comienza con '- – mgilson

+0

Lo solucioné por [reemplazando la lambda] (https://gist.github.com/3026853) con lógica codificada que se niega a dividirse después de un parámetro con nombre. ¡Con ese cambio, esto está haciendo exactamente lo que necesito! Gracias por la ayuda. –

Cuestiones relacionadas