6.20.4.4 Esempi

Ecco un'esempio di opzione di callback che non accetta argomenti, e registra solamente il fatto che l'opzione è stata specificata:

def record_foo_seen(option, opt, value, parser):
    parser.saw_foo = 1

parser.add_option("--foo", action="callback", callback=record_foo_seen)

Naturalmente, potreste fare questo con l'azione ``store_true''. Ecco un esempio un po' più interessante: viene registrato il fatto che -a è stato specificato, ma se specificato dopo -b sulla riga di comando, viene considerato non valido.

def check_order(option, opt, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use -a after -b")
    parser.values.a = 1
...
parser.add_option("-a", action="callback", callback=check_order)
parser.add_option("-b", action="store_true", dest="b")

Se volete riutilizzare questa funzione di callback per diverse opzioni simili (definire una stringa di opzione, ma invalidarla se -b è stata già invocata), è necessario lavorarci sopra: il messaggio di errore e la stringa di opzione su cui viene impostato hanno bisogno di venire generalizzati.

def check_order(option, opt, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use %s after -b" % opt)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("-a", action="callback", callback=check_order, dest='a')
parser.add_option("-b", action="store_true", dest="b")
parser.add_option("-c", action="callback", callback=check_order, dest='c')

Naturalmente, potete valutare qualsiasi condizione -- non siete obbligati a controllare i valori delle opzioni già definite. Per esempio, se avete delle opzioni che non dovrebbero venire chiamate quando c'è luna piena, ciò che bisogna fare è questo:

def check_moon(option, opt, value, parser):
    if is_full_moon():
        raise OptionValueError("%s option invalid when moon full" % opt)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("--foo",
                  action="callback", callback=check_moon, dest="foo")

La definizione di is_full_moon() viene lasciato come esercizio al lettore.

Argomenti costanti

Le cose diventano un po' più interessanti quando si definiscono opzioni di callback che accettano un numero di argomenti prefissato. La specificazione che una opzione di callback accetti argomenti è simile alla definizione di una opzione ``store'' o ``append'': se definite un tipo, allora l'opzione accetta un argomento che sia convertibile in quel tipo; se in seguito definirete nargs, allora l'opzione accetterà tutti quegli argomenti.

Ecco un esempio che emula l'azione standard ``store'':

def store_value(option, opt, value, parser):
    setattr(parser.values, option.dest, value)
...
parser.add_option("--foo",
                  action="callback", callback=store_value,
                  type="int", nargs=3, dest="foo")

Notate che optparse si occupa di elaborare tre argomenti e di convertirli in interi al posto vostro; tutto quello che voi dovrete fare sarà memorizzarli. (O qualcosa di simile: ovviamente non c'è bisogno di una funzione di callback per questo esempio. Usate la vostra immaginazione!)

Argomenti variabili

Le cose si complicheranno nel momento in cui vorrete un'opzione che accetti un numero variabile di argomenti. In questo caso dovrete scrivere una funzione di callback; optparse non possiede nessuna funzionalità built-in per poterlo fare Dovrete confrontarvi con la ben strutturata sintassi per poter effettuare l'analisi attraverso la riga di comando convenzionale Unix. (In precedenza optparse si prendeva in carico questo compito, ma non funzionava bene. L'errore è stato corretto, al costo però di rendere più complesso questo tipo di callback.) In particolare, le funzioni di callback devono preoccuparsi degli argomenti nudi -- e -; la convenzione é:

Se desiderate un'opzione che accetti un numero variabile di argomenti, bisogna che abbiate scaltrezza ed ingegno, per via di diverse difficoltà che potrebbero presentarvisi. L'esatta implementazione che verrà scelta dovrà essere basata su quello che desiderate e su quanto sarete disposti a fare per la vostra applicazione (questo è il motivo per cui optparse non supporta direttamente questo tipo di operazioni).

Comunque, ecco un tentativo di una opzione con argomenti variabili su di una funzione di callback:

def varargs(option, opt, value, parser):
    assert value is None
    done = 0
    value = []
    rargs = parser.rargs
    while rargs:
        arg = rargs[0]

        #  Stop se viene intercettato un argomento come "--foo", "-a",
	#+ "-fx", "--file=f", etc. 
	#  Notate che che lo stop avviene anche su "-3" o "-3.0",
	#+ così se la vostra opzione accetta valori numerici, dovrete
        #+ gestirli in questo modo. 

        if ((arg[:2] == "--" and len(arg) > 2) or
            (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
            break
        else:
            value.append(arg)
            del rargs[0]

     setattr(parser.values, option.dest, value)

...
parser.add_option("-c", "--callback",
                  action="callback", callback=varargs)

La principale debolezza di questa particolare implementazione, è che i numeri negativi negli argomenti che seguono -c verranno interpretati come opzioni successive, piuttosto che come argomenti di -c. La risoluzione di questo problema viene lasciata per esercizio al lettore.

Vedete Circa questo documento... per informazioni su modifiche e suggerimenti.