Introduzione a Python¶
Parte 2 · Linguaggi di programmazione · Capitolo 7 · Dispensa, volume 2 (PDF) · Esercizi: Introduzione a Python
Introduzione¶
Nel capitolo «Introduzione a C++» abbiamo tradotto lo pseudocodice dei nostri algoritmi in un linguaggio di programmazione compilato. In questo capitolo introduciamo un secondo linguaggio di programmazione, Python, che è interpretato, ha una sintassi più leggera ed è molto diffuso sia nella didattica sia nel calcolo scientifico.
Il capitolo segue lo stesso percorso del capitolo «Introduzione a C++», in modo che i due linguaggi possano essere confrontati sezione per sezione:
-
le caratteristiche principali del linguaggio e la struttura di un programma;
-
variabili, tipi di dato, ingresso e uscita;
-
operatori, istruzioni condizionali e cicli;
-
le liste, che svolgono il ruolo degli array di
C++; -
le funzioni, i loro parametri e i loro valori di ritorno;
-
un algoritmo completo, la ricerca del valore massimo in un array, scritto in pseudocodice e in
Python; -
gli operatori bit a bit e una tabella riassuntiva che confronta
PythonconC++.
Ogni frammento di codice del capitolo è stato eseguito con l'interprete python3 (Python 3.14): gli output riportati negli esempi sono quelli stampati dai programmi.
Nello pseudocodice le componenti di un array \(a[1..n]\) sono indicizzate da \(1\) a \(n\); in Python, come in C++, gli elementi di una lista di dimensione \(n\) sono indicizzati da \(0\) a \(n-1\). La componente \(a[i]\) dello pseudocodice corrisponde all'elemento a[i-1] del codice Python.
7.1 Caratteristiche principali del linguaggio di programmazione¶
Le caratteristiche principali di Python sono le seguenti.
-
Pythonè un linguaggio interpretato: i programmi sono eseguiti istruzione per istruzione dall'interpretePython, senza una fase di compilazione separata. Questo rende lo sviluppo e il debug rapidi e interattivi. -
Pythonusa la tipizzazione dinamica: le variabili non devono essere dichiarate con un tipo di dato. Il tipo di dato è determinato automaticamente, durante l'esecuzione, dal valore assegnato. -
Pythonsupporta le funzioni, che permettono un approccio strutturato e modulare alla programmazione. Le funzioni consentono di riutilizzare il codice e di organizzarlo meglio. -
L'indentazione è obbligatoria in
Python: la struttura a blocchi del codice (cicli, istruzioni condizionali, funzioni) è definita dal livello di indentazione, non dalle parentesi graffe. L'indentazione standard è di \(4\) spazi. -
In
Python, un commento su una sola riga inizia con il simbolo riservato “#”. Non esiste un simbolo dedicato ai commenti su più righe: un testo racchiuso fra tripli apici"""(oppure”') è una stringa che il programma non usa, e viene comunemente usato come commento su più righe. La stessa stringa, scritta come prima riga di una funzione, è la sua stringa di documentazione (docstring).
Esempio 7.1: commenti in Python
Questo è un esempio di commento su una sola riga:
Questo è un esempio di commento su più righe:
7.1.1 La struttura di un programma¶
Un programma Python è un file di testo (con estensione .py) che l'interprete esegue dalla prima riga all'ultima. A differenza di C++, non è richiesta una funzione main: le istruzioni scritte al livello più esterno del file sono eseguite in ordine.
Esempio 7.2: lo scheletro di un programma
Se il codice sorgente è salvato nel file hello.py, lo si esegue con il comando
e l'output è
Negli esempi seguenti, a meno che non contengano un programma completo, i frammenti di codice sono scritti al livello più esterno di un file ed eseguiti in questo modo.
- Un blocco di istruzioni (il corpo di un'istruzione condizionale, di un ciclo o di una funzione) è introdotto dal simbolo “
:” alla fine della riga precedente, e tutte le sue istruzioni sono indentate dello stesso numero di spazi. Il blocco termina alla prima istruzione indentata di meno.
Esempio 7.3: blocchi definiti dall'indentazione
x = 7
if x > 0:
print("positivo") # Dentro il blocco dell'if
print("ancora dentro") # Dentro il blocco dell'if
print("fuori dal blocco") # Eseguita in ogni caso
Output:
In C++ lo stesso blocco sarebbe racchiuso fra parentesi graffe {}; in Python un'indentazione sbagliata cambia il significato del programma o produce un IndentationError.
In Python le istruzioni non terminano con “;”, e i blocchi sono delimitati dall'indentazione (4 spazi) invece che dalle parentesi graffe.
7.2 Variabili e tipi di dato¶
Il codice sorgente opera su variabili, e ogni valore ha un tipo di dato.
-
Le informazioni sono classificate in diversi tipi di dato. I quattro tipi di dato fondamentali sono:
-
Il tipo di dato “
int” rappresenta un numero intero, cioè un numero scritto senza la virgola decimale. Comprende i numeri interi positivi e negativi, e lo zero. A differenza diC++, gli interi diPythonnon hanno un valore massimo: possono avere tutte le cifre che servono. -
Il tipo di dato “
bool” rappresenta un valore booleano:TrueoFalse(si noti l'iniziale maiuscola). -
Il tipo di dato “
float” rappresenta un numero in virgola mobile, che comprende i numeri scritti con la virgola decimale. UnfloatdiPythonha la stessa precisione (doppia) di undoublediC++. -
Il tipo di dato “
str” rappresenta una stringa di caratteri, racchiusa fra apici singoli o doppi (ad esempio'ciao',"mondo"). Non esiste un tipo di dato separato per un singolo carattere: un carattere è una stringa di lunghezza \(1\).
-
-
Una variabile funziona come un contenitore che memorizza un valore. Ogni variabile ha un nome univoco.
-
Alle variabili si assegnano valori con l'operatore di assegnamento “
=”. Quando si assegna un nuovo valore, il valore precedente viene sovrascritto. -
Non serve alcuna dichiarazione prima dell'uso: una variabile viene creata nel momento in cui le si assegna un valore. La funzione
type()restituisce il tipo di dato di un valore.
Le variabili sono create tramite assegnamento; non c'è una fase di dichiarazione separata, e il tipo di dato non è scritto nel codice.
Esempio 7.4: assegnamenti di variabili
age = 25 # Variabile intera
is_raining = False # Variabile booleana
small_number = 3.14 # Variabile in virgola mobile
large_number = 123456.789 # Variabile in virgola mobile
character = 'a' # Variabile stringa (un solo carattere)
name = "Alice" # Variabile stringa
age = 26 # Il valore precedente 25 viene sovrascritto
print(age, is_raining, small_number, large_number, character, name)
print(type(age), type(is_raining), type(small_number), type(name))
Output:
Si confronti con l'Esempio 7.6 più avanti e con l'esempio corrispondente del capitolo «Introduzione a C++»: il valore booleano è visualizzato come False, e il numero 123456.789 è visualizzato con tutte le sue cifre.
Esempio 7.5: tipizzazione dinamica e interi grandi
x = 5
print(x, type(x))
x = "cinque" # Lo stesso nome ora si riferisce a una stringa
print(x, type(x))
print(2 ** 100) # Un intero con 31 cifre
Output:
L'operatore ** è l'elevamento a potenza (Sezione 7.4.1). In C++ il valore \(2^{100}\) non entra in una variabile di tipo int.
7.3 Ingresso e uscita¶
-
La funzione
print()visualizza un output sullo schermo. Più valori possono essere stampati in una sola chiamata separandoli con virgole: sono visualizzati separati da uno spazio, e la riga termina con un a capo (lo stesso effetto diendlinC++). -
I parametri opzionali
sepeendcambiano il separatore fra i valori e il testo scritto alla fine:print(x, end=" ")scrive uno spazio invece dell'a capo, così laprintsuccessiva continua sulla stessa riga. -
Le stringhe e i valori delle variabili possono essere combinati usando le f-string (stringhe formattate), precedute dalla lettera
f. Dentro le f-string i nomi delle variabili (e, più in generale, le espressioni) si scrivono fra parentesi graffe{}. -
Dentro le parentesi graffe di una f-string, il formato
:.kfvisualizza un numero in virgola mobile con esattamente \(k\) cifre dopo la virgola decimale (lo stesso effetto difixedesetprecision(k)inC++).
Esempio 7.6: stampe sullo schermo
n = 42
print("Il valore della variabile è", n)
print(f"Il valore della variabile è {n}") # Versione con f-string
print(f"n = {n}, doppio = {n * 2}") # Espressione dentro {}
print("a", "b", "c", sep="-") # Separatore "-" invece dello spazio
print("Niente a capo", end=" ") # Uno spazio invece dell'a capo
print("dopo end")
print(f"{10 / 3:.2f}") # Due cifre dopo la virgola decimale
Output:
- La funzione
input()visualizza un messaggio, attende che l'utente scriva una riga di testo e la restituisce. Restituisce sempre unastr; per ottenere un numero, il risultato deve essere convertito conint()ofloat().
Esempio 7.7: ingresso da tastiera
name = input("Inserisci il tuo nome: ") # Legge una stringa
n = int(input("Inserisci un intero: ")) # Legge e converte in int
x = float(input("Inserisci un numero reale: ")) # Legge e converte in float
print(f"Ciao {name}, n = {n}, x = {x}")
Esempio di esecuzione (l'utente scrive Ada, 7 e 2.5):
7.4 Operatori¶
Gli operatori sono simboli che eseguono operazioni su variabili e valori. Come in C++, sono classificati, secondo la loro funzione, in operatori aritmetici, di assegnamento, relazionali e logici; Python non ha operatori di incremento e decremento.
7.4.1 Operatori aritmetici¶
Operatori aritmetici, usati per eseguire le operazioni matematiche di base:
-
+(Addizione) \(\rightsquigarrow\) Somma due valori. -
-(Sottrazione) \(\rightsquigarrow\) Sottrae un valore da un altro. -
*(Moltiplicazione) \(\rightsquigarrow\) Moltiplica due valori. -
/(Divisione) \(\rightsquigarrow\) Divide un valore per un altro (restituisce sempre unfloat). -
//(Divisione intera) \(\rightsquigarrow\) Restituisce il quoziente intero (divisione con arrotondamento per difetto). -
%(Resto) \(\rightsquigarrow\) Restituisce il resto di una divisione. -
**(Elevamento a potenza) \(\rightsquigarrow\) Eleva un valore a una potenza.
Esempio 7.8: operatori aritmetici
a = 10
b = 3
print("Addizione:", a + b)
print("Sottrazione:", a - b)
print("Moltiplicazione:", a * b)
print("Divisione:", a / b) # Sempre un float
print("Divisione intera:", a // b)
print("Resto:", a % b)
print("Elevamento a potenza:", a ** b)
Output:
Addizione: 13
Sottrazione: 7
Moltiplicazione: 30
Divisione: 3.3333333333333335
Divisione intera: 3
Resto: 1
Elevamento a potenza: 1000
L'ultima cifra 5 della divisione non è un errore del programma: \(10/3\) ha infinite cifre decimali, e viene visualizzato il float più vicino.
-
L'operatore di divisione
/restituisce sempre unfloatinPython 3, anche quando divide due interi. Per ottenere un risultato intero si usa l'operatore di divisione intera//. È la convenzione opposta rispetto aC++, dove10 / 3è la divisione intera. -
L'operatore
//calcola \(\lfloor a/b \rfloor\), arrotondando per difetto. Per operandi non negativi coincide con la divisione intera diC++; per un quoziente negativo non coincide, perchéC++tronca verso lo zero: inPython-7 // 2vale-4e-7 % 2vale1, mentre inC++-7 / 2vale-3e-7 % 2vale-1. In entrambi i linguaggi vale l'identità \(a = b \cdot q + r\) fra quoziente \(q\) e resto \(r\). -
Un valore è convertito in un altro tipo di dato (conversione di tipo) con le funzioni
int(),float()estr():int(3.9)vale3(la parte decimale è eliminata),float(7)vale7.0,int("12")è l'intero12.
Esempio 7.9: divisione intera e in virgola mobile
a = 10
b = 3
print(a / b) # Divisione in virgola mobile
print(a // b) # Divisione intera
print(f"{a / b:.2f}") # Due cifre decimali
print(-7 // 2, -7 % 2) # Divisione per difetto con quoziente negativo
print(int(-7 / 2)) # Troncamento verso zero, come in C++
print(int(3.9), float(7), int("12") + 1)
Output:
7.4.2 Operatori di assegnamento¶
Operatori di assegnamento, usati per assegnare valori alle variabili:
-
=(Assegnamento) \(\rightsquigarrow\) Assegna un valore a una variabile. -
+=(Assegnamento con addizione) \(\rightsquigarrow\) Somma un valore e assegna il risultato. -
-=(Assegnamento con sottrazione) \(\rightsquigarrow\) Sottrae un valore e assegna il risultato. -
*=(Assegnamento con moltiplicazione) \(\rightsquigarrow\) Moltiplica e assegna il risultato. -
/=(Assegnamento con divisione) \(\rightsquigarrow\) Divide e assegna il risultato (unfloat). -
//=(Assegnamento con divisione intera) \(\rightsquigarrow\) Divide per difetto e assegna il risultato. -
%=(Assegnamento con resto) \(\rightsquigarrow\) Calcola il resto e assegna il risultato. -
**=(Assegnamento con elevamento a potenza) \(\rightsquigarrow\) Eleva a una potenza e assegna il risultato.
Esempio 7.10: operatori di assegnamento
x = 10 # Assegnamento
print("Valore iniziale:", x)
x += 5 # Equivalente a: x = x + 5
print("Dopo += 5:", x)
x -= 3 # Equivalente a: x = x - 3
print("Dopo -= 3:", x)
x *= 2 # Equivalente a: x = x * 2
print("Dopo *= 2:", x)
x //= 4 # Equivalente a: x = x // 4
print("Dopo //= 4:", x)
x %= 4 # Equivalente a: x = x % 4
print("Dopo %= 4:", x)
x **= 3 # Equivalente a: x = x ** 3
print("Dopo **= 3:", x)
x /= 4 # Equivalente a: x = x / 4 (il risultato è un float)
print("Dopo /= 4:", x)
Output:
7.4.3 Incremento e decremento¶
-
Pythonnon ha gli operatori++e- -: una variabile si incrementa conx += 1e si decrementa conx -= 1. -
L'istruzione
x++è un errore di sintassi. L'espressione++xè accettata, ma non incrementax: applica due volte il più unario, quindi il suo valore èxstesso.
Esempio 7.11: incremento e decremento
x = 5
x += 1 # Incremento
print("Dopo x += 1:", x)
x -= 1 # Decremento
print("Dopo x -= 1:", x)
print("++x vale", ++x, "e x vale ancora", x) # ++x non è un incremento
Output:
7.4.4 Operatori relazionali¶
Operatori relazionali, usati per confrontare valori e restituire un risultato booleano:
-
==(Uguale a) \(\rightsquigarrow\) Verifica se due valori sono uguali. -
!=(Diverso da) \(\rightsquigarrow\) Verifica se due valori sono diversi. -
<(Minore di) \(\rightsquigarrow\) Verifica se un valore è minore di un altro. -
>(Maggiore di) \(\rightsquigarrow\) Verifica se un valore è maggiore di un altro. -
<=(Minore o uguale a) \(\rightsquigarrow\) Verifica se un valore è minore o uguale a un altro. -
>=(Maggiore o uguale a) \(\rightsquigarrow\) Verifica se un valore è maggiore o uguale a un altro.
-
Gli operatori relazionali restituiscono un risultato booleano:
Truese la condizione è soddisfatta,Falsealtrimenti (visualizzati comeTrueeFalse, non come1e0come inC++). Questi operatori sono usati comunemente nelle istruzioni condizionali e nei cicli. -
I confronti possono essere concatenati:
0 < x <= 10significa0 < x and x <= 10.
Esempio 7.12: operatori relazionali
a = 10
b = 5
print("a == b:", a == b) # Uguale a
print("a != b:", a != b) # Diverso da
print("a < b:", a < b) # Minore di
print("a > b:", a > b) # Maggiore di
print("a <= b:", a <= b) # Minore o uguale a
print("a >= b:", a >= b) # Maggiore o uguale a
print("0 < b <= a:", 0 < b <= a) # Confronto concatenato
Output:
7.4.5 Operatori logici¶
Operatori logici, usati per le operazioni logiche, spesso nelle istruzioni condizionali:
-
and(AND logico) \(\rightsquigarrow\) RestituisceTruese entrambe le condizioni sonoTrue. -
or(OR logico) \(\rightsquigarrow\) RestituisceTruese almeno una condizione èTrue. -
not(NOT logico) \(\rightsquigarrow\) Inverte il valore booleano.
- Gli operatori logici di
Pythonsono parole, mentre inC++sono i simboli&&,||e!.
Esempio 7.13: operatori logici
condition1 = True
condition2 = False
print("condition1:", condition1)
print("condition2:", condition2)
# AND logico: True solo se entrambe le condizioni sono True
print("condition1 and condition2:", condition1 and condition2)
# OR logico: True se almeno una condizione è True
print("condition1 or condition2:", condition1 or condition2)
# NOT logico: inverte il valore booleano
print("not condition1:", not condition1)
print("not condition2:", not condition2)
Output:
7.5 Istruzioni condizionali¶
Gli operatori relazionali e logici producono le condizioni che decidono quali istruzioni vengono eseguite.
-
Le istruzioni condizionali permettono di eseguire blocchi di codice diversi in base a condizioni specifiche.
-
L'istruzione
ifvaluta una condizione. Se la condizione èTrue, il blocco indentato viene eseguito. -
La clausola opzionale
elif(else if) verifica una condizione aggiuntiva quando le precedenti sonoFalse. -
La clausola opzionale
elseviene eseguita quando tutte le condizioni precedenti sonoFalse. -
Non servono parentesi attorno alla condizione, e non si usano parentesi graffe: la riga della condizione termina con “
:” e il blocco è delimitato dall'indentazione.
Esempio 7.14: istruzione condizionale
number = 10
# Verifica se il numero è positivo
if number > 0:
print("Il numero è positivo.")
else:
print("Il numero non è positivo.")
Output:
Esempio 7.15: if / elif / else
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else:
grade = "F"
print(f"Punteggio: {score}, Voto: {grade}")
Output:
Le condizioni sono valutate dall'alto verso il basso, e viene eseguito solo il blocco della prima condizione vera: score >= 90 è falsa e score >= 80 è vera, quindi il voto è "B". Il risultato è lo stesso degli operatori ternari annidati del capitolo «Introduzione a C++».
7.5.1 Espressione condizionale¶
-
L'espressione condizionale è la versione
Pythondell'operatore ternario?:diC++: offre un modo compatto per scrivere semplici istruzioniif-else. -
Sintassi:
valore_se_vero if condizione else valore_se_falso -
Se la condizione è
True, l'espressione valevalore_se_vero; altrimenti valevalore_se_falso.
Esempio 7.16: espressione condizionale
number = 10
# Espressione condizionale compatta
result = "positivo" if number > 0 else "non positivo"
print(f"Il numero è {result}")
# Ricerca del massimo fra due numeri
a, b = 15, 20 # Assegnamento multiplo: a = 15 e b = 20
maximum = a if a > b else b
print(f"Massimo: {maximum}")
# Verifica se pari o dispari
n = 7
parity = "pari" if n % 2 == 0 else "dispari"
print(f"{n} è {parity}")
# Valore assoluto
x = -5
abs_value = x if x >= 0 else -x
print(f"Il valore assoluto di {x} è {abs_value}")
Output:
La libreria di Python fornisce anche le funzioni max(a, b) e abs(x), che restituiscono gli stessi valori.
7.6 Cicli¶
Le istruzioni condizionali scelgono se un blocco di codice viene eseguito; i cicli decidono quante volte viene eseguito.
- I cicli servono a eseguire ripetutamente un blocco di codice. In
Pythoni due costrutti di ciclo sono il ciclowhilee il ciclofor.
7.6.1 Il ciclo while¶
- Il ciclo
whileesegue un blocco di codice finché la condizione valeTrue. Se la condizione èFalsefin dall'inizio, il blocco non viene mai eseguito.
Esempio 7.17: ciclo while
i = 1 # Inizializzazione
while i <= 5: # Condizione
print(f"Numero: {i}")
i += 1 # Incremento (in Python non esiste l'operatore ++)
Output:
Come in C++, la condizione i <= 5 è valutata sei volte: cinque volte è vera, e la sesta volta (i uguale a 6) è falsa e il ciclo termina.
7.6.2 Il ciclo for¶
-
Il ciclo
fordiPythonscorre gli elementi di un iterabile, come una lista, una stringa o un intervallo di interi: a ogni iterazione la variabile del ciclo assume l'elemento successivo. -
La funzione
range(start, stop, step)genera la sequenza di interi dastart(incluso) astop(escluso), con incrementostep. Se è dato un solo argomento, la sequenza parte da \(0\); sestepè omesso, vale \(1\); con unstepnegativo la sequenza decresce. -
Il ciclo dello pseudocodice “for \(i := 1\) to \(n\)” corrisponde a
for i in range(1, n + 1), e il ciclo sugli indici di una lista di dimensione \(n\) èfor i in range(n), con \(i = 0, 1, \dots, n-1\).
Esempio 7.18: ciclo for con range
L'output è lo stesso del ciclo while dell'Esempio 7.17. La funzione list() mostra gli interi generati da un range:
print(list(range(5)))
print(list(range(1, 6)))
print(list(range(0, 10, 3)))
print(list(range(5, 0, -1)))
Output:
Esempio 7.19: ciclo for su una lista
Output:
Il ciclo visita direttamente gli elementi, senza usare i loro indici.
7.6.3 Le istruzioni break e continue¶
-
L'istruzione
breaktermina immediatamente il ciclo. -
L'istruzione
continuesalta il resto dell'iterazione corrente e passa alla successiva.
Esempio 7.20: break e continue
for i in range(1, 11):
if i % 2 == 0:
continue # Salta i numeri pari
if i > 7:
break # Interrompe il ciclo al primo dispari maggiore di 7
print(i, end=" ")
print()
Output:
Come nella versione C++, i valori pari di i sono saltati da continue; quando i è uguale a 9 l'istruzione break termina il ciclo, e il valore 10 non viene mai raggiunto. L'ultima print() scrive solo l'a capo.
7.7 Liste¶
I cicli diventano davvero utili quando visitano collezioni di valori. In Python una collezione di valori è memorizzata in una lista.
-
Una lista è una collezione ordinata e modificabile di elementi, che può contenere valori di qualunque tipo. Le liste sono la principale struttura dati sequenziale di
Pythone svolgono il ruolo degli array diC++. -
Le liste sono racchiuse fra parentesi quadre
[]e gli elementi sono separati da virgole. Gli elementi si raggiungono tramite il loro indice, a partire da0: gli elementi di una listaadi dimensione \(n\) sonoa[0],a[1], …,a[n-1]. La funzionelen(a)restituisce la dimensione della lista, e l'indice negativoa[-1]indica l'ultimo elemento. -
A differenza degli array di
C++, le liste sono dinamiche: possono crescere o ridursi durante l'esecuzione senza gestire manualmente la memoria. L'istruzionea.append(x)aggiunge l'elementoxin fondo alla lista. -
L'espressione
[0] * ncrea una lista di \(n\) zeri. Più in generale, una list comprehension[espressione for i in range(n)]crea la lista degli \(n\) valori dell'espressione per \(i = 0, 1, \dots, n-1\); quando la variabile del ciclo non è usata, per convenzione si chiama_.
Le liste si creano con [] e si indicizzano a partire da 0. Non servono né l'allocazione né la deallocazione della memoria.
Esempio 7.21: creazione e accesso a una lista
n = 5
# Crea una lista di n zeri
a = [0] * n
# Assegna i valori
for i in range(n):
a[i] = i * 2
print(a) # L'intera lista
print(a[0]) # Primo elemento
print(a[4]) # Ultimo elemento, indice n-1
print(len(a)) # Numero di elementi
Output:
Esempio 7.22: lista scritta per esteso, modifica e crescita
b = [9, 12, 3, 16] # Lista di 4 interi
b[2] = 5 # Assegna un nuovo valore al terzo elemento
b.append(20) # La lista cresce: ora ha 5 elementi
print(b, len(b))
print(b[-1]) # L'ultimo elemento
squares = [i * i for i in range(6)] # List comprehension
print(squares)
Output:
Accedere a un indice che non esiste, per esempio b[5], ferma il programma con l'errore IndexError: list index out of range (in C++ lo stesso accesso non è controllato).
Esempio 7.23: lista scritta per esteso e iterazione sugli indici
Output:
7.7.1 Liste bidimensionali¶
-
I dati bidimensionali possono essere rappresentati con una lista di liste. Ogni riga è a sua volta una lista, e gli elementi si raggiungono con due indici
matrix[i][j], entrambi a partire da \(0\): per esempio, sec = [[3, 1, 4], [1, 5, 9]], allorac[1][2]è l'elemento nella seconda riga e terza colonna, uguale a \(9\). -
Una matrice di \(m\) righe e \(n\) colonne riempita di zeri si crea con la list comprehension
[[0] * n for _ in range(m)], che costruisce \(m\) righe distinte.
Esempio 7.24: lista bidimensionale (matrice)
m = 3 # Numero di righe
n = 2 # Numero di colonne
# Crea una matrice di zeri
matrix = [[0] * n for _ in range(m)]
# Assegna i valori
for i in range(m):
for j in range(n):
matrix[i][j] = i * j
# Stampa la matrice
for i in range(m):
for j in range(n):
print(f"matrix[{i}][{j}] = {matrix[i][j]}")
print(matrix)
Output:
- L'espressione più breve
[[0] * n] * mè sbagliata: ripete \(m\) volte la stessa riga, quindi una modifica a una riga compare in tutte le righe.
Esempio 7.25: un errore frequente con le liste bidimensionali
wrong = [[0] * 2] * 3 # Tre riferimenti alla stessa riga
wrong[0][0] = 1
print(wrong)
right = [[0] * 2 for _ in range(3)] # Tre righe distinte
right[0][0] = 1
print(right)
Output:
7.8 Funzioni¶
Come nello pseudocodice, un algoritmo è scritto come una funzione che riceve l'input e restituisce l'output.
-
Le funzioni permettono di scrivere codice modulare e riutilizzabile, raggruppando le istruzioni in una sola unità. Una funzione si definisce con la parola chiave
def, seguita dal nome della funzione e dall'elenco dei parametri fra parentesi, e termina con il simbolo “:”. -
Una funzione in
Pythonè composta da:-
la parola chiave
defseguita dal nome della funzione; -
un elenco di parametri (opzionale): specifica i valori in ingresso, senza i loro tipi di dato;
-
un corpo indentato: il blocco di codice eseguito quando la funzione viene chiamata;
-
un'istruzione
return(opzionale): restituisce un valore a chi chiama la funzione. Una funzione senzareturnrestituisce il valore specialeNone.
-
-
Una funzione deve essere definita prima che venga eseguita l'istruzione che la chiama: per questo motivo le funzioni sono scritte all'inizio del file.
-
Le istruzioni principali di un programma
Pythonsono tipicamente poste al livello più esterno del file, oppure dentro un blocco protetto daif __name__ == "__main__":, che garantisce che il codice venga eseguito solo quando il file è eseguito direttamente (e non quando è importato come modulo da un altro file). Questo blocco svolge il ruolo della funzionemaindiC++. -
Il codice sorgente
Pythonpuò anche essere eseguito online, per esempio al seguente indirizzo:
www.mycompiler.io/online-python-compiler
Esempio 7.26: funzioni
# Definizione di funzione
def addition(a, b):
return a + b # Restituisce la somma
# Definizione di funzione
def multiplication(a, b):
return a * b # Restituisce il prodotto
if __name__ == "__main__":
total = addition(5, 10) # Chiamata di funzione
print(f"Somma: {total}")
product = multiplication(5, 10) # Chiamata di funzione
print(f"Prodotto: {product}")
Output:
Esempio 7.27: funzione che opera su una lista bidimensionale
def sum_matrix(matrix, rows, columns):
"""Restituisce la somma di tutti gli elementi di una lista 2D."""
total = 0
for i in range(rows):
for j in range(columns):
total += matrix[i][j]
return total
if __name__ == "__main__":
m, n = 3, 2
# Costruisce la matrice con una list comprehension annidata
matrix = [[i * j for j in range(n)] for i in range(m)]
result = sum_matrix(matrix, m, n)
print(f"Somma degli elementi della matrice: {result}")
Output:
La matrice è [[0, 0], [0, 1], [0, 2]], come nell'Esempio 7.24, e la somma dei suoi elementi è \(0+0+0+1+0+2 = 3\).
7.8.1 Parametri e valori di ritorno¶
In C++ i parametri sono passati per valore o per riferimento. In Python ogni parametro riceve lo stesso oggetto che è l'argomento di chi chiama, e l'effetto di una funzione su chi la chiama dipende da ciò che la funzione fa con esso.
-
Se la funzione assegna un nuovo valore a un parametro (per esempio
x = x + 1), cambia solo il nome locale: la variabile di chi chiama non è toccata. Per i numeri, il comportamento è lo stesso dei parametri passati per valore inC++. -
Se la funzione modifica gli elementi di una lista ricevuta come parametro (per esempio
a[i] = 0), la modifica è visibile a chi chiama, come per gli array passati a una funzione inC++. -
Una funzione può restituire più valori contemporaneamente, separati da virgole: sono restituiti come una tupla, e chi chiama li assegna a più variabili con un assegnamento multiplo. In
C++lo stesso risultato richiede parametri passati per riferimento.
Esempio 7.28: parametri e valori di ritorno multipli
def increment(x):
x = x + 1 # Cambia solo il nome locale x
def fill_with_zeros(a):
for i in range(len(a)):
a[i] = 0 # Modifica la lista di chi chiama
def divide(n, m):
return n // m, n % m # Restituisce due valori (una tupla)
if __name__ == "__main__":
k = 5
increment(k)
print("Dopo increment:", k)
b = [4, 7, 1]
fill_with_zeros(b)
print("Lista:", b)
q, r = divide(17, 5)
print("Quoziente e resto:", q, r)
print("Tupla:", divide(17, 5))
Output:
7.9 Un algoritmo completo: il valore massimo in un array¶
Mettiamo ora insieme tutti i pezzi: una funzione, un ciclo, un'istruzione condizionale e una lista.
Consideriamo il problema di trovare il valore massimo in un array \(a\) di \(n \ge 1\) numeri interi.
- Questo è lo pseudocodice dell'algoritmo
FindMaximumdel capitolo «Pseudocodice»: le componenti sono indicizzate da \(1\) a \(n\).
Algoritmo: FindMaximum
-
Questa è l'implementazione in
Python. Gli elementi sono indicizzati da \(0\) a \(n-1\), quindi l'inizializzazione usaa[0]e il ciclofor i in range(1, len(a))visita gli indici \(1, \dots, n-1\). La dimensione \(n\) non è passata come parametro, perché la funzione la ottiene conlen(a). La variabile si chiamamax_vale nonmax, per non nascondere la funzione predefinitamax(). La funzione suppone \(n \ge 1\), come lo pseudocodice: per una lista vuota l'accesso ada[0]ferma il programma con unIndexError.def array_max_value(a): """Restituisce il valore massimo della lista a (len(a) >= 1).""" max_val = a[0] # Inizializza con il primo elemento for i in range(1, len(a)): if a[i] > max_val: max_val = a[i] # Aggiorna il massimo return max_val if __name__ == "__main__": a = [9, 12, 3, 16, 19, 11, 12] max_val = array_max_value(a) print(f"Valore massimo: {max_val}")Output:
-
L'istanza di prova può anche essere generata a caso con il modulo
randomdella libreria diPython:random.randint(1, 100)restituisce un intero casuale fra \(1\) e \(100\) (entrambi inclusi). L'istruzionerandom.seed(2026)fissa il punto di partenza del generatore casuale, in modo che ogni esecuzione produca la stessa lista; senza di essa, ogni esecuzione produce una lista diversa.
Esempio 7.29: un'istanza casuale
import random
def array_max_value(a):
max_val = a[0]
for i in range(1, len(a)):
if a[i] > max_val:
max_val = a[i]
return max_val
if __name__ == "__main__":
random.seed(2026) # Stessa lista casuale a ogni esecuzione
n = 10 # Dimensione della lista
a = [random.randint(1, 100) for _ in range(n)]
print(a)
print(f"Valore massimo: {array_max_value(a)}")
Output:
Esempio 7.30: esecuzione passo per passo
In ogni tabella, la colonna \(i\) è l'indice del ciclo Python e la colonna \(i+1\) è l'indice corrispondente dello pseudocodice. La prima riga è l'inizializzazione max_val = a[0].
Istanza 1: \(a = [9, 12, 3, 16, 19, 11, 12]\), \(n=7\)
\(i\) (Python) |
\(i+1\) (pseudocodice) | a[i] |
a[i] > max_val? |
max_val |
|---|---|---|---|---|
| – | – | – | – | \(9\) |
| \(1\) | \(2\) | \(12\) | Sì | \(12\) |
| \(2\) | \(3\) | \(3\) | No | \(12\) |
| \(3\) | \(4\) | \(16\) | Sì | \(16\) |
| \(4\) | \(5\) | \(19\) | Sì | \(19\) |
| \(5\) | \(6\) | \(11\) | No | \(19\) |
| \(6\) | \(7\) | \(12\) | No | \(19\) |
Restituisce: max_val \(= 19\)
Istanza 2: \(a = [3, 7, 2, 9, 1]\), \(n=5\)
\(i\) (Python) |
\(i+1\) (pseudocodice) | a[i] |
a[i] > max_val? |
max_val |
|---|---|---|---|---|
| – | – | – | – | \(3\) |
| \(1\) | \(2\) | \(7\) | Sì | \(7\) |
| \(2\) | \(3\) | \(2\) | No | \(7\) |
| \(3\) | \(4\) | \(9\) | Sì | \(9\) |
| \(4\) | \(5\) | \(1\) | No | \(9\) |
Restituisce: max_val \(= 9\)
7.10 Operatori bit a bit¶
Gli operatori bit a bit del capitolo «Introduzione a C++» esistono in Python con gli stessi simboli e lo stesso significato: & (AND), | (OR), (XOR), ~ (NOT), < < (scorrimento a sinistra) e > > (scorrimento a destra). La funzione bin() restituisce la rappresentazione binaria di un intero, preceduta dal prefisso 0b.
- Poiché gli interi di
Pythonnon hanno un numero fisso di bit, il NOT bit a bit non dipende da un tipo di dato:~xè sempre uguale a \(-x-1\). Per ottenere il risultato a \(8\) bit diC++, il risultato è combinato con la maschera0xFF(il numero \(255\), la cui rappresentazione binaria è \(11111111\)).
Esempio 7.31: operatori bit a bit
a = 12 # Binario: 1100
b = 10 # Binario: 1010
print(a & b, a | b, a ^ b) # AND, OR, XOR
print(bin(a), bin(b), bin(a & b)) # Rappresentazioni binarie
print(5 << 2, 20 >> 2, 20 >> 3) # Scorrimenti
print(~a, ~a & 0xFF) # NOT, e la sua versione a 8 bit
n = 15
print("dispari" if n & 1 else "pari") # Bit meno significativo
Output:
Tutti i valori coincidono con quelli degli esempi corrispondenti del capitolo «Introduzione a C++».
7.11 Python e C++ a confronto¶
La tabella seguente riassume le principali differenze fra i due linguaggi incontrate in questo capitolo.
C++ |
Python |
|
|---|---|---|
| Esecuzione | compilato (g++), poi eseguito |
interpretato (python3) |
| Tipi di dato | dichiarati: int x = 5; |
non dichiarati: x = 5 |
| Fine dell'istruzione | ; |
fine della riga |
| Blocchi | parentesi graffe {} |
: e indentazione |
| Commenti | // e /\* \*/ |
# (e """ """) |
| Valori booleani | true, false (stampati 1, 0) |
True, False |
10 / 3 |
3 (divisione intera) |
3.3333333333333335 |
| Divisione intera | / fra due int |
// |
| Potenza | funzione pow |
operatore \*\* |
| Incremento | x++, ++x |
x += 1 |
| Operatori logici | &&, ||, ! |
and, or, not |
| Operatore ternario | c ? x : y |
x if c else y |
Ciclo for |
for (int i = 0; i < n; i++) |
for i in range(n): |
| Collezioni | array, di dimensione fissa o dinamica | liste, dinamiche |
| Dimensione di una collezione | memorizzata in una variabile separata | len(a) |
| Più risultati | parametri per riferimento | restituzione di una tupla |
| Punto di ingresso | funzione main |
livello più esterno del file |
Punti chiave del capitolo
-
Un programma
Pythonè eseguito dall'interprete (python3) dalla prima riga all'ultima; le istruzioni non terminano con “;” e i blocchi sono delimitati da “:” e dall'indentazione. -
Le variabili sono create tramite assegnamento, senza dichiarare il loro tipo di dato; gli interi non hanno un valore massimo.
-
L'operatore
/dà sempre unfloat; la divisione intera è//e arrotonda per difetto, anche per i numeri negativi. -
Le istruzioni condizionali (
if,elif,else, e l'espressione condizionale) scelgono quali istruzioni vengono eseguite; i cicli (while, eforsu unrangeo su una lista) le ripetono. -
Le liste di
Pythonsono indicizzate da \(0\) a \(n-1\), con \(n\) =len(a), mentre gli array dello pseudocodice sono indicizzati da \(1\) a \(n\); le liste crescono conappende non richiedono gestione della memoria. -
Una funzione modifica la lista di chi chiama quando ne cambia gli elementi, ma non un numero che riceve; più risultati sono restituiti insieme come una tupla.
Esercizi su questo capitolo: Introduzione a Python