14  Istruzioni

In Python, un programma è composto da una sequenza di istruzioni che l’interprete esegue una dopo l’altra. Le istruzioni sono i comandi fondamentali inviati al sistema operativo per la generazione delle attività computazionali da parte dell’hardware.

Ogni istruzione rappresenta un’azione, come la creazione di una variabile, l’esecuzione di una iterazione di ciclo, la definizione di una funzione o la stampa di un messaggio sullo schermo.

Le istruzioni si distinguono in semplici e composte:

14.1 Istruzione di gestione identificatori

14.1.1 Assegnamenti

Gli assegnamenti in Python sono istruzioni semplici che collegano valori a variabili utilizzando l’operatore =. L’assegnamento in Python è una definizione e non può mai far parte di un’espressione. Per eseguire un’assegnamento come parte di un’espressione, è necessario utilizzare l’operatore := (noto come operatore “walrus”).

Esempio di assegnamento semplice:

1x = 10
2y = 20
3print(x + y)
1
Assegna il valore 10 alla variabile x.
2
Assegna il valore 20 alla variabile y.
3
Output della somma di x e y: 30.

Esempio di assegnamento con l’operatore walrus:

1if (n := 10) > 5:
2    print(n)
1
Assegna il valore 10 a n e verifica se n è maggiore di 5.
2
Output di n: 10.

14.1.2 Importazione di moduli

L’istruzione semplice import viene utilizzata per importare moduli in un programma Python, permettendo l’accesso alle funzioni, classi e variabili definite al loro interno.

Tutti gli identificatori definiti nel modulo nome_modulo si importano colla sintassi import nome_modulo e dal quel punto fino alla fine del modulo importatore, sono accessibili colla notazione data dal nome del modulo seguito dal punto e l’identificatore di interesse, cioè nome_modulo.nome_variabile dove nome_variabile è l’identificatore importato.

Una sintassi alternativa è from nome_modulo import *, per cui gli identificatori sono utilizzabili senza preporre nome_modulo..

Infine, si possono importare identificatori particolari usando from nome_modulo import seguito dall’elenco degli identificatori necessari, separati da virgole.

Esempi:

  • Importazione di tutti gli identificatori di un modulo:

    1import math
    
    2print(math.sqrt(4))
    1
    Si importa il modulo math.
    2
    Output: 2.0.
  • Importazione di identificatori particolari:

    from math import sqrt, pi
    
    1print(sqrt(4))
    
    2print(pi)
    1
    Output: 2.0.
    2
    Output: 3.141592653589793.
  • Importazione di un modulo con un alias:

    1import numpy as np
    
    array = np.array([1, 2, 3])
    
    2print(array)
    1
    numpy è una librarie non facente parte dello standard Python, importata solitamente con un identificatore abbreviato in np.
    2
    Output: [1 2 3].
  • Importazione di tutti gli identificatori di un modulo con accesso semplificato:

    from math import *
    
    1print(sqrt(4))
    
    2print(pi)
    1
    Output: 2.0.
    2
    Output: 3.141592653589793.

È importante notare che l’istruzione import carica e inizializza il modulo solo una volta per sessione del programma. Se il modulo è già stato importato in precedenza, Python utilizza la versione già caricata, riducendo così il tempo di esecuzione e il consumo di memoria.

Quando si importa un modulo, Python cerca il modulo nelle directory specificate nella variabile sys.path. Questa variabile include la directory corrente, le directory specificate nella variabile d’ambiente PYTHONPATH, e le directory di installazione predefinite.

Esempio:

import sys

1print(sys.path)
1
Elenco delle directory del computer dove Python cerca i moduli.

14.2 Istruzioni di controllo di flusso

Il flusso di controllo di un programma regola l’ordine in cui le istruzioni vengno eseguite. Il flusso di controllo di un programma Python dipende principalmente da istruzioni condizionali, cicli e chiamate a funzioni.

Anche il sollevamento e la gestione delle eccezioni influenzano il flusso di controllo (tramite le istruzioni try e with).

14.2.1 Istruzione di esecuzione condizionale

Spesso è necessario eseguire alcune istruzioni solo quando una certa condizione è vera o scegliere le istruzioni da eseguire a seconda di condizioni mutuamente esclusive. L’istruzione composta if, che comprende le clausole if, elif ed else, consente di eseguire condizionalmente blocchi di istruzioni.

La sintassi dell’istruzione if in pseudocodice è la seguente:

1if espressione:
2  istruzione(i)

3elif espressione:
4  istruzione(i)

5elif espressione:
6  istruzione(i)

7else:
8  istruzione(i)
1
Clausola if con una condizione, cioè una espressione con valore interpretato come logico.
2
Blocco di codice eseguito se la condizione if è vera.
3
Clausola elif con una condizione.
4
Blocco di codice eseguito se la condizione elif è vera.
5
Clausola elif con una condizione.
6
Blocco di codice eseguito se la condizione elif è vera.
7
Clausola else eseguita se tutte le condizioni precedenti sono false.
8
Blocco di codice eseguito dalla clausola else.

Le clausole elif ed else sono opzionali. Ecco un tipico esempio di istruzione if con tutti e tre i tipi di clausole:

1if x < 0:
2  print('x è negativo')

3elif x % 2:
4  print('x è positivo e dispari')

else:
5  print('x è pari e non negativo')
1
Controlla se x è negativo.
2
Stampa "x è negativo" se la condizione è vera.
3
Controlla se x è positivo e dispari.
4
Stampa "x è positivo e dispari" se la condizione è vera.
5
Stampa "x è pari e non negativo" se nessuna delle condizioni precedenti è vera.

Ogni clausola controlla una o più istruzioni raggruppate in un blocco di codice: si posizionano le istruzioni del blocco su righe logiche separate dopo la riga contenente la parola chiave della clausola (nota come riga intestazione della clausola), con un’indentazione tipicamente di quattro spazi oltre la riga intestazione. Il blocco termina quando l’indentazione torna al livello della riga intestazione della clausola o ulteriormente a sinistra (questo è lo stile imposto da PEP 8).

È possibile utilizzare qualsiasi espressione Python come condizione in una clausola if o elif. Utilizzare un’espressione in questo modo è noto come usarla in un contesto booleano. In questo contesto, qualsiasi valore viene considerato vero o falso. Qualsiasi numero diverso da zero o contenitore non vuoto (stringa, tupla, lista, dizionario, set, ecc.) viene valutato come vero, mentre zero (0, di qualsiasi tipo numerico), None e contenitori vuoti vengono valutati come falsi.

