2009-06-22 17 views
11

Con Perl Getopt::Long si può facilmente definire le opzioni della riga di comando che accettano un numero variabile di argomenti:Con il modulo optparse di Python, come si crea un'opzione che richiede un numero variabile di argomenti?

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

C'è un modo per farlo direttamente con il modulo di Python optparse? Per quanto posso dire, l'attributo opzione nargs può essere utilizzato per specificare un numero fisso di argomenti di opzioni e non ho visto altre alternative nella documentazione.

+1

Specificare i nomi file tramite argomenti, non tramite l'opzione: 'foo.pl a.txt b.txt c.txt -verbose' I nomi dei file verrebbero inseriti in args in questo caso. – jfs

+0

Se --files definisce gli input, questo approccio non è raccomandato. –

risposta

8

Credo che optparse non supporti ciò che richiede (non direttamente - come hai notato, puoi farlo se sei disposto a fare tutto il lavoro extra di un callback! -). Potresti anche farlo semplicemente con l'estensione di terze parti argparse, che supporta numeri variabili di argomenti (e aggiunge anche altri utili bit di funzionalità).

This URL documenti argparse 's add_argument - che passano nargs='*' consente l'opzione prendere zero o più argomenti, '+' lascia prendere uno o più argomenti, ecc

+4

'argparse' è in Python 2.7+ http://docs.python.org/library/argparse.html – jfs

+2

Sì, ma se non è ancora possibile eseguire l'aggiornamento a 2.7 (rilasciato il giorno prima di ieri), il pacchetto di terze parti è ancora una manna dal cielo! -) –

9

Il mio errore: ho appena trovato questo Callback Example 6.

+4

Questa è sicuramente la migliore risposta per la domanda esatta; argparse è molto meglio, ma non puoi sempre usarlo facilmente: es. in un comando di gestione Django. – Stefano

2

Non sareste meglio con questo?

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

No. Decisamente no. Ad esempio, ciò proibirebbe espansioni di shell come 'foo.py * .txt'. – Constantinius

+0

Non penso che meriti un -1, potrebbe essere una soluzione valida in alcuni casi, come la lista in virgola mobile nel link alla documentazione sopra. Forse il tono dell'interrogatorio è un po 'off (ma cosa ne so ...). – dhill

+0

@Constantinius - L'espansione della shell non è sempre auspicabile. Se hai a che fare con un numero elevato di file di input, puoi raggiungere un limite di lunghezza della riga di comando arbitrario (reso dinamico dal fatto che si riduce in base alle dimensioni dell'ambiente), nel qual caso, è meglio usare il metodo bsd_glob di perl glob per fare l'espansione dopo aver ricevuto gli argomenti. Di solito fornisco più file/modelli glob all'interno di virgolette, delimitate. – hepcat72

20

Questo mi ci è voluto un po 'per capire, ma è possibile utilizzare l'azione di callback per le opzioni per ottenere questo risultato. Scopri come faccio ad afferrare un numero arbitrario di arg per il flag "--file" in questo esempio.

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 

Unico effetto collaterale è che si ottiene il proprio argomento in una lista anziché in tupla. Ma ciò potrebbe essere facilmente risolto, per il mio particolare caso d'uso è auspicabile una lista.

+0

In realtà preferisco l'esempio nel documento python come mostrato nella risposta FMc: http://stackoverflow.com/a/1025230/422670 – Stefano

+1

I due sono funzionalmente equivalenti, tranne che il codice di esempio consente anche valori come "-1" analizzato come args alla bandiera che è una caratteristica piacevole, suppongo per alcuni casi d'uso. –

+0

infatti, consente numeri negativi (mi piace anche che provenga direttamente dai documenti ufficiali :)) – Stefano

0

Ecco un modo: prendere la stringa generando fileLst come una stringa e quindi utilizzare http://docs.python.org/2/library/glob.html per fare l'espansione ugh questo potrebbe non funzionare senza sfuggire al *

In realtà, un modo migliore: pitone myprog.py -V -l 1000 /home/dominic/radar/*.json < - Se questa è la linea di comando

parser, opta = parse_args()

inFileLst = parser.largs

1

Recentemente ho riscontrato questo problema: ero su Python 2.6 e avevo bisogno di un'opzione per prendere un numero variabile di argomenti. Ho cercato di usare la soluzione di Dave, ma ha scoperto che non avrebbe funzionato senza nargs anche impostando esplicitamente 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() 

Il problema era che, per impostazione predefinita, una nuova opzione aggiunta da add_options si assume di avere nargs = 1 e quando nargs> 0 OptionParser espellerà gli elementi da rarg e li assegnerà al valore prima che vengano richiamati tutti i callback. Pertanto, per le opzioni che non specificano nargs, rargs sarà sempre disattivato di uno al momento in cui viene richiamato il callback.

Questo callback può essere utilizzato per qualsiasi numero di opzioni, è sufficiente chiamare callback_args invece di setattr.

+0

questo funziona per me con una piccola modifica: "if arg [0] == '-':" –

Problemi correlati