18: PARAMETRI CON VALORI DI DEFAULT

ARGOMENTI OPZIONALI

Abbiamo visto che alcune funzioni possono essere chiamate con un numero variabile di argomenti. In Python ci sono più modi per ottenere questo comportamento: qui vedremo quello più usato, cioè i parametri con valori di default.

Riprendete il programma "saluti.py" (qui) e modificatelo così:


def saluta(nome="Peppe"):
    print ("Ciao", nome + "!")

saluta()
saluta("Ciccio")
n = input("Chi vuoi salutare? ")
saluta(n)

Nella definizione di saluta() dopo il parametro nome abbiamo aggiunto ="Peppe". Questo vuol dire che quel parametro ha un valore di default: se l'utente chiama la funzione senza argomenti, Python sostituisce automaticamente "Peppe" al posto del parametro nome, se invece l'utente specifica un argomento, la sostituzione avviene normalmente.

Nella definizione di una funzione possiamo avere sia parametri con valore di default (opzionali) sia parametri ordinari (obbligatori). Gli argomenti opzionali devono sempre seguire quelli obbligatori nella lista dei parametri.

Vediamo qualche esempio:


def funz1(a, b, c=0, d=1):    # OK, 2 paranetri ordinari e 2 di default
    ...

def funz2(a=1, b=2, c=3):     # OK, 3 parametri di default
    ...
	
def funz3(a=1, b):            # Errore: il parametro di default precede quello ordinario
    ...

Avrete notato che non ho lasciato spazi prima e dopo il segno di = nella definizione dei valori di default: anche questo non è obbligatorio (si possono lasciare quanti spazi si vuole sia prima che dopo), ma è diventata un'abitudine comune, probabilmente per distinguere i valori di default dalle assegnazioni; conviene quindi adottare questa convenzione. Vediamo un altro esempio:

NUOVO PROGRAMMA: prova_default.py

def compra(cosa, prezzo, quantita=1):
    print("Mi serve", quantita, "etto di", cosa)
    print("Ecco qui")
    print("Quanto costa?")
    print(prezzo * quantita, "euro")

compra("Prosciutto", 1.5, 2)   # compra 2 etti di prosciutto a 1.5 euro l'uno
compra("Salame", 1.0)          # compra 1 etto (default) di salame a 1.0 euro
compra("Carne")                # ERRORE! un solo argomento (ne servono almeno 2)

nella prima chiamata abbiamo scritto tutti e tre i parametri della funzione, nella seconda abiamo omesso il parametro opzionale quantita (e Python ha sostituito 1 al posto di esso) mentre nel terzo abbiamo causato un errore omettendo due parametri (uno solo è opzionale).

ESERCIZIO 18.1 Modificate l'ultima riga in modo che non causi errore e compri 2 etti di carne che costano 3.5 euro l'uno; aggiungete poi un'altra chiamata che compri 1 etto di formaggio che costa 1.2 euro all'etto.

KEYWORD ARGUMENTS

Non c'è limite al numero di argomenti (obbligatori od opzionali) che una funzione può avere. Quando però ci sono molti parametri di default le cose si complicano: tenete sempre presente che Python effettua le sostituzioni secondo l'ordine dei parametri nella definizione.

NUOVO PROGRAMMA: analisi_logica.py

Copiate questo codice ed eseguitelo:


def analisi_logica(sogg, verbo, compl_ogg="", compl_luogo="", compl_tempo=""):
    print(sogg, verbo, compl_ogg, compl_luogo, compl_tempo)
    print("SOGGETTO:  ", sogg)
    print("PREDICATO: ", verbo)
    if len(compl_ogg) > 0:
        print("COMPLEMENTO OGGETTO:", compl_ogg)
    if len(compl_luogo) > 0:
        print("COMPLEMENTO DI LUOGO:", compl_luogo)
    if len(compl_tempo) > 0:
        print("COMPLEMENTO DI TEMPO:", compl_tempo)

analisi_logica("Io", "mangio")
analisi_logica("Gigi", "mangia", "un panino")
analisi_logica("Peppe", "sta mangiando", "la pastasciutta", "a tavola")