Per testare un valore x in un contesto booleano, utilizzare lo stile di codifica seguente:

if x:

Questa è la forma più chiara e più “Pythonica”.

Non utilizzare nessuna delle seguenti forme:

if x is True:

if x == True:

if bool(x):

C’è una differenza cruciale tra dire che un’espressione restituisce True (significa che l’espressione restituisce il valore 1 con il tipo bool) e dire che un’espressione viene valutata come vera (significa che l’espressione restituisce qualsiasi risultato che è vero in un contesto booleano). Quando si testa un’espressione, ad esempio in una clausola if, interessa solo come viene valutata, non cosa, precisamente, restituisce. Come menzionato in precedenza, “valutata come vera” è spesso espresso informalmente come “è veritiera”, e “valutata come falsa” come “è falsa”.

Quando la condizione della clausola if viene valutata come vera, le istruzioni all’interno della clausola if vengono eseguite, quindi l’intera istruzione if termina. Altrimenti, Python valuta la condizione di ciascuna clausola elif, in ordine. Le istruzioni all’interno della prima clausola elif la cui condizione viene valutata come vera, se presente, vengono eseguite e l’intera istruzione if termina. Altrimenti, quando esiste una clausola else, essa viene eseguita. In ogni caso, le istruzioni successive all’intera costruzione if, allo stesso livello, vengono eseguite successivamente.

14.2.2 Istruzione di pattern matching

L’istruzione match introduce il pattern matching strutturale nel linguaggio Python. Questa funzionalità consente di testare facilmente la struttura e il contenuto degli oggetti Python.

La struttura sintattica generale dell’istruzione match è la seguente:

1match espressione:
2  case pattern1 [if guard1]:
3    istruzione(i)

  case pattern2 [if guard2]:
4    istruzione(i)

  ...

5  case _:
6    istruzione(i)
1
La parola chiave match seguita da un’espressione il cui valore diventa il soggetto del matching.
2
Clausole case indentate che controllano l’esecuzione del blocco di codice che contengono. Possono includere un’opzione if guard per ulteriori controlli.
3
Blocco di istruzioni da eseguire se pattern1 corrisponde.
4
Blocco di istruzioni da eseguire se pattern2 corrisponde.
5
Pattern wildcard che corrisponde a qualsiasi valore.
6
Blocco di codice eseguito se nessun altro pattern corrisponde.

Durante l’esecuzione, Python prima valuta l’espressione, quindi testa il valore risultante contro il pattern in ciascuna clausola case a turno, dall’inizio alla fine, fino a quando uno corrisponde. A quel punto, il blocco di codice indentato all’interno della clausola case corrispondente viene eseguito. Un pattern può fare due cose:

  • Verificare che il soggetto sia un oggetto con una struttura particolare.

  • Associare componenti corrispondenti a nomi per un uso successivo (di solito all’interno della clausola case associata).

Quando un pattern corrisponde al soggetto, il guard consente un controllo finale prima della selezione della clausola per l’esecuzione. Tutti i binding dei nomi del pattern sono già avvenuti, e si possono usare nel guard. Quando non c’è un guard, o quando il guard viene valutato come vero, il blocco di codice indentato della clausola case viene eseguito, dopo di che l’esecuzione dell’istruzione match è completa e non vengono controllate ulteriori clausole.

L’istruzione match, di per sé, non prevede un’azione predefinita. Se ne serve una, l’ultima clausola case deve specificare un pattern wildcard, uno la cui sintassi garantisce che corrisponda a qualsiasi valore del soggetto. È un errore di sintassi seguire una clausola case con un pattern wildcard con ulteriori clausole case.

Gli elementi del pattern non possono essere creati in anticipo, associati a variabili e riutilizzati in più punti. La sintassi del pattern è valida solo immediatamente dopo la parola chiave case, quindi non c’è modo di eseguire tale assegnazione. Per ogni esecuzione di un’istruzione match, l’interprete è libero di memorizzare nella cache le espressioni del pattern che si ripetono all’interno delle clausole, ma la cache inizia vuota per ogni nuova esecuzione.

Esempio di utilizzo dell’istruzione match:

1def azione(comando, livello):
2  match comando:
3    case "start" if livello > 1:
4      print("Avvio con livello alto")

5    case "start":
6      print("Avvio con livello basso")

7    case "stop" if livello > 1:
8      print("Arresto con livello alto")

9    case "stop":
10      print("Arresto con livello basso")

11    case "pause":
12      print("Pausa")
        
13    case _:
14      print("Comando sconosciuto")

15azione("start", 2)
16azione("start", 1)
17azione("pause", 3)
18azione("exit", 0)
1
Definizione della funzione azione con due parametri: comando e livello.
2
Inizia il blocco match per il valore comando.
3
Pattern "start" con guard che verifica se livello è maggiore di 1.
4
Output se comando è "start" e livello è maggiore di 1.
5
Pattern "start" senza guard.
6
Output se comando è "start" e livello è minore o uguale a 1.
7
Pattern "stop" con guard che verifica se livello è maggiore di 1.
8
Output se comando è "stop" e livello è maggiore di 1.
9
Pattern "stop" senza guard.
10
Output se comando è "stop" e livello è minore o uguale a 1.
11
Pattern "pause".
12
Output se comando è "pause".
13
Pattern wildcard che corrisponde a qualsiasi altro valore.
14
Output se comando non corrisponde a nessun altro pattern.
15
Chiamata a azione con "start" e livello 2. Output: Avvio con livello alto.
16
Chiamata a azione con "start" e livello 1. Output: Avvio con livello basso.
17
Chiamata a azione con "pause" e livello 3. Output: Pausa.
18
Chiamata a azione con "exit" e livello 0. Output: Comando sconosciuto.

In questo esempio, la guardia if livello > 1 aggiunge una condizione extra per i casi "start" e "stop", permettendo di distinguere tra diversi livelli di comando.

14.2.2.1 Pattern letterali

I pattern letterali corrispondono a valori letterali come interi, float, stringhe, ecc. La corrispondenza viene effettuata confrontando il valore del soggetto con il valore del pattern.

Esempio:

1def controlla_valore(valore):
2  match valore:
3    case 1:
4      return "Uno"

5    case "ciao":
6      return "Saluto"

7    case True:
8      return "Vero"

9    case None:
10      return "Nessuno"

11    case _:
12      return "Altro"

