2012-01-26 20 views
23

Ho riscontrato un piccolo problema con argparse. Ho un'opzione xlim che è lo xrange di un grafico. Voglio essere in grado di passare numeri come -2e-5. Tuttavia questo non funziona - interpreti argparse questo è un argomento posizionale. Se faccio -0.00002 funziona: argparse lo legge come numero negativo. È possibile avere la capacità di leggere in -2e-3?Python Argparse: problema con argomenti facoltativi che sono numeri negativi

Il codice è al di sotto, e un esempio di come vorrei correre che è:

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

Se faccio la seguente funziona:

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

Il codice:

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

Anche se riesco a farlo funzionare in questo modo, preferirei utilizzare la notazione scientifica. Qualcuno ha qualche idea?

Acclamazioni

+0

Il quoting '-2e-5' è d'aiuto? – nmichaels

+0

Secondo http://code.google.com/p/argparse/issues/detail?id=37 avrebbe dovuto essere riparato. Controlla se la versione di argparse che hai è più nuova o uguale. – favoretti

+0

@nmichaels Ciao, vuoi dire "-2e-5"? Sfortunatamente non funziona, penso che lo interpreti ancora come un argomento. L'errore esatto da './blah.py -xlim" -.2e-5 "1e5' è --xlim: 2 argomento (i) previsto (i). Se uso \ - si pensa che sia una stringa e poi si lamenta perché dovrebbe essere un float – Ger

risposta

11

come già evidenziato dai commenti, il problema è che un prefisso - viene analizzato come opzione anziché come argomento. Un modo per aggirare questo è cambiare il prefisso utilizzato per le opzioni con prefix_chars argomento:

#!/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() 

uscita Esempio:

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

Edit: In alternativa, è possibile continuare a utilizzare - come separatore, passare xlim come un unico il valore e utilizzare una funzione in type per implementare la propria analisi:

#!/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() 

Esempio outp ut:

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

Desideravo davvero mantenere il' -' come separatore, quindi ho fatto un'analisi approssimativa del sys .argv prima che io chiamassi parse_args(). Il modo in cui l'ho fatto è in un commento sopra, ma la tua strada è molto meglio. Grazie! – Ger

3

Se si sono fino a modificare argparse.py sé, è possibile modificare il numero al taglio negativi per gestire la notazione scientifica:

In class _ActionsContainer.__init__()

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

o dopo aver creato il parser, è potrebbe impostare parser._negative_number_matcher su questo valore. Questo approccio potrebbe avere problemi se si stanno creando gruppi o subparatori, ma si dovrebbe lavorare con un parser semplice.

19

Una soluzione alternativa che ho trovato è di citare il valore, ma aggiungendo uno spazio. Cioè,

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

In questo modo argparse non penserà -2.e-3 è un nome opzione perché il primo carattere non è un trattino-dash, ma sarà ancora convertito correttamente per un galleggiante in quanto galleggiante (stringa) ignora gli spazi a sinistra.

+1

bello! Ho lavorato per me anche in un linguaggio/ambiente completamente diverso –

+0

Ho creato un piccolo preprocessore che esegue la scansione di sys.argv per "xlim" e aggiunge uno spazio all'inizio (tramite la risposta). Metto questo prima della chiamata ad argparse, e sembra funzionare bene ... 'per indx in range (len (sys.argv) - 1): if 'xlim' in sys.argv [indx]: sys.argv [indx + 1] = '{0}'. format (sys.argv [indx + 1]) ' – jeremiahbuddha

+0

Funziona anche nel modulo argparse torcia –

3

Ecco il codice che utilizzo. (È simile a quello di jeremiahbuddha, ma risponde più direttamente alla domanda poiché tratta di numeri negativi.)

mettere questo prima di chiamare argparse.ArgumentParser()

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

risposta migliore e più semplice per questo bug di lunga data – mxmlnkn

2

Un'altra soluzione consiste nel passare nell'argomento usando '=' simbolo, oltre a citare l'argomento - vale a dire, --xlim="-2.3e14"

1

Ispirato approccio di andrewfn, ho creato una funzione di supporto separato per fare il sys.argv giocherellare:

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 regex cerca:

  • -: un segno negativo
  • \\d*: zero o più cifre (per i valori stranamente formattati come -.5e-2 o -4354.5e-6)
  • \\.?: un periodo facoltativo (ad esempio, -2e-5 è ragionevole)
  • \\d*: un'altra serie di zero o più cifre (per cose come -2e-5 e -7.e-3)
  • e: per abbinare il marcatore esponente

re.I rende abbinare sia -2e-5 e -2E-5. L'utilizzo di p.match significa che ricerca solo dall'inizio di ogni stringa.

0

Se si specifica il valore per la vostra opzione con un segno di uguale, argparse non si trattarlo come opzione separata, anche se inizia con -:

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

E se il valore non avere spazi in esso, è possibile eliminare le virgolette:

./blaa.py --xlim=-0.002 

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

Con questo, non c'è bisogno di scriverti r possedere il parser type= o ridefinire il carattere prefisso da - a @ come suggerito dalla risposta accettata.

+0

Questo non funziona in questo caso particolare perché --- xlim si aspetta due argomenti (nargs = 2). Cioè, a meno che tu non voglia cambiare la convenzione in modo che il tuo programma richieda che l'invocatore codifichi i due valori come una singola stringa, e il tuo programma esegua la divisione. – itub

+0

Ah, buon punto @ end. Se 'nargs = 2' è il requisito E uno qualsiasi dei due valori di opzione inizia con un trattino, quindi non c'è modo di aggirarlo. – mksios

Problemi correlati