Le funzioni di Python ci sono ormai familiari, ma in realtà sappiamo ancora molto poco su di esse. Infatti tutti i linguaggi di programmazione, oltre a fornire un certo numero di funzioni predefinite, permettono all'utente di creare da sè le proprie funzioni. Questo significa che è possibile scrivere delle righe di codice separate dal programma principale, dare loro un nome, ed eseguirle nel resto del programma con una chiamata del tutto uguale a quelle che già conosciamo. Per creare una tale funzione sono quindi necessari alcuni passi:
def firma():
print("\tFirmato: Il grande Peppe")
print("\tImperatore galattico")
print("\tPadrone dell'Universo")
# L'esecuzione inizia da qui!!!
print ("Tutti i professori devono mettermi 10")
firma()
print ("Tutti i compagni devono passarmi i compiti")
firma()
print ("Il bar della scuola deve farmi i cappuccini gratis")
firma()
L'istruzione def
definisce una funzione creata dal programmatore: è seguita dal nome
della funzione con le parentesi tonde e i due punti. Il blocco di istruzioni (indentate) che segue costituisce il
corpo della funzione: queste istruzioni saranno eseguite ogni volta che la funzione verrà chiamata
(dal programma principale o da un'altra funzione).
Notate che dopo la def
e le righe indentate ho lasciato una riga bianca, per sottolineare che le prime
quattro righe non fanno parte del programma principale. Proviamo ad eseguire il programma: l'output che otterremo
sarà questo:
Tutti i professori devono mettermi 10
Firmato: Il grande Peppe
Imperatore galattico
Padrone dell'Universo
Tutti i compagni devono passarmi i compiti
Firmato: Il grande Peppe
Imperatore galattico
Padrone dell'Universo
Il bar della scuola deve farmi i cappuccini gratis
Firmato: Il grande Peppe
Imperatore galattico
Padrone dell'Universo
E' importante notare che quando si lancia il programma la definizione di una funzione (cioè il blocco
dopo il def
) non viene eseguita. Python trova per prima cosa il
def
: memorizza il nome della funzione firma()
e salta tutte
le righe indentate. Il programma principale comincia dalla sesta riga: per tre volte scrive una frase
e poi chiama la funzione firma()
, e solo allora Python salta alla funzione ed esegue le righe indentate.
Le funzioni definite dall'utente costituiscono quindi dei "sottoprogrammi" che vengono
chiamati dal programma principale con l'usuale sintassi per le chiamate. Per questo si usa separare le
definizioni di funzioni dal resto del programma con una linea bianca.
Provate ad eseguire il programma passo passo con il debugger: se usate il tasto Step Into lo vedrete iniziare dalla sesta riga e "saltare" per tre volte alla funzione. Usando invece lo Step Over ad ogni chiamata il debugger eseguirà tutta la funzione in una volta sola continuando con la riga successiva.
Il principale vantaggio dell'uso delle funzioni si ha quando in un programma bisogna ripetere più volte
le stesse istruzioni. Certamente avremmo potuto evitare di definire
la funzione firma()
, scrivendo le righe direttamente nel programma principale, ma avremmo
avuto i seguenti svantaggi:
Come sappiamo le funzioni di Python possono avere degli argomenti. Questo è possibile anche per le funzioni definite nel programma:
def saluta(nome):
print ("Ciao", nome + "!") # nome + "!" non inserisce lo spazio tra il nome e "!"
# qui inizia il programma principale
saluta("Peppe")
saluta("Ciccio")
n = input("Chi vuoi salutare? ")
saluta(n)
Per usare degli argomenti nella funzione dobbiamo scrivere, nella definizione, il loro nome tra parentesi tonde, separati da virgole; nelle funzioni definite dal programmatore si usa di solito il termine parametri come sinonimo di argomenti.
Ogni volta che chiameremo la funzione dal programma principale Python controllerà che nella chiamata ci sia lo stesso numero di parametri della definizione (altrimenti si otterrà un TypeError), e copierà i parametri che abbiamo fornito nella chiamata (parametri effettivi) nei rispettivi parametri della definizione (parametri formali) secondo il loro ordine. A questo punto, nel corpo della funzione, i parametri diventeranno delle variabili in piena regola, che potremo leggere e scrivere.
Ad esempio, nel programma precedente, la prima volta che chiamiamo la funzione Python copierà la
stringa "Peppe"
nel parametro nome
, poi copierà "Ciccio"
, mentre
la terza volta copierà il contenuto della variabile n
(in Italiano si usa il termine
"passare il parametro alla funzione").
Nel corpo della funzione i parametri sono quindi delle variabili come tutte le altre, il cui valore viene però impostato nella chiamata anzichè attraverso un'assegnazione. Inoltre, come di consueto, potremo creare nella nostra funzione altre variabili, semplicemente assegnando loro un valore. Tutto questo pone un fondamentale problema, che spesso disorienta i principianti: che rapporto c'è tra le variabili nel corpo di una funzione e quelle fuori di esso? Cosa succederebbe se usassi lo stesso nome di variabile sia dentro che fuori la funzione? Questo problema è talmente importante (e complicato!) che dedicheremo ad esso tutta la prossima lezione; per il momento, provvisoriamente, possiamo risolverlo usando per le nostre variabili tutti nomi diversi.
Il prossimo esempio mostra come, nella chiamata, possiamo scrivere come parametro una costante (numero o stringa), una variabile oppure un'intera espressione, che sarà valutata e passata alla funzione (tutte cose che già eravamo abituati a fare con le funzioni predefinite di Python, ma che, lo ribadisco, possiamo fare anche con le funzioni definite da noi).
def scrividoppio(a): # a e' il parametro formale
print("Il doppio di", a, "e'", 2*a)
# qui inizia il programma principale
x = 3
scrividoppio(5) # scrive: "Il doppio di 5 e' 10
scrividoppio(x) # scrive: "Il doppio di 3 e' 6
scrividoppio(2 * x + 1) # scrive: "Il doppio di 7 e' 14
Vediamo un altro esempio con più parametri:
def compra (cosa, sn, quanto, prezzo):
print ("Avete", cosa + "?")
if sn == "n":
print ("Spiacente, non ne abbiamo")
else:
print ("Certamente! Quanto ne vuole?")
print (quanto, "etti")
print ("sono", prezzo * quanto, "euro")
compra("gorgonzola", "s", 2, 1.5)
compra("prosciutto", "s", 2, 3.5)
compra("corni di rinoceronte", "n", 1, 1)
Ricordate che la chiamata deve avere esattamente lo stesso numero di parametri della definizione, e
che i parametri saranno sostituiti in base al loro ordine (il primo diventera cosa
, il secondo sn
ecc.).
Cercate di analizzare bene la funzione (eventualmente con il debugger) e di capire a cosa serve ogni parametro. Provate a modificare
i parametri nelle chiamate osservando cosa succede.
stampa_quadrato(x)
che prenda in ingresso un parametro x
e stampi "Il quadrato di x e' yyyyy"
. Chiamatela più volte nel programma principale con numeri diversi.
def saluta(nome):
print ("Ciao", nome + "!")
saluta("Peppe")
saluta("Rosina")
Ora vogliamo modificare la funzione saluta()
in modo che risponda in questo modo:Ciao Peppe!
Sei il mio migliore amico
oppure:
Ciao Rosina!
Sei la mia migliore amica
Abbiamo bisogno di un altro parametro nella funzione che ci dica se dobbiamo salutare un maschio o una
femmina: questo parametro potrebbe essere una stringa che vale "m" o "f". Quindi le chiamate andranno
modificate così:
saluta("Peppe", "m")
saluta("Rosina", "f")
Siete capaci di modificare il corpo della funzione?Soffermiamoci infine per riassumere cosa succede esattamente quando Python incontra una funzione:
Infine vediamo come è possibile fare in modo che una funzione da noi definita restituisca un valore al programma principale.
def cubo(x):
cubo = x ** 3
return cubo
a = float(input("Scrivi un numero "))
print("Il cubo di", a, "e'", cubo(a))
L'istruzione return
, che si può scrivere solo nel corpo di una funzione, può
essere seguita o no da un'espressione.
break
può essere usata per avere diversi punti di uscita,
anche prima della fine del corpo della funzione.La seconda forma del return
rende le funzioni simili a quelle della Matematica: il programma passa
loro uno o più argomenti ed esse restituiscono un dato calcolato in base agli argomenti ricevuti. Quindi il risultato
di una funzione può essere usato in qualunque espressione (come abbiamo fatto per le funzioni predefinite di Python)
oppure assegnato ad una variabile. Modifichiamo ancora il programma così:
def cubo(x):
return x ** 3 # ancora piu' sintetico, usando un'espressione
def minimo(x, y):
if x <= y:
return x
else:
return y
a = float(input("Scrivi un numero "))
print("Il cubo di", a, "e'", cubo(a))
b = float(input("Adesso un altro numero "))
print("Il minimo tra", a, "e", b, "e'", minimo(a, b))
media
e reddito
e restituisca True
se lo studente può avere la borsa di studio e False
altrimenti. Nel programma principale copiate
la seguente lista, che contiene nell'ordine il cognome, la media ed il reddito degli studenti che hanno
fatto domanda per la borsa di studio:
studenti = [ ["Alberti", 8.5, 29500], ["Bongini", 7.9, 28000], ["Castroni", 8.6, 36500],
["De Lallis", 8.2, 27500], ["Esterini", 8.5, 31000], ["Folletti", 7.7, 27000],
["Giuliani", 9.1, 28000], ["Lulli", 8.0, 30500], ["Milanesi", 8.2, 25500], ["Nonnini", 8.6, 34000],
["Pampanato", 7.9, 26000], ["Rossi", 8.2, 31000], ["Santi", 8.1, 28000], ["Tontini", 7.8, 25000] ]
for
che scorra la lista stampando solo i nomi degli studenti che possono
ottenere la borsa di studio. SUGGERIMENTO: ogni elemento della lista è a sua volta una lista, quindi dovete
considerare che, se fate variare l'iteratore nell'insieme degli indici, dovete applicare le tecniche imparate
nell'ESERCIZIO 15.11: il cognome del primo studente sarà in
studenti[0][0]
, la sua media in studenti[0][1]
e il suo reddito in
studenti[0][2]
...Riprendiamo ora il nostro vecchio programma divisibilita.py e trasformiamolo in una funzione
def divisibilita(n):
for k in range(2, n // 2 + 1):
if n % k == 0: # se n e' divisibilr per k ...
return k # restituisce k (< n)
return n # altrimenti restituisce n ( n e' primo)
questa funzione restituisce il più piccolo divisore di n
(diverso da
1); se n
è un numero primo restituisce n
stesso. Possiamo utilizzarla per fare
qualche esercizio di aritmetica:
n
è primo se divisibilita(n) == n
)num
in fattori primi. Il procedimento è uguale
all'algoritmo con carta e penna: dato num
cerchiamo div
, il più piccolo fattore primo
di num
, dopodichè dividiamo num
per div
ed iteriamo il procedimento
fino a quando non otteniamo 1.
fattori
inizialmente vuotanum
while
, da ripetere finchè num
è maggiore di 1
div
div
alla lista fattori
num
per div
e riassegnamo il risultato a num
(qui
finisce il corpo del ciclo). ATTENZIONE: è necessario usare la divisione intera //
perchè
la divisione normale /
trasformerebbe il numero in un float
: questo è uno dei
rari casi nei quali dobbiamo fare attenzione alla distinzione tra interi e floatfattori
Fine della lezione