13print(controlla_valore(1))
14print(controlla_valore("ciao"))
15print(controlla_valore(False))
1
Definizione della funzione controlla_valore.
2
Inizia il blocco match per il valore valore.
3
Pattern letterale 1.
4
Output se valore è 1.
5
Pattern letterale "ciao".
6
Output se valore è "ciao".
7
Pattern letterale True.
8
Output se valore è True.
9
Pattern letterale None.
10
Output se valore è None.
11
Pattern wildcard che corrisponde a qualsiasi altro valore.
12
Output se valore non corrisponde a nessun altro pattern.
13
Chiamata a controlla_valore con 1. Output: Uno.
14
Chiamata a controlla_valore con "ciao". Output: Saluto.
15
Chiamata a controlla_valore con False. Output: Altro.

14.2.2.2 Pattern di cattura

I pattern di cattura utilizzano nomi non qualificati (nomi senza punti) per catturare valori all’interno di un pattern. Questi nomi sono wildcard che corrispondono a qualsiasi valore, ma con un effetto collaterale: il nome viene associato all’oggetto corrispondente nella corrispondente espressione di pattern matching. I binding creati dai pattern di cattura rimangono disponibili dopo l’esecuzione dell’istruzione match, permettendo alle istruzioni all’interno del blocco case e al codice successivo di processare i valori catturati.

Un pattern di cattura semplice associa il nome della variabile al valore corrispondente. Se il pattern di cattura è combinato con altre forme di pattern, può catturare parti specifiche del soggetto.

Esempio di utilizzo dei pattern di cattura:

1def descrivi_valore(valore):
2  match valore:
3    case x if x < 0:
4      print(f"{x} è un numero negativo")

5    case x if x == 0:
6      print(f"{x} è zero")

7    case x if x > 0 and x % 2 == 0:
8      print(f"{x} è un numero positivo pari")

9    case x if x > 0 and x % 2 != 0:
10      print(f"{x} è un numero positivo dispari")

11    case _ if isinstance(valore, str):
12      print(f'"{valore}" è una stringa')

13    case _ if isinstance(valore, list):
14      print(f"{valore} è una lista")
        
15    case _:
16      print("Tipo di valore non riconosciuto")

# Esempi di utilizzo della funzione
17descrivi_valore(-5)
18descrivi_valore(0)
19descrivi_valore(4)
20descrivi_valore(7)
21descrivi_valore("ciao")
22descrivi_valore([1, 2, 3])
23descrivi_valore({"chiave": "valore"})
1
Definizione della funzione descrivi_valore.
2
Inizio del blocco match per il valore valore.
3
Pattern di cattura x con guard x < 0.
4
Output se valore è un numero negativo. Esempio di output: -5 è un numero negativo.
5
Pattern di cattura x con guard x == 0.
6
Output se valore è zero. Esempio di output: 0 è zero.
7
Pattern di cattura x con guard x > 0 and x % 2 == 0.
8
Output se valore è un numero positivo pari. Esempio di output: 4 è un numero positivo pari.
9
Pattern di cattura x con guard x > 0 and x % 2 != 0.
10
Output se valore è un numero positivo dispari. Esempio di output: 7 è un numero positivo dispari.
11
Pattern di guard isinstance(valore, str).
12
Output se valore è una stringa. Esempio di output: "ciao" è una stringa.
13
Pattern di guard isinstance(valore, list).
14
Output se valore è una lista. Esempio di output: [1, 2, 3] è una lista.
15
Pattern wildcard che corrisponde a qualsiasi altro valore.
16
Output se valore non corrisponde a nessun altro pattern. Esempio di output: Tipo di valore non riconosciuto.
17
Chiamata a descrivi_valore con -5. Output: -5 è un numero negativo.
18
Chiamata a descrivi_valore con 0. Output: 0 è zero.
19
Chiamata a descrivi_valore con 4. Output: 4 è un numero positivo pari.
20
Chiamata a descrivi_valore con 7. Output: 7 è un numero positivo dispari.
21
Chiamata a descrivi_valore con "ciao". Output: "ciao" è una stringa.
22
Chiamata a descrivi_valore con [1, 2, 3]. Output: [1, 2, 3] è una lista.
23
Chiamata a descrivi_valore con {"chiave": "valore"}. Output: Tipo di valore non riconosciuto.

14.2.2.3 Pattern a valore

I pattern a valore utilizzano nomi qualificati per rappresentare valori piuttosto che catturarli. In questo modo, puoi fare riferimento a valori specifici all’interno di un pattern senza rischiare di sovrascrivere variabili esistenti. I nomi qualificati possono essere attributi di una classe o attributi di istanze di classe.

Poiché i nomi semplici catturano i valori durante il pattern matching, è necessario utilizzare riferimenti agli attributi (nomi qualificati come nome.attr) per esprimere valori che possono cambiare tra le diverse esecuzioni dello stesso statement match.

Esempio di utilizzo dei pattern a valore:

class Valori:
  V1 = 42
  V2 = "ciao"
  V3 = [1, 2, 3]

obj = Valori()
1obj.V4 = 99

2def controlla_valore(valore):
3  match valore:
4    case Valori.V1:
5      print("Valore uguale a 42")

6    case Valori.V2:
7      print('Valore uguale a "ciao"')

8    case Valori.V3:
9      print("Valore uguale a [1, 2, 3]")

10    case obj.V4:
11      print("Valore uguale a 99")

12    case _:
13      print("Valore non riconosciuto")

# Esempi di utilizzo della funzione
14controlla_valore(42)
15controlla_valore("ciao")
16controlla_valore([1, 2, 3])
17controlla_valore(99)
18controlla_valore(100)
1
Assegna un nuovo attributo V4 all’istanza obj della classe Valori.
2
Definizione della funzione controlla_valore.
3
Inizia il blocco match per il valore valore.
4
Pattern a valore per Valori.V1.
5
Output se valore è uguale a 42. Esempio di output: Valore uguale a 42.
6
Pattern a valore per Valori.V2.
7
Output se valore è uguale a "ciao". Esempio di output: Valore uguale a "ciao".
8
Pattern a valore per Valori.V3.
9
Output se valore è uguale a [1, 2, 3]. Esempio di output: Valore uguale a [1, 2, 3].
10
Pattern a valore per obj.V4.
11
Output se valore è uguale a 99. Esempio di output: Valore uguale a 99.
12
Pattern wildcard che corrisponde a qualsiasi altro valore.
13
Output se valore non corrisponde a nessun altro pattern. Esempio di output: Valore non riconosciuto.
14
Chiamata a controlla_valore con 42. Output: Valore uguale a 42.
15
Chiamata a controlla_valore con "ciao". Output: Valore uguale a "ciao".
16
Chiamata a controlla_valore con [1, 2, 3]. Output: Valore uguale a [1, 2, 3].
17
Chiamata a controlla_valore con 99. Output: Valore uguale a 99.
18
Chiamata a controlla_valore con 100. Output: Valore non riconosciuto.