Dopo aver ben compreso cosa fa la funzione analisi_logica() chiedetevi: cosa succederebbe se io volessi fare l'analisi logica di "Io mangio a mezzogiorno"? Dovrei passare alla funzione i parametri sogg, verbo, compl_tempo (cioè i primi due, obbligatori, più il quinto, opzionale) ma come potrebbe capire Python quale dei tre parametri opzionali gli sto passando?

Una soluzione potrebbe essere quella di chiamare la funzione in questo modo:


analisi_logica("Io", "mangio", "", "", "a mezzogiorno")

rispettando così l'ordine degli argomenti che abbiamo stabilito nella definizione della funzione. Questo ci costringe però ad indicare nella chiamata tutti i parametri, anche quelli opzionali, vanificando la possibilità di tralasciare quelli che non ci servono.

Il problema è risolto elegantemente da Python con la possibilità di inserire il nome degli argomenti che stiamo passando anche nella chiamata della funzione. Provate ad aggiungere in coda al programma queste altre due righe:


analisi_logica("Io", "mangio", compl_tempo="a mezzogiorno")
analisi_logica("Luigi", "mangia", compl_luogo="al ristorante")

In questo modo indichiamo esplicitamente a Python che deve sostituire la stringa "a mezzogiorno" al posto del parametro formale compl_tempo indicato nella definizione della funzione e la stringa "al ristorante" al posto del parametro compl_luogo.

Quando indichiamo esplicitamente il nome di un parametro non siamo più vincolati all'ordine della definizione (e questo è senz'altro utile se i parametri sono molti e non ricordiamo più il loro ordine). Inoltre possiamo indicare con il nome anche i parametri obbligatori (che comunque non possono mai essere omessi). Python chiama i parametri senza il nome positional arguments (parametri che saranno sostituiti in base alla loro posizione) e quelli con il nome keyword arguments (parametri sostituiti in base al loro nome); L'unica restrizione è che, se usiamo keywords arguments nella chiamata, essi devono seguire i positional arguments. Provate queste altre chiamate:


analisi_logica(compl_ogg="un cornetto", sogg="Io", verbo="mangio")
analisi_logica(verbo="mangia", sogg="Luigino")
analisi_logica(compl_ogg="la pasta", "Mio cugino", "mangia")

L'ultima chiamata provoca un errore perchè un keyword argument viene prima dei positional arguments. Per finire analizziamo meglio la vecchia e cara funzione print(): solo adesso possiamo capire cosa fa veramente.


>>> help(print)

Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

Analizzando i parametri di print(), vediamo che value, ..., rappresentano la lista variabile di argomenti che deve stampare (non tratteremo qui come si fa). Più interessanti sono i parametri di default. Leggendo la descrizione in inglese apprendiamo che:

Parametro Significato
sep E'la stringa che viene inserita tra i vari valori da stampare: di default uno spazio
end E' la stringa che viene stampata dopo l'ultimo argomento, di default un \n (a capo)
file E' un oggetto di tipo file (li vedremo nella prossima lezione) sul quale vengono stampati gli argomenti: di default la console di IDLE (sys.stdout indica l'output standard del sistema)
flush Controlla la stampa nei file, non ce ne occupiamo qui

Quindi usando i parametri sep e end, possiamo cambiare notevolmente il comportamento standard di print(). Possiamo ad esempio evitare che la funzione vada a capo sostituendo il carattere "\n" del parametro end con uno spazio od una stringa vuota.

ESERCIZIO 18.2 Scrivete queste istruzioni in IDLE. Provate ad immaginare cosa viene stampato.
>>> print("Amo", "la", "mia", "mamma", sep="_____")
>>> print("Ciao mamma", end="*******\n")
>>> print("Ciao mamma", end="\n\n\n")
ESERCIZIO 18.3 Data la funzione:

def mi_presento(nome="Peppe", eta=18, citta="Roma"):
    print("Mi chiamo", nome, "ho", anni, "anni e abito a", citta)
Copiatela nel vostro programma e chiamatela tre volte con un numero di parametri differente

Fine della lezione