2010-08-11 19 views
11

Actualmente mi código es así. Me permite analizar múltiples parámetros que obtiene mi script de programa. ¿Hay alguna manera diferente de acercarse a las "mejores prácticas"? No he visto el código realmente utilizando la salida argparse, solo cómo configurarlo.Uso de la salida argparse para llamar a funciones

def useArguments(): 
    x = 0 
    while x <= 5: 
     if x == 0:      
      if args.getweather != None: 
       getWeather(args.getweather) 
     if x == 1: 
      if args.post != None: 
       post(args.post) 
     if x == 2: 
      if args.custompost != None: 
       custompost(args.custompost) 
     if x == 3: 
      if args.list != None: 
       listAccounts(args.list) 
     if x == 4: 
      if args.add != None: 
       addAccount(args.add[0]) 
     if x == 5: 
      if args.edit != None: 
       editAccount(args.edit[0]) 
     x = x + 1  


if __name__ == '__main__': 

    updateConfig() 

    parser = argparse.ArgumentParser(description='Post Yahoo weather to Twitter.', epilog="Report any bugs to [email protected]", prog='Program') 

    parser.add_argument('-a', '--add', nargs=1, help='Add a new account. Use the desired account name as an argument.') 
    parser.add_argument('-e', '--edit', nargs=1, choices=accountListSTR[:-1], help='Edit an account. Use the desired account name as an argument.') 
    parser.add_argument('-g', '--getweather', nargs='*', choices=accountListSTR, help='Get weather and post here. Specify account(s) as argument. Use "all" for all accounts. If you specify multiple accounts, separate by a space NOT a comma.') 
    parser.add_argument('-p', '--post', nargs='*', choices=accountListSTR, help='Post weather to Twitter. Specify account(s) as argument. Use "all" for all accounts. If you specify multiple accounts, separate by a space NOT a comma.') 
    parser.add_argument('-c', '--custompost', nargs=2, help='Post a custom message. Specify an account then type the message. Make sure you use "" around the message. Use "all" for all accounts.') 
    parser.add_argument('-l', '--list', action='store_const', const='all', help='List all accounts.') 
    parser.add_argument('--version', action='version', version='%(prog)s 0.3.3') 

    args = parser.parse_args() 

    useArguments() 

Respuesta

11

Usted podría suministrar una costumbre action para un argumento por, y cito:

pasar un objeto que implementa la API Acción. La forma más fácil de hacer esto es es extender argparse.Action, suministrando un método apropiado __call__ . El método __call__ debe aceptar cuatro parámetros:

  1. analizador: el objeto ArgumentParser que contiene esta acción.
  2. namespace: El objeto de espacio de nombres que será devuelto por parse_args(). La mayoría de las acciones agregan un atributo a este objeto.
  3. valores:. Los argumentos de línea de comandos asociados, con cualquier tipo conversiones aplicado (tipo de conversiones se especifican con el tipo de palabra clave argumento para add_argument()
  4. option_string:. La cadena de opciones que se utiliza para invocar . el argumento esta acción option_string es opcional, y estará ausente si la acción está asociada con un argumento posicional
+0

¿En qué situaciones sería este el mejor método? No puedo ver el uso de todo ese código adicional. Pero, de nuevo, apenas usé Classes, así que probablemente me esté perdiendo algo. – avacariu

+1

@vlad, se podría usar para llamar automáticamente a una función cuando se proporciona un argumento, que es lo que está haciendo va a ser todo lo que se repite: simplemente tendrías que hacer que las funciones sean los métodos '__call__' de las subclases apropiadas de 'argparse.Action'. Pero si no "obtienes" programación orientada a objetos, está bien, puedes hacerlo a tu manera (aunque las comprobaciones de bucle y 'si x ==' son realmente redundantes en cualquier caso; simplemente haz una tras otra las verificaciones para qué argumentos están presentes posiblemente seguidor por las llamadas apropiadas, no hay ningún valor agregado en el otro texto repetitivo que utiliza). –

+0

He aceptado esta respuesta porque responde mi pregunta. Yo * podría * terminar intentando esto para aprender cómo funciona; pero requerirá muchos cambios en la forma en que mi código funciona actualmente (especialmente las funciones enumeradas allí). Gracias! – avacariu

4

Con la excepción de --version, que es muy comúnmente una opción, las acciones que nos ha facilitado están mejor tratados como "subcomandos".

estoy al tanto de los detalles argparse, ya que todavía tengo que probar Python 2.7, pero es posible echar un vistazo a la orden svn como ejemplo, he aquí algo de pseudocódigo para la línea de comandos:

myprog [--version] <command> [<command opts>...] 
Cuando

<command> en:

add|edit|getweather|post|custompost|list 

Y <command opts> son opciones específicas para ese comando. Usando optparse (que es similar), esto significaría que su comando sería devuelto en args, al llamar parse_args, que le permite hacer algo como esto:

opts, args = parser.parse_args() 
if opts.version: 
    ... 
else: 
    getattr("do_" + args[0])(*args[1:]) 

encuentro este patrón particularmente útil para la depuración, donde Proporcionar acceso a funciones internas desde la línea de comando y pasar varios argumentos para probar. Ajuste la selección del controlador de comando según corresponda para su propio proyecto.

+0

'argparse' realmente proporciona soporte para precisamente este patrón. ('optparse' no.) Todavía estoy atrapado en Python 2.6 por mi mismo, así que no sé los detalles de forma directa tampoco, pero están explicados en la [documentación] (http://docs.python.org/ library/argparse.html # subcomandos). –

+0

¿Cuál sería la ventaja de hacer esto en lugar de simplemente eliminar el '- 'de mis argumentos? Supongo que para el usuario final terminaría luciendo igual, ¿verdad? Supongo que tenerlo así tendría más sentido para el usuario, ya que en realidad no están ejecutando el programa con parámetros personalizados, sino diciéndole que haga algo. – avacariu

+0

@ vlad003: Eso es correcto. El usuario del programa debe seleccionar una y solo una de esas "opciones", así que realmente son comandos para su programa. Sin embargo, esos comandos potencialmente toman argumentos. Una alternativa es escribir scripts ejecutables separados para cada comando, realizar un análisis arg por separado en cada uno y llamar a una base de código común para la implementación. Por ejemplo, sus scripts podrían llamarse: myprog-list, myprog-add, etc. Sin embargo, podría agregar, como está usando argparse de Python-2.7, que podría haber un manejo de argumentos muy sofisticado ya incorporado en eso. –

6

Ver http://docs.python.org/library/argparse.html#sub-commands:.

Una forma particularmente efectiva de manejar los subcomandos es combinar el uso del método add_subparsers() con las llamadas al set_defaults() para que cada subparser sepa qué función Python debe ejecutar.

En pocas palabras:

parser = argparse.ArgumentParser() 
subparsers = parser.add_subparsers() 

weather_parser = subparsers.add_parser('get-weather') 
weather_parser.add_argument('--bar') 
weather_parser.set_defaults(function=get_weather) # ! 

args = parser.parse_args(['get-weather', '--bar', 'quux']) 
print args.function(args) 

Aquí creamos un subparser para el comando get-weather y asignar la función get_weather a ella.

Tenga en cuenta que la documentación dice que la palabra clave/atributo se llama func pero definitivamente es function como de argparse 1.1.

El código resultante es un poco demasiado prolijos por lo que he publicado un pequeño paquete "argh" que hace las cosas más simples, por ejemplo:

parser = argparse.ArgumentParser() 
add_commands(parser, [get_weather]) 
print dispatch(parser, ['get-weather', '--bar', 'quux']) 

"Argh" puede hacer más, pero voy a dejar que la pila respuesta desbordamiento . :-)

+2

Con respecto a la edición reciente de caffinatedmonkey ("No dejaré que esta pila se desborde" → "Dejaré que el desbordamiento de la pila responda eso"). La nueva versión suena bien, pero en realidad quería decir que la respuesta se hincharía si hubiera introducido demasiada información en el área de texto. =) –

+0

¿Estás seguro de que la parte 'func' /' function' sigue siendo verdadera? 'func' funciona bien para mí ... –

+0

No solo es feo el enfoque de subparsing, sino que parece pasar la tarea de análisis de argumentos a un nivel inferior; o bien tienes que tener funciones separadas para pasar a cada' func' que luego llama a sus funciones "reales", o sus funciones reales tienen que tomar el dict genérico args. Supongo que lo primero está bien para programas grandes, pero parece ridículo introducir tantas capas adicionales en un programa pequeño.De todos modos, los subparsers parecen ser la mejor opción hasta ahora. –

Cuestiones relacionadas