In questo esempio, Valori.V1, Valori.V2, e Valori.V3 sono attributi della classe Valori, mentre obj.V4 è un attributo dell’istanza obj della classe Valori.

14.2.2.4 Pattern OR

I pattern OR utilizzano l’operatore | per combinare più pattern. Il match ha successo se uno qualsiasi dei pattern combinati corrisponde al soggetto.

Esempio di utilizzo dei pattern OR:

1def descrivi_numero(numero):
2  match numero:
3    case 0 | 1:
4      print("Numero è 0 o 1")

5    case 2 | 3:
6      print("Numero è 2 o 3")

7    case _ if numero > 3:
8      print("Numero è maggiore di 3")
        
9    case _:
10      print("Numero non riconosciuto")

# Esempi di utilizzo della funzione
11descrivi_numero(0)
12descrivi_numero(2)
13descrivi_numero(5)
14descrivi_numero(-1)
1
Definizione della funzione descrivi_numero.
2
Inizia il blocco match per il valore numero.
3
Pattern OR per 0 | 1.
4
Output se numero è 0 o 1. Esempio di output: Numero è 0 o 1.
5
Pattern OR per 2 | 3.
6
Output se numero è 2 o 3. Esempio di output: Numero è 2 o 3.
7
Pattern di guard per numero > 3.
8
Output se numero è maggiore di 3. Esempio di output: Numero è maggiore di 3.
9
Pattern wildcard che corrisponde a qualsiasi altro valore.
10
Output se numero non corrisponde a nessun altro pattern. Esempio di output: Numero non riconosciuto.
11
Chiamata a descrivi_numero con 0. Output: Numero è 0 o 1.
12
Chiamata a descrivi_numero con 2. Output: Numero è 2 o 3.
13
Chiamata a descrivi_numero con 5. Output: Numero è maggiore di 3.
14
Chiamata a descrivi_numero con -1. Output: Numero non riconosciuto.

14.2.2.5 Pattern di gruppo

I pattern di gruppo utilizzano parentesi per raggruppare parti di un pattern, consentendo la combinazione di pattern complessi. Questa funzionalità è utile quando si vuole applicare operazioni di pattern matching su componenti specifici di un soggetto.

Esempio di utilizzo dei pattern di gruppo:

1def analizza_tupla(tupla):
2  match tupla:
3    case (x, (y, z)):
4      print(f"Primo elemento: {x}, Secondo elemento: ({y}, {z})")
        
5    case (x, y):
6      print(f"Primo elemento: {x}, Secondo elemento: {y}")

7    case _:
8      print("Pattern non riconosciuto")

# Esempi di utilizzo della funzione
9analizza_tupla((1, (2, 3)))
10analizza_tupla((1, 4))
11analizza_tupla((1, 2, 3))
1
Definizione della funzione analizza_tupla.
2
Inizia il blocco match per il valore tupla.
3
Pattern di gruppo (x, (y, z)).
4
Output se tupla corrisponde al pattern (x, (y, z)). Esempio di output: Primo elemento: 1, Secondo elemento: (2, 3).
5
Pattern di gruppo (x, y).
6
Output se tupla corrisponde al pattern (x, y). Esempio di output: Primo elemento: 1, Secondo elemento: 4.
7
Pattern wildcard che corrisponde a qualsiasi altro valore.
8
Output se tupla non corrisponde a nessun altro pattern. Esempio di output: Pattern non riconosciuto.
9
Chiamata a analizza_tupla con (1, (2, 3)). Output: Primo elemento: 1, Secondo elemento: (2, 3).
10
Chiamata a analizza_tupla con (1, 4). Output: Primo elemento: 1, Secondo elemento: 4.
11
Chiamata a analizza_tupla con (1, 2, 3). Output: Pattern non riconosciuto.

In questo esempio, il pattern (x, (y, z)) confronta la tupla tupla per verificare se il secondo elemento è una tupla di due elementi, mentre il pattern (x, y) confronta la tupla tupla per verificare se ha esattamente due elementi. Questo esempio mostra come utilizzare i pattern di gruppo in Python per eseguire il pattern matching su tuple.

14.2.2.6 Pattern di sequenza

I pattern di sequenza corrispondono a sequenze come liste o tuple. Ogni elemento della sequenza viene confrontato con il pattern corrispondente. È possibile utilizzare l’asterisco (*) per catturare più elementi in una sottosequenza.

Esempio:

1def verifica_sequenza(sequenza):
2  match sequenza:
3    case [1, 2, 3]:
4      return "Sequenza 1, 2, 3"

5    case [x, y, z]:
6      return f"Sequenza generica: {x}, {y}, {z}"

7    case [x, *y, z]:
8      return f"Sequenza con primo e ultimo elemento: {x}, {z}, e mediano: {y}"
        
9    case _:
10      return "Altro"

11print(verifica_sequenza([1, 2, 3]))
12print(verifica_sequenza([4, 5, 6]))
13print(verifica_sequenza([7, 8, 9, 10]))
14print(verifica_sequenza([7, 8]))
1
Definizione della funzione verifica_sequenza.
2
Inizia il blocco match per il valore sequenza.
3
Pattern di sequenza [1, 2, 3].
4
Output se sequenza è [1, 2, 3].
5
Pattern di sequenza generico [x, y, z] per una sequenza di esattamente tre elementi.
6
Output con i valori catturati.
7
Pattern di sequenza con l’uso dell’asterisco (*y) per catturare tutti gli elementi intermedi tra il primo (x) e l’ultimo (z).
8
Output con il primo, l’ultimo e gli elementi intermedi della sequenza.
9
Pattern wildcard che corrisponde a qualsiasi altro valore.
10
Output se sequenza non corrisponde a nessun altro pattern.
11
Chiamata a verifica_sequenza con [1, 2, 3]. Output: Sequenza 1, 2, 3.
12
Chiamata a verifica_sequenza con [4, 5, 6]. Output: Sequenza generica: 4, 5, 6.
13
Chiamata a verifica_sequenza con [7, 8, 9, 10]. Output: Sequenza con primo e ultimo elemento: 7, 10, e mediano: [8, 9].
14
Chiamata a verifica_sequenza con [7, 8]. Output: Altro.

In questo esempio, l’uso dell’asterisco * nel pattern [x, *y, z] permette di catturare una sottosequenza di lunghezza arbitraria tra il primo e l’ultimo elemento della sequenza. Questo rende possibile gestire sequenze di lunghezza variabile, mentre il pattern [x, y, z] corrisponde solo a sequenze di esattamente tre elementi.

14.2.2.7 Pattern as

È possibile utilizzare i pattern as per catturare i valori abbinati da pattern più complessi o componenti di un pattern, che i semplici pattern di cattura non possono gestire. Quando P1 è un pattern, allora P1 as name è anche un pattern; quando P1 ha successo, Python associa il valore abbinato al nome name nel namespace locale.

Esempio di utilizzo del pattern as:

def analizza_comando(comando):
  match comando:
    case ("start", param) as c:
1      print(f"Avvio con parametro {param}. Comando completo: {c}")

    case ("stop", param) as c:
2      print(f"Arresto con parametro {param}. Comando completo: {c}")

    case ("pause", param) as c:
3      print(f"Pausa con parametro {param}. Comando completo: {c}")
        
    case _ as c:
4      print(f"Comando sconosciuto: {c}")

# Esempi di utilizzo
5analizza_comando(("start", 5))
6analizza_comando(("stop", 10))
7analizza_comando(("pause", 15))
8analizza_comando(("exit", 20))
1
Caso in cui il comando è un avvio con un parametro.
2
Caso in cui il comando è un arresto con un parametro.
3
Caso in cui il comando è una pausa con un parametro.
4
Caso wildcard che cattura qualsiasi altro comando.
5
Chiamata a analizza_comando con ("start", 5). Output: Avvio con parametro 5. Comando completo: ('start', 5).
6
Chiamata a analizza_comando con ("stop", 10). Output: Arresto con parametro 10. Comando completo: ('stop', 10).
7
Chiamata a analizza_comando con ("pause", 15). Output: Pausa con parametro 15. Comando completo: ('pause', 15).
8
Chiamata a analizza_comando con ("exit", 20). Output: Comando sconosciuto: ('exit', 20).

14.2.2.8 Pattern di mappatura

I pattern di mappatura corrispondono alle mappature definite nel linguaggio come i dizionari. Ogni coppia chiave-valore viene confrontata con il pattern corrispondente.

Esempio:

1def verifica_mappatura(mappatura):
2  match mappatura:
3    case {"a": 1, "b": 2}:
4      return "Mappatura a=1, b=2"

5    case {"a": x, "b": y}:
6      return f"Mappatura generica: a={x}, b={y}"

7    case _:
8      return "Altro"

9print(verifica_mappatura({"a": 1, "b": 2}))
10print(verifica_mappatura({"a": 3, "b": 4}))
11print(verifica_mappatura({"c": 5}))
1
Definizione della funzione verifica_mappatura.
2
Inizia il blocco match per il valore mappatura.
3
Pattern di mappatura {"a": 1, "b": 2}.
4
Output se mappatura è {"a": 1, "b": 2}.
5
Pattern di mappatura generico {"a": x, "b": y}.
6
Output con i valori catturati.
7
Pattern wildcard che corrisponde a qualsiasi altro valore.
8
Output se mappatura non corrisponde a nessun altro pattern.
9
Chiamata a verifica_mappatura con {"a": 1, "b": 2}. Output: Mappatura a=1, b=2.
10
Chiamata a verifica_mappatura con {"a": 3, "b": 4}. Output: Mappatura generica: a=3, b=4.
11
Chiamata a verifica_mappatura con {"c": 5}. Output: Altro.

14.2.2.9 Pattern di classe

I pattern di classe permettono di verificare se un oggetto è un’istanza di una particolare classe e di accedere ai suoi attributi. Un pattern di classe ha la forma generale nome_o_attr(patterns), dove nome_o_attr è un nome semplice o qualificato legato a una classe, e patterns è una lista separata da virgole di specifiche di pattern.

Se non ci sono specifiche di pattern, il pattern di classe corrisponde a qualsiasi istanza della classe data. Se ci sono specifiche di pattern posizionali, queste devono precedere qualsiasi specifica di pattern nominata.

Le classi predefinite di Python come bool, bytearray, bytes, dict, float, frozenset, int, list, set, str e tuple sono tutte configurate per accettare un singolo pattern posizionale, che viene confrontato con il valore dell’istanza.

Esempio:

class Punto:
  def __init__(self, x, y):
    self.x = x
    self.y = y

def descrivi_punto(p):
  match p:
    case Punto(0, 0):
1      return "Punto all'origine"

    case Punto(x, 0):
2      return f"Punto sull'asse x a {x}"

    case Punto(0, y):
3      return f"Punto sull'asse y a {y}"

    case Punto(x, y) if x == y:
4      return f"Punto sulla bisettrice x=y a ({x}, {y})"

    case Punto(x, y):
5      return f"Punto a ({x}, {y})"

    case _:
6      return "Non è un punto"

# Esempi di utilizzo
p1 = Punto(0, 0)
p2 = Punto(3, 0)
p3 = Punto(0, 4)
p4 = Punto(2, 2)
p5 = Punto(1, 5)

7print(descrivi_punto(p1))
8print(descrivi_punto(p2))
9print(descrivi_punto(p3))
10print(descrivi_punto(p4))
11print(descrivi_punto(p5))
1
Pattern di classe che verifica se p è un’istanza di Punto con x e y uguali a 0.
2
Pattern di classe che verifica se p è un’istanza di Punto con y uguale a 0.
3
Pattern di classe che verifica se p è un’istanza di Punto con x uguale a 0.
4
Pattern di classe con guard che verifica se p è un’istanza di Punto con x uguale a y.
5
Pattern di classe generico che verifica se p è un’istanza di Punto e cattura i valori di x e y.
6
Pattern wildcard che corrisponde a qualsiasi altro valore.
7
Chiamata a descrivi_punto con Punto(0, 0). Output: Punto all'origine.
8
Chiamata a descrivi_punto con Punto(3, 0). Output: Punto sull'asse x a 3.
9
Chiamata a descrivi_punto con Punto(0, 4). Output: Punto sull'asse y a 4.
10
Chiamata a descrivi_punto con Punto(2, 2). Output: Punto sulla bisettrice x=y a (2, 2).
11
Chiamata a descrivi_punto con Punto(1, 5). Output: Punto a (1, 5).

In questo esempio, Punto è una classe con attributi x e y. I pattern di classe permettono di verificare se un oggetto è un’istanza di Punto e di accedere ai suoi attributi per ulteriori controlli.

14.3 Cicli

14.3.1 Istruzione while

L’istruzione composta while ripete l’esecuzione di un blocco di istruzioni fintantoché un’espressione condizionale risulta vera. La clausola else viene eseguita quando il ciclo while termina naturalmente (cioè, la condizione del ciclo diventa falsa).

Ecco la sintassi completa dello pseudocodice per l’istruzione while con la clausola else:

1while espressione:
2  istruzione(i)

3else:
4  istruzione(i)
1
L’interprete valuta l’espressione condizionale.
2
Se l’espressione condizionale è vera, esegue il blocco di istruzioni all’interno del ciclo while. Al termine del blocco, torna a valutare l’espressione condizionale.
3
Se l’espressione condizionale è falsa, esegue il blocco di istruzioni all’interno della clausola else.
4
Il blocco di istruzioni all’interno della clausola else viene eseguito solo se il ciclo while termina naturalmente (cioè, la condizione del ciclo diventa falsa).

Esempio pratico con while e else:

x = 3

1while x > 0:
2  print(x)

  x -= 1

3else:
4  print("Ciclo terminato")
1
Inizia il ciclo while finché x è maggiore di 0.
2
Stampa il valore corrente di x.
3
La clausola else viene eseguita quando il ciclo while termina naturalmente.
4
Stampa “Ciclo terminato”.

L’istruzione while può anche includere una clausola else e le istruzioni break e continue. L’istruzione break interrompe il ciclo while, al pari di return se il ciclo si trova in una funzione. L’istruzione continue salta l’iterazione corrente e passa alla successiva.

Esempio:

x = 10

1while x > 0:
  x -= 1

  if x == 5:
2    break

  if x % 2 == 0:
3    continue

4  print(x)
1
Inizia il ciclo while finché x è maggiore di 0.
2
Interrompe il ciclo quando x è uguale a 5.
3
Salta l’iterazione corrente se x è pari.
4
Stampa il valore di x se non è stato saltato.

14.3.2 Istruzione for

L’istruzione for ripete l’esecuzione di un blocco di istruzioni controllata da un’espressione iterabile. La sintassi è:

1for indice in iterabile:
2    istruzione(i)
1
indice è normalmente un identificatore che funge da variabile di controllo del ciclo e viene associato a ciascun elemento dell’iterabile.
2
istruzione(i) rappresenta una o più istruzioni che vengono eseguite per ogni elemento dell’iterabile.

Esempio tipico di for:

1for lettera in 'ciao':
2    print(f'Dammi una {lettera}...')
1
Inizia il ciclo for su ogni carattere della stringa 'ciao'.
2
Stampa "Dammi una [lettera]..." per ogni lettera della stringa.

L’istruzione for può anche includere una clausola else che viene eseguita se il ciclo termina normalmente (cioè, non viene interrotto da un’istruzione break o return).

numeri = [1, 2, 3, 4, 5]

1for numero in numeri:
2  if numero == 3:
    break
    
3  print(numero)

4else:
5    print("Ciclo completato")
1
Inizia il ciclo for sulla lista numeri.
2
Se il numero è 3, interrompe il ciclo con break.
3
Stampa il numero corrente.
4
La clausola else viene eseguita se il ciclo for termina naturalmente.
5
Stampa “Ciclo completato”.

L’iterabile può essere qualsiasi espressione iterabile in Python. In particolare, qualsiasi sequenza è iterabile. L’interprete chiama implicitamente la funzione built-in iter() sull’iterabile, producendo un iteratore.

14.3.3 Iteratori e iterabili

Un iteratore è un oggetto che permette di attraversare una collezione di elementi, uno alla volta. Gli iteratori sono utilizzati per rappresentare flussi di dati o collezioni di elementi che non sono necessariamente tutti disponibili in memoria contemporaneamente. Pertanto:

  • Un oggetto è iterabile se può restituire un iteratore. Un oggetto iterabile implementa il metodo __iter__() che deve restituire un iteratore.

  • Un oggetto è un iteratore se implementa i metodi __iter__() e __next__(). Il metodo __next__() restituisce il prossimo elemento della collezione e solleva l’eccezione StopIteration quando non ci sono più elementi.

Esempio di iteratore:

1numeri = [1, 2, 3]
2iteratore = iter(numeri)

3print(next(iteratore))
4print(next(iteratore))
5print(next(iteratore))
6print(next(iteratore))
1
Definizione di una lista di numeri.
2
Creazione di un iteratore dall’iterabile numeri.
3
Output: 1.
4
Output: 2.
5
Output: 3.
6
Solleva l’eccezione StopIteration perché non ci sono più elementi.

L’istruzione for chiama implicitamente iter sul suo iterabile per ottenere un iteratore. Lo pseudocodice seguente mostra cosa accade dietro le quinte:

_iteratore_temporaneo = iter(contenitore)

while True:
    try:
        x = next(_iteratore_temporaneo)

    except StopIteration:
        break

    istruzione(i)

14.3.4 La funzione range

La funzione range genera una sequenza di numeri interi. È comunemente usata nei cicli for.

1for i in range(5):
2  print(i)
1
Inizia il ciclo for sui numeri da 0 a 4.
2
Stampa il numero corrente.

range può accettare fino a tre argomenti: start, stop, e step.

1for i in range(1, 10, 2):
2  print(i)
1
Inizia il ciclo for sui numeri da 1 a 9, con incremento di 2.
2
Stampa il numero corrente.

L’oggetto range è un iterabile ma non un iteratore. Tuttavia, è possibile ottenere un iteratore chiamando iter() su un oggetto range.

r = range(5)
i = iter(r)

1print(next(i))
2print(next(i))
1
Stampa il primo numero dell’oggetto range: 0.
2
Stampa il secondo numero dell’oggetto range: 1.

14.3.5 Spacchettamento nei cicli for

È possibile utilizzare un indice composto da più identificatori, come in un’assegnazione con spacchettamento. In questo caso, gli elementi dell’iteratore devono essere essi stessi iterabili, ciascuno con esattamente tanti elementi quanti sono gli identificatori nell’indice.

Esempio di ciclo for su un dizionario:

d = {'a': 1, 'b': 2, 'c': 3}

1for chiave, valore in d.items():
2  if chiave and valore:
3    print(chiave, valore)
1
Inizia il ciclo for sugli elementi del dizionario d.
2
Verifica se sia la chiave che il valore sono “truthy”.
3
Stampa la coppia chiave-valore.

È possibile usare un identificatore preceduto da un asterisco * nel target. Questo identificatore verrà associato a una lista di tutti gli elementi non assegnati ad altri target.

lista = [1, 2, 3, 4, 5]

1for primo, *centro, ultimo in [lista]:
2  print(primo)
3  print(centro)
4  print(ultimo)
1
Inizia il ciclo for sulla lista lista.
2
Stampa il primo elemento della lista.
3
Stampa tutti gli elementi centrali della lista.
4
Stampa l’ultimo elemento della lista.

14.4 Comprensioni

Le comprensioni comprehension in Python sono un modo conciso e leggibile per creare nuove sequenze (liste, insiemi, dizionari) da iterabili esistenti. Sono un esempio di supporto alla programmazione funzionale in quanto permettono di creare nuove collezioni attraverso la trasformazione e il filtraggio di elementi, senza modificare l’iterabile originale. Questa capacità di trasformare dati in modo dichiarativo, senza effetti collaterali, è un principio fondamentale della programmazione funzionale.

14.4.1 Liste

Le comprensioni di liste sono uno degli utilizzi più comuni. Permettono di ispezionare ogni elemento di un iterabile e costruire una nuova lista aggiungendo i risultati di un’espressione calcolata su alcuni o tutti gli elementi. Una compresa di lista ha la seguente sintassi:

[espressione for indice in iterabile clausole]
  • indice e iterabile in ogni clausola for di una compresa di lista hanno la stessa sintassi e significato di quelli in una normale istruzione for.

  • espressione può essere qualsiasi espressione Python valida e viene calcolata per ogni elemento della lista risultante.

  • clausole è una serie di zero o più clausole, ciascuna con la forma for indice in iterabile o if espressione.

Esempio semplice:

1result = [x + 1 for x in range(5)]

2print(result)
1
Crea una lista di numeri incrementati di 1 da 0 a 4.
2
Output: [1, 2, 3, 4, 5].

Esempio con condizione:

1result = [x + 1 for x in range(5) if x > 2]

2print(result)
1
Crea una lista con i numeri da 1 a 5, ma solo per i numeri maggiori di 2.
2
Output: [4, 5].

Esempio con annidamento:

lista_di_liste = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

1result = [x for sublist in lista_di_liste for x in sublist]
2print(result)
1
Appiattisce una lista di liste in una singola lista.
2
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9].

14.4.2 Insiemi

Le comprensioni di insiemi hanno la stessa sintassi e semantica delle comprese di liste, ad eccezione che sono racchiuse tra parentesi graffe {} invece che tra parentesi quadre []. Il risultato è un insieme.

Esempio:

1s = {n // 2 for n in range(10)}

2print(sorted(s))
1
Crea un insieme con i risultati della divisione intera di n per 2, da 0 a 9.
2
Output: [0, 1, 2, 3, 4].

14.4.3 Dizionari

Le comprensioni di dizionari hanno la stessa sintassi delle comprese di insiemi, ma invece di una singola espressione prima della clausola for, si usano due espressioni separate da un due punti :: chiave:valore. Il risultato è un dizionario che mantiene l’ordine di inserimento.

Esempio:

1d = {s: i for i, s in enumerate(['zero', 'uno', 'due'])}

2print(d)
1
Crea un dizionario associando ogni stringa al suo indice nella lista.
2
Output: {'zero': 0, 'uno': 1, 'due': 2}.

14.5 Gestione anomalie

14.5.1 Istruzioni try e raise

Python supporta la gestione delle eccezioni con l’istruzione composta try, che include le clausole try, except, finally ed else. Il codice può anche sollevare esplicitamente un’eccezione con l’istruzione raise. Quando il codice solleva un’eccezione, il normale flusso di controllo del programma si interrompe e Python cerca un gestore di eccezioni adatto.

Esempio di utilizzo di try e raise:

1def dividi(a, b):
2  try:
3    return a / b

4  except ZeroDivisionError:
5    raise ValueError("Divisione per zero non consentita")

6try:
7  risultato = dividi(10, 0)

8except ValueError as e:
9  print(e)
1
Definizione della funzione dividi.
2
Inizia il blocco try.
3
Tentativo di divisione.
4
Gestione dell’eccezione ZeroDivisionError.
5
Sollevamento di una nuova eccezione ValueError.
6
Inizia un altro blocco try.
7
Tentativo di chiamare dividi con un denominatore pari a zero.
8
Gestione dell’eccezione ValueError.
9
Output del messaggio di errore: Divisione per zero non consentita.

14.5.2 Istruzione di controllo condizioni anomale

L’istruzione assert condizione, messaggio viene utilizzata per eseguire controlli durante l’esecuzione del programma. Se la condizione è falsa, viene sollevata un’eccezione AssertionError che include il messaggio. Può essere usata per il debugging e per verificare condizioni che dovrebbero essere sempre vere in un punto specifico del codice.

Esempi di utilizzo:

x = 5

1assert x > 0, "x deve essere maggiore di zero"
2assert x < 0, "x deve essere minore di zero"
1
Non genera errore perché x > 0 è vero.
2
Genera AssertionError con il messaggio "x deve essere minore di zero" perché x < 0 è falso.

È importante notare che le asserzioni possono essere disabilitate a livello di runtime utilizzando l’opzione -O (ottimizzazione) quando si esegue lo script Python. Questo rimuoverà tutte le istruzioni assert dal bytecode generato.

python -O script.py

14.6 Altre istruzioni

14.6.1 Istruzione pass

Il corpo di un’istruzione composta in Python non può essere vuoto; deve contenere almeno un’istruzione. Si può utilizzare l’istruzione pass, che non esegue alcuna azione, come segnaposto esplicito quando è richiesta un’istruzione sintatticamente ma non c’è nulla da fare.

Esempio di utilizzo di pass:

1if True:
2  pass
1
Condizione sempre vera.
2
Segnaposto che non esegue alcuna azione.
1def funzione_non_implementata():
2  pass
1
Definizione di una funzione.
2
Segnaposto per una funzione non ancora implementata.
1class ClasseVuota:
2  pass
1
Definizione di una classe.
2
Segnaposto per una classe non ancora implementata.

14.6.2 Istruzione with

L’istruzione composta with può spesso essere un’alternativa più leggibile e utile all’istruzione try/finally. Essa consente di gestire risorse in modo efficiente e sicuro, assicurando che le risorse siano correttamente rilasciate dopo l’uso. Per essere gestita dall’istruzione with, una risorsa deve implementare il protocollo del context manager, che richiede i metodi speciali __enter__ e __exit__.

Un esempio comune è l’uso di with per gestire i file:

1with open('file.txt', 'r') as file:
2  contenuto = file.read()
  
3  print(contenuto)
1
Apre il file file.txt in modalità lettura.
2
Legge il contenuto del file.
3
Output del contenuto del file.

Esempio di un contesto personalizzato:

class GestoreRisorsa:
1  def __enter__(self):
2    print("Risorsa acquisita")

    return self
    
3  def __exit__(self, tipo, valore, traceback):
4    print("Risorsa rilasciata")
      
5with GestoreRisorsa() as risorsa:
6  print("Usando la risorsa")
1
Metodo __enter__ che viene chiamato all’inizio del blocco with.
2
Output indicante che la risorsa è stata acquisita.
3
Metodo __exit__ che viene chiamato alla fine del blocco with, indipendentemente dal fatto che ci sia stata un’eccezione o meno.
4
Output indicante che la risorsa è stata rilasciata.
5
Inizia il blocco with usando il GestoreRisorsa.
6
Output indicante l’uso della risorsa.

14.6.3 Istruzioni di ritorno

Le istruzioni di ritorno vengono utilizzate per restituire valori da una funzione. Esistono due tipi principali di istruzioni di ritorno: return e yield.

14.6.3.1 return

L’istruzione return viene utilizzata per restituire un valore da una funzione e terminare l’esecuzione della funzione.

1def somma(a, b):
2  return a + b

3print(somma(3, 4))
1
Definizione della funzione somma.
2
Restituisce la somma di a e b.
3
Output della somma: 7.

14.6.3.2 yield

L’istruzione yield viene utilizzata per restituire un valore da una funzione generatore senza terminare l’esecuzione della funzione. La funzione può riprendere l’esecuzione dal punto in cui è stata interrotta al successivo ciclo di iterazione.

1def generatore():
2    yield 1
3    yield 2
4    yield 3

5for valore in generatore():
6    print(valore)
1
Definizione della funzione generatore generatore.
2
Restituisce 1 e sospende l’esecuzione.
3
Restituisce 2 e sospende l’esecuzione.
4
Restituisce 3 e sospende l’esecuzione.
5
Itera sui valori restituiti dal generatore.
6
Output dei valori: 1, 2, 3.

14.6.4 Modificatori di ambito

Le istruzioni global e nonlocal sono utilizzate per modificare la visibilità delle variabili all’interno delle funzioni.

L’istruzione global viene utilizzata per dichiarare che una variabile all’interno di una funzione fa riferimento a una variabile globale, cioè una variabile definita al di fuori di qualsiasi funzione. Senza global, tutte le assegnazioni di variabili all’interno di una funzione sono considerate locali alla funzione stessa.

Esempio di utilizzo di global:

1x = 10

def modifica_global():
2  global x

  x = 20

modifica_global()

3print(x)
1
x è una variabile globale.
2
L’istruzione global dichiara che x fa riferimento alla variabile globale x, permettendo alla funzione di modificarla.
3
Output: 20.

L’istruzione nonlocal viene utilizzata per dichiarare che una variabile all’interno di una funzione fa riferimento a una variabile non locale, cioè una variabile definita in un contesto esterno ma non globale (ad esempio, all’interno di una funzione contenente). Senza nonlocal, tutte le assegnazioni di variabili all’interno di una funzione sono considerate locali alla funzione stessa.

Esempio di utilizzo di nonlocal:

def esterna():
1  x = 10

  def interna():
2    nonlocal x
    
    x = 20

  interna()

  print(x)

3esterna()
1
x è una variabile locale alla funzione esterna.
2
L’istruzione nonlocal dichiara che x fa riferimento alla variabile non locale x, permettendo alla funzione interna di modificarla.
3
Output: 20.

14.6.5 Alias di tipo

L’istruzione type viene utilizzata per creare alias di tipo. Questo consente di assegnare nomi significativi ai tipi di dati complessi, migliorando la leggibilità del codice. Si possono definire anche alias di tipi generici, cioè tipi parametrizzati da altri tipi.

È importante sottolineare che gli alias non sono da intendere come utili al controllo statico dei tipi durante l’esecuzione, ma come annotazione utile per strumenti di analisi del codice e miglioramento della leggibilità.

Esempi:

  • Definizione di alias di tipo:

    1type lista_coppie = list[tuple[str, int]]
    1
    lista_coppie è un alias di list[tuple[str, int]].
  • Definizione di alias di tipo generico:

    1type contenitore_ordinato[T] = list[t] | tuple[T, ...]
    1
    contenitore_ordinato può essere o una lista o una tupla con zero o più elementi.

14.6.6 Eliminazione di identificatori e elementi in contenitori

L’istruzione del viene utilizzata per eliminare identificatori come variabili o di funzione e oggetti da contenitori, come elementi singoli o in sezioni (slice) di liste oppure chiavi di dizionari. del rimuovendo i riferimenti agli oggetti, segnala al garbage collector la possibilità di liberazione delle risorse associate.

Esempi di utilizzo:

  • Eliminazione di una variabile:

    x = 10
    
    1del x
    
    2print(x)
    1
    Elimina la variabile x.
    2
    Dà errore perché x non esiste.
  • Eliminazione di un elemento da un contenitore di oggetti di tipo lista per indice:

    lista = [1, 2, 3, 4]
    
    1del lista[0]
    
    2print(lista)
    1
    Elimina il primo elemento dalla lista.
    2
    Output: [2, 3, 4].
  • Eliminare di elementi contigui da una lista:

    lista = [1, 2, 3, 4, 5, 6]
    
    1del lista[1:4]
    
    2print(lista)
    1
    Elimina gli elementi dal secondo al quarto.
    2
    Output: [1, 5, 6].
  • Eliminazione di una chiave da un dizionario:

    dizionario = {'a': 1, 'b': 2, 'c': 3}
    
    1del dizionario['a']
    
    2print(dizionario)
    1
    Elimina la chiave 'a' dal dizionario.
    2
    Output: {'b': 2, 'c': 3}.
  • Eliminazione di un attributo da un oggetto:

    class ClasseSemplice:
      def __init__(self):
        self.attr = 42
    
    oggetto_semplice = ClasseSemplice()
    
    1del oggetto_semplice.attr
    1
    Elimina l’attributo 'attr' dall’oggetto 'oggetto_semplice'.
  • Eliminazione dell’identificatore di una funzione:

    def somma_semplice(a, b):
        return a + b
    
    1del somma_semplice
    
    2somma_semplice(a, b)
    1
    Elimina il riferimento somma_semplice alla funzione.
    2
    Errore. Output: NameError: name 'somma_semplice' is not defined.
  • Eliminazione dell’identificatore di un modulo:

    import math
    
    1print(math.sqrt(4))
    
    del math
    
    2print(math)
    1
    Output: 2.0.
    2
    Errore. Output: NameError: name 'math' is not defined. Did you forget to import 'math'?.