2012-01-26 15 views
23

Tengo un pequeño problema con argparse. Tengo una opción xlim que es xrange de una parcela. Quiero poder pasar números como -2e-5. Sin embargo, esto no funciona: argparse interpreta que este es un argumento posicional. Si lo hago -0.00002 funciona: argparse lo lee como un número negativo. ¿Es posible haber leído en -2e-3?Python Argparse: Problema con argumentos opcionales que son números negativos

El código está por debajo, y un ejemplo de cómo iba a ejecutar es:

./blaa.py --xlim -2.e-3 1e4 

Si hago lo siguiente funciona:

./blaa.py --xlim -0.002 1e4 

El código:

parser.add_argument('--xlim', nargs = 2, 
        help = 'X axis limits', 
        action = 'store', type = float, 
        default = [-1.e-3, 1.e-3]) 

Aunque puedo hacer que funcione de esta manera, realmente podría utilizar la notación científica. ¿Alguien tiene alguna idea?

Saludos

+0

¿Cita la ayuda '-2e-5'? – nmichaels

+0

De acuerdo con http://code.google.com/p/argparse/issues/detail?id=37, debería haberse solucionado. Compruebe si la versión de argparse que tiene es más nueva o la misma. – favoretti

+0

@nmichaels Hola, ¿quieres decir "-2e-5"? Desafortunadamente, no funciona, creo que todavía lo interpreta como un argumento. El error exacto de './blah.py -xlim" -.2e-5 "1e5' es --xlim: esperado 2 argumento (s). Si uso \ - cree que es una cadena y luego se queja porque debería ser un flotador – Ger

Respuesta

11

Como ya se ha señalado por los comentarios, el problema es que un prefijo - se analiza como una opción en lugar de como un argumento. Una forma de solucionar esto es cambiar el prefijo utilizado para opciones con prefix_chars argumento:

#!/usr/bin/python 
import argparse 

parser = argparse.ArgumentParser(prefix_chars='@') 
parser.add_argument('@@xlim', nargs = 2, 
        help = 'X axis limits', 
        action = 'store', type = float, 
        default = [-1.e-3, 1.e-3]) 
print parser.parse_args() 

Ejemplo de salida:

$ ./blaa.py @@xlim -2.e-3 1e4 
Namespace(xlim=[-0.002, 10000.0]) 

Editar: Como alternativa, puede seguir usando - como separador, pasan xlim como una sola valor y el uso de una función en type para implementar su propio análisis:

#!/usr/bin/python 
import argparse 

def two_floats(value): 
    values = value.split() 
    if len(values) != 2: 
     raise argparse.ArgumentError 
    values = map(float, values) 
    return values 

parser = argparse.ArgumentParser() 
parser.add_argument('--xlim', 
        help = 'X axis limits', 
        action = 'store', type=two_floats, 
        default = [-1.e-3, 1.e-3]) 
print parser.parse_args() 

Ejemplo outp UT:

$ ./blaa.py --xlim "-2e-3 1e4" 
Namespace(xlim=[-0.002, 10000.0]) 
+0

Realmente quería mantener el' -' como separador, así que hice un análisis crudo del sistema .argv antes de llamar a parse_args(). La forma en que lo hice es en un comentario anterior, pero tu camino es mucho mejor. ¡Gracias! – Ger

3

Si usted está hasta la modificación argparse.py sí, podría cambiar el matcher número negativo para manejar la notación científica:

En class _ActionsContainer.__init__()

self._negative_number_matcher = _re.compile(r'^-(\d+\.?|\d*\.\d+)([eE][+\-]?\d+)?$') 

O después de crear el analizador, se podría establecer parser._negative_number_matcher a este valor. Este enfoque podría tener problemas si está creando grupos o subparsores, pero debería funcionar con un analizador simple.

19

Una solución que he encontrado es citar el valor, pero agregando un espacio. Es decir,

./blaa.py --xlim " -2.e-3" 1e4 

Este argparse manera no pensará -2.e-3 es un nombre de opción debido a que el primer carácter no es un guión-guión, pero seguirá siendo convertidos correctamente a un flotador porque flotador (cadena) ignora los espacios de la izquierda.

+1

¡agradable! Funcionó para mí en un lenguaje/entorno completamente diferente también –

+0

Hice un pequeño preprocesador que escanea sys.argv para "xlim" y agrega un espacio al principio (a través de su respuesta). Puse esto antes de la llamada a argparse, y parece estar funcionando bien ... 'para indx en rango (len (sys.argv) - 1): si 'xlim' en sys.argv [indx]: sys.argv [indx + 1] = '{0}'. format (sys.argv [indx + 1]) ' – jeremiahbuddha

+0

Esto también funciona en el módulo argparse de la antorcha –

3

Aquí está el código que uso. (Es similar a la de jeremiahbuddha, pero responde la pregunta de manera más directa, ya que trata con números negativos.)

poner esto antes de llamar argparse.ArgumentParser()

for i, arg in enumerate(sys.argv): 
    if (arg[0] == '-') and arg[1].isdigit(): sys.argv[i] = ' ' + arg 
+0

mejor y más fácil respuesta para este bug de larga data – mxmlnkn

2

Otra solución consiste en pasar en el argumento usando '=' símbolo además de citar el argumento - es decir, --xlim="-2.3e14"

1

Inspirado por el enfoque de andrewfn, me creado una función auxiliar por separado a la sys.argv tocar el violín:

def _tweak_neg_scinot(): 
    import re 
    import sys 
    p = re.compile('-\\d*\\.?\\d*e', re.I) 
    sys.argv = [' ' + a if p.match(a) else a for a in sys.argv] 

la expresión regular busca:

  • -: un signo negativo
  • \\d*: cero o más dígitos (para valores extrañamente formateados como -.5e-2 o -4354.5e-6)
  • \\.?: un período opcional (por ejemplo, -2e-5 es razonable)
  • \\d*: otro conjunto de cero o más dígitos (para cosas como -2e-5 y -7.e-3)
  • e: para que coincida con el marcador exponente

re.I hace que se acople tanto -2e-5 y -2E-5. Usar p.match significa que solo busca desde el inicio de cada cadena.

0

Si especifica el valor para su opción con un signo de igual, argparse no lo tratará como una opción independiente, incluso si se comienza con -:

./blaa.py --xlim='-0.002 1e4' 
# As opposed to --xlim '-0.002 1e4' 

Y si el valor no tiene espacios en ella, usted puede bajar las cotizaciones:

./blaa.py --xlim=-0.002 

Ver: https://www.gnu.org/software/guile/manual/html_node/Command-Line-Format.html

con esto, no hay necesidad de escribir se r propio type= analizador o redefinir el carácter de prefijo de - a @ como la respuesta aceptada sugiere.

+0

Esto no funciona en este caso particular porque --- xlim espera dos argumentos (nargs = 2). Es decir, a menos que desee cambiar la convención para que su programa _requiere_ el invocador para codificar los dos valores como una sola cadena, y luego su programa realiza la división. – itub

+0

Ah, buen punto @itub. Si 'nargs = 2' es el requisito Y cualquiera de los dos valores de opción comienza con un guión, entonces no hay forma de evitarlo. – mksios

Cuestiones relacionadas