16  Esercizi

Legenda livelli:

➀ Neofita: Adatto a chi è alle prime armi con la programmazione. Gli esercizi di questo livello richiedono una conoscenza basilare della sintassi di Python e dei concetti fondamentali come variabili, semplici espressioni, dimistichezza coll’esecuzione dell’interprete.

➁ Principiante: Gli esercizi a questo livello sono pensati per chi ha familiarità con i costrutti di base di Python e vuole iniziare a esplorare le strutture dati come liste, tuple e dizionari.

➂ Principiante evoluto: Questi esercizi richiedono una comprensione più approfondita dei costrutti disponibili e delle operazioni sulle strutture dati fornite dal linguaggio. Gli studenti dovrebbero essere in grado di scrivere funzioni e manipolare collezioni di dati, usando la documentazione del linguaggio.

➃ Autonomo: A questo livello, gli studenti devono saper gestire concetti come il controllo del workflow di esecuzione per mezzo delle eccezioni, l’uso di moduli e pacchetti standard, nonché di quelli esterni al linguaggio. Gli studenti devono saper effettuare un debugging, fornire codice documentato e più organizzato e modulare.

➄ Intermedio: Gli esercizi richiedono la capacità di lavorare con librerie esterne, creare e gestire oggetti complessi, e utilizzare tecniche di programmazione più avanzate come le comprensioni di lista e le espressioni lambda, sapendo applicare pienamente sia lo stile orientato agli oggetti che quello funzionale. Gli studenti devono produrre codice robusto per mezzo di tecniche come i test di unità.

➅ Esperto: A questo livello, gli esercizi implicano la padronanza di concetti avanzati come il decoratori, i generatori, e la manipolazione avanzata dei dati. Gli studenti dovrebbero essere in grado di risolvere problemi complessi con soluzioni eleganti.

➆ Esperto evoluto: Gli studenti devono avere competenze solide di disegno di software basato sul paradigma dell’orientamento agli oggetti e funzionale, nonché nell’ottimizzazione del codice per la performance.

➇ Maestro: Gli esercizi a questo livello richiedono la conoscenza approfondita di Python, comprese le tecniche di programmazione asincrona, il threading e la gestione di progetti di grandi dimensioni in diversi ambiti.

➈ Maestro evoluto: A questo livello, gli studenti devono padroneggiare la creazione di librerie proprie anche usando le modalità di estensione di Python.

➉ Guru: Questo è il livello più alto di difficoltà, dove gli esercizi richiedono una comprensione approfondita e una padronanza assoluta di Python. Gli studenti devono essere in grado di risolvere problemi estremamente complessi, ottimizzare il codice a livello di prestazioni e memoria, e applicare concetti avanzati di ingegneria del software.

16.1 ➀ Python come calcolatrice

Primi esperimenti con Python.

16.1.1 Numeri interi e in virgola mobile

Usare gli operatori matematici su costanti numeriche e osservare i risultati e gli errori nel REPL, perché è più immediato rispetto all’esecuzione completa del programma e permette di prendere dimistichezza velocemente con dei costrutti di base del linguaggio.

Il codice seguente può essere eseguito sia nel REPL, riga per riga, sia come programma.

Suggerimento

Usando il REPL, basterà digitare l’espressione senza assegnamento per ottenere il risultato.

# Moltiplicazione
x = 5 * 2
print(x)

x = 5 * 2.
print(x) # Cosa notiamo?

# Divisione in virgola mobile
x = 5 / 2
print(x)

x = 4 / 2
print(x) # Cosa notiamo?

x = 4 / 2.
print(x)

# Confronto
x = 5 > 2
print(x)

x = 5 > 2.
print(x) # Cosa notiamo?

# Diversità
x = 4 != 4.
print(x) # Cosa notiamo?

x = 0 != (1 - 1)
print(x) # Cosa notiamo?

16.1.2 Stringhe

Usare gli operatori su stringhe, sempre nel REPL.

s = "Hello" + ' ' + 'World!'
print(s)

ss = s

ss *= 2
print(ss)
print(s) # Cosa notiamo per s e ss?

# Appartenenza
b = 'el' in s
print(b) 

b = 'oo' not in s
print(b)

# Confronto
b = "Ciao Mondo!" < s 
print(b) # È rispettato l'ordine lessicografico?

l_s= len(s)
print(l_s)

# Slicing della stringa come contenitore di caratteri
s_ = ss[:l_s] 
print(s_) 

l_ss = len(ss) 
print(l_ss)

# Modo alternativo di ottenere la stringa originale solo usando ss
s_ = ss[:int(l_ss / 2)] 
print(s_) 

# Metodo per rendere la stringa in maiuscolo
su = s.upper()
print(su)

# Uguaglianza
b = s == su
print(b) # Cosa notiamo?

16.1.3 Espressioni

Costruire delle espressioni per comprendere come mischiare numeri e stringhe, la precedenza degli operatori e le conversioni di tipo, sempre nel REPL.

n = 42
s = "42"

# Congiunzione
b = n and s
print(b) # Cosa notiamo?

# Disgiunzione
b = n or s
print(b) 

# Negazione e congiunzione
b = n and not s
print(b) # Cosa notiamo?

# Conversione di tipo in stringa e appartenenza
b = str(2) in s
print(b)

# Conversione di tipo in intero e divisione
b = int(s) / 2
print(b)

# Espressione con precedenza data dall'ordine degli operatori 
e = 2 + n * 3
print(e)

# Espressione con precedenza modificata colle parentesi 
e = (2 + n) * 3
print(e) # Cosa notiamo?

16.2 ➁ Numeri pari o dispari

Definire una funzione che prende in input un numero intero e restituisce una stringa di Pari o Dispari.

16.2.1 Riscaldamento

Sperimentiamo l’operatore modulo %, che restituisce il resto della divisione di due interi, con diversi input sia pari che dispari usando un test condizionale.

n = 42

if n % 2 == 0:
  print("Pari")

else:
  print("Dispari")

16.2.2 Svolgimento

Inserire le istruzioni in una funzione che prende in input un parametro, il numero intero, e restituisce una stringa, Pari o Dispari. Sperimentare soluzioni diverse.

Usiamo l’operatore modulo % che restituisce il resto della divisione di due interi all’interno di una funzione. Questa prende in input un numero intero e restituisce la stringa richiesta.

def pari_o_dispari(n):
  if n % 2 == 0:
    return "Pari"

  else:
    return "Dispari"

risultato = pari_o_dispari(42)

print(risultato)

risultato = pari_o_dispari(73)

print(risultato)

Usiamo l’operatore modulo % per il test di parità sul numero intero e la funzione isinstance per verificare il tipo in input.

def pari_o_dispari(n):
  if not isinstance(n, int):
    return "Errore: l'input deve essere un numero intero!"
    
  if n % 2 == 0:
    return "Pari"

  else:
    return "Dispari"

risultato = pari_o_dispari(42)

print(risultato)

risultato = pari_o_dispari(73)

print(risultato)

Usiamo l’operatore modulo %, la funzione isinstance per verificare il tipo in input e assert in caso di input non corretto.

def pari_o_dispari(n):
  assert isinstance(n, int), \
    "Errore: l'input deve essere un numero intero!"
    
  if n % 2 == 0:
    return "Pari"

  else:
    return "Dispari"

risultato = pari_o_dispari(42)

print(risultato)

risultato = pari_o_dispari(73)

print(risultato)

'''
risultato = pari_o_dispari("42")

print(risultato)

risultato = pari_o_dispari(73.)

print(risultato)
'''

Usiamo la funzione divmod che restituisce il quoziente e il resto della divisione di due interi. Per ottenere documentazione su essa basterà digitare help(divmod) nel REPL.

def pari_o_dispari(n):
  _, remainder = divmod(n, 2)

  return "Pari" if remainder == 0 else "Dispari"

risultato = pari_o_dispari(42)

print(risultato)

risultato = pari_o_dispari(73)

print(risultato)

16.3 ➁ Rimozione di duplicati da una lista preservando l’ordinamento

Scrivere una funzione che prende in input una lista e ne rimuove i duplicati, preservando l’ordinamento.

Usiamo un ciclo for per iterare attraverso la lista originale e una lista di appoggio per memorizzare gli elementi unici. Gli elementi vengono aggiunti alla lista di appoggio solo se non sono già presenti in essa, preservando così l’ordine originale.

def rimuovi_duplicati(lista):
  lista_senza_duplicati = []

  for elemento in lista:
    if elemento not in lista_senza_duplicati:
      lista_senza_duplicati.append(elemento)

  return lista_senza_duplicati

# Esempio di utilizzo
lista = [4, 2, 2, 3, 1, 4, 5]

print(rimuovi_duplicati(lista)) 

Usiamo un ciclo while per iterare attraverso la lista originale. Un set viene utilizzato per memorizzare gli elementi già visti e una lista di appoggio per memorizzare gli elementi unici. Gli elementi vengono aggiunti alla lista di appoggio solo se non sono già presenti nel set.

def rimuovi_duplicati(lista):
  lista_senza_duplicati = []

  visti = set()

  i = 0
  while i < len(lista):
    if lista[i] not in visti:
      lista_senza_duplicati.append(lista[i])

      visti.add(lista[i])

    i += 1

  return lista_senza_duplicati

# Esempio di utilizzo
lista = [4, 2, 2, 3, 1, 4, 5]

print(rimuovi_duplicati(lista)) 

Usiamo un dizionario per memorizzare gli elementi unici, sfruttando il fatto che i dizionari preservano l’ordine di inserimento a partire da Python 3.7. Gli elementi vengono aggiunti al dizionario come chiavi, e infine si restituisce la lista delle chiavi del dizionario.

def rimuovi_duplicati(lista):
  return list(dict.fromkeys(lista))

# Esempio di utilizzo
lista = [4, 2, 2, 3, 1, 4, 5]

print(rimuovi_duplicati(lista)) 

Utilizziamo una list comprehension per creare una nuova lista. Un set viene usato per tenere traccia degli elementi già visti, e gli elementi vengono aggiunti alla lista finale solo se non sono già presenti nel set.

def rimuovi_duplicati(lista):
    visti = set()
    
    lista_senza_duplicati = [elemento 
                             for elemento in lista 
                             if elemento not in visti and not visti.add(elemento)]
    
    return lista_senza_duplicati

# Esempio di utilizzo
lista = [4, 2, 2, 3, 1, 4, 5]

print(rimuovi_duplicati(lista)) 

16.4 ➁ Rimozione di duplicati da una lista e ordinamento

Scrivere una funzione che prende in input una lista e ne rimuove i duplicati, ordinando il risultato.

Usiamo un ciclo for per iterare attraverso la lista originale e una lista di appoggio per memorizzare gli elementi unici. Gli elementi vengono aggiunti alla lista di appoggio solo se non sono già presenti in essa. Dopo aver rimosso i duplicati, ordiniamo la lista risultante.

def rimuovi_duplicati(lista):
  lista_senza_duplicati = []

  for elemento in lista:
    if elemento not in lista_senza_duplicati:
      lista_senza_duplicati.append(elemento)

  return sorted(lista_senza_duplicati)

# Esempio di utilizzo
lista = [4, 2, 2, 3, 1, 4, 5]

print(rimuovi_duplicati(lista)) 

Usiamo un ciclo while per iterare attraverso la lista originale. Un set viene utilizzato per memorizzare gli elementi già visti e una lista di appoggio per memorizzare gli elementi unici. Gli elementi vengono aggiunti alla lista di appoggio solo se non sono già presenti nel set. Dopo aver rimosso i duplicati, ordiniamo la lista risultante.

def rimuovi_duplicati(lista):
  lista_senza_duplicati = []
  visti = set()

  i = 0
  while i < len(lista):
    if lista[i] not in visti:
      lista_senza_duplicati.append(lista[i])

      visti.add(lista[i])

    i += 1

  return sorted(lista_senza_duplicati)

# Esempio di utilizzo
lista = [4, 2, 2, 3, 1, 4, 5]

print(rimuovi_duplicati(lista)) 

Usiamo un dizionario per memorizzare gli elementi unici, sfruttando il fatto che i dizionari preservano l’ordine di inserimento a partire da Python 3.7. Gli elementi vengono aggiunti al dizionario come chiavi. Dopo aver rimosso i duplicati, ordiniamo la lista delle chiavi del dizionario.

def rimuovi_duplicati(lista):
  return sorted(dict.fromkeys(lista))

# Esempio di utilizzo
lista = [4, 2, 2, 3, 1, 4, 5]

print(rimuovi_duplicati(lista)) 

Utilizziamo una list comprehension per creare una nuova lista. Un set viene usato per tenere traccia degli elementi già visti, e gli elementi vengono aggiunti alla lista finale solo se non sono già presenti nel set. Dopo aver rimosso i duplicati, ordiniamo la lista risultante.

def rimuovi_duplicati(lista):
  visti = set()

  lista_senza_duplicati = [x for x in lista if not (x in visti or visti.add(x))]

  return sorted(lista_senza_duplicati)

# Esempio di utilizzo
lista = [4, 2, 2, 3, 1, 4, 5]

print(rimuovi_duplicati(lista)) 

16.5 ➁ Calcolo del fattoriale di un numero

Scrivere una funzione che prende in input un numero intero positivo e restituisce il suo fattoriale.

Suggerimento

Il fattoriale di un numero n è il prodotto di tutti i numeri interi positivi minori o uguali a n ed è denotato come n!.

Usiamo un ciclo for per calcolare il fattoriale. Partiamo da 1 e moltiplichiamo progressivamente tutti i numeri fino a n.

def fattoriale(n):
  risultato = 1

  for i in range(1, n + 1):
    risultato *= i

  return risultato

# Esempio di utilizzo
numero = 5

1print(fattoriale(numero))
1
Output: 120.

Usiamo un ciclo while per calcolare il fattoriale. Partiamo da 1 e moltiplichiamo progressivamente tutti i numeri fino a n, utilizzando una variabile di iterazione.

def fattoriale(n):
  risultato = 1
  i = 1

  while i <= n:
    risultato *= i

    i += 1

  return risultato

# Esempio di utilizzo
numero = 5

1print(fattoriale(numero))
1
Output: 120.

Utilizziamo la ricorsione per calcolare il fattoriale. La funzione richiama se stessa riducendo il problema fino a raggiungere il caso base n = 1.

def fattoriale(n):
  if n == 0 or n == 1:
    return 1

  else:
    return n * fattoriale(n - 1)

# Esempio di utilizzo
numero = 5

1print(fattoriale(numero))
1
Output: 120.

Usiamo la funzione reduce del modulo functools per calcolare il fattoriale. Questa soluzione utilizza un approccio funzionale per ridurre una sequenza di numeri a un singolo valore.

from functools import reduce

def fattoriale(n):
  return reduce(lambda x, y: x * y, range(1, n + 1), 1)

# Esempio di utilizzo
numero = 5

1print(fattoriale(numero))
1
Output: 120.

16.6 ➁ Contare le parole in una frase in modo semplificato

Scrivere una funzione che prende in input una stringa contenente una frase e restituisce un dizionario con il conteggio di ciascuna parola nella frase. Le frasi non devono contenere punteggiatura e il confronto tiene conto della differenza tra lettere maiuscole e minuscole.

Usiamo un ciclo for per iterare attraverso le parole della frase, aggiornando il conteggio di ciascuna parola in un dizionario.

def conta_parole(frase):
  parole = frase.split()
  conteggio = {}
  
  for parola in parole:
    if parola in conteggio:
      conteggio[parola] += 1

    else:
      conteggio[parola] = 1

  return conteggio

# Esempio di utilizzo
frase = "ciao ciao come stai ciao"

print(conta_parole(frase))  # <1> # 
  1. Output: {'ciao': 3, 'come': 1, 'stai': 1}.

Usiamo il metodo get del dizionario per aggiornare il conteggio delle parole in un dizionario.

def conta_parole(frase):
  parole = frase.split()
  conteggio = {}
  
  for parola in parole:
    conteggio[parola] = conteggio.get(parola, 0) + 1
  return conteggio

# Esempio di utilizzo
frase = "ciao ciao come stai ciao"

print(conta_parole(frase))  

Usiamo il modulo collections e il defaultdict per semplificare il conteggio delle parole.

from collections import defaultdict

def conta_parole(frase):
  parole = frase.split()
  conteggio = defaultdict(int)

  for parola in parole:
    conteggio[parola] += 1
      
  return dict(conteggio)

# Esempio di utilizzo
frase = "ciao ciao come stai ciao"

print(conta_parole(frase))  

Usiamo il modulo collections e Counter per contare le parole nella frase in modo conciso.

from collections import Counter

def conta_parole(frase):
  parole = frase.split()

  conteggio = Counter(parole)

  return dict(conteggio)

# Esempio di utilizzo
frase = "ciao ciao come stai ciao"

print(conta_parole(frase))  

16.7 ➂ Contare le parole in una frase con esattezza

Scrivere una funzione che prende in input una stringa contenente una frase e un flag maiuscolo_minuscolo che controlla se il conteggio delle parole debba tener conto del maiuscolo o minuscolo. Inoltre considera parole senza terner conto di eventuale punteggiatura nel calcolo. La funzione restituisce un dizionario con il conteggio di ciascuna parola nella frase.

Suggerimento

Si può usare string.punctuation del modulo string che contiene tutti i caratteri di punteggiatura disponibili in Python. Include caratteri come !"#$%&'()*+,-./:;<=>?@[\]^_``{|}~.

Usiamo un ciclo for per iterare attraverso le parole della frase, aggiornando il conteggio di ciascuna parola in un dizionario. Il comportamento è determinato dal flag maiuscolo_minuscolo.

import string

def conta_parole(frase, maiuscolo_minuscolo=False):
  if not maiuscolo_minuscolo:
    frase = frase.lower()

  frase = ''.join(carattere for carattere in frase if carattere not in string.punctuation)

  parole = frase.split()

  conteggio = {}

  for parola in parole:
    if parola in conteggio:
      conteggio[parola] += 1

    else:
      conteggio[parola] = 1

  return conteggio

# Esempio di utilizzo
frase = "Ciao, ciao! Come stai? Ciao."

print(conta_parole(frase, maiuscolo_minuscolo=False)) 
print(conta_parole(frase, maiuscolo_minuscolo=True))  

Usiamo il metodo get del dizionario per aggiornare il conteggio delle parole in un dizionario. Il comportamento è determinato dal flag maiuscolo_minuscolo.

import string

def conta_parole(frase, maiuscolo_minuscolo=False):
  if not maiuscolo_minuscolo:
    frase = frase.lower()

  frase = ''.join(carattere for carattere in frase if carattere not in string.punctuation)

  parole = frase.split()

  conteggio = {}

  for parola in parole:
    conteggio[parola] = conteggio.get(parola, 0) + 1
      
  return conteggio

# Esempio di utilizzo
frase = "Ciao, ciao! Come stai? Ciao."

print(conta_parole(frase, maiuscolo_minuscolo=False))  
print(conta_parole(frase, maiuscolo_minuscolo=True))  

Usiamo il modulo collections e il defaultdict per semplificare il conteggio delle parole. Il comportamento è determinato dal flag maiuscolo_minuscolo.

import string
from collections import defaultdict

def conta_parole(frase, maiuscolo_minuscolo=False):
  if not maiuscolo_minuscolo:
    frase = frase.lower()

  frase = ''.join(carattere for carattere in frase if carattere not in string.punctuation)

  parole = frase.split()

  conteggio = defaultdict(int)

  for parola in parole:
    conteggio[parola] += 1

  return dict(conteggio)

# Esempio di utilizzo
frase = "Ciao, ciao! Come stai? Ciao."

print(conta_parole(frase, maiuscolo_minuscolo=False)) 
print(conta_parole(frase, maiuscolo_minuscolo=True))  

Usiamo il modulo collections e Counter per contare le parole nella frase in modo conciso. Il comportamento è determinato dal flag maiuscolo_minuscolo.

import string
from collections import Counter

def conta_parole(frase, maiuscolo_minuscolo=False):
  if not maiuscolo_minuscolo:
    frase = frase.lower()

  frase = ''.join(carattere for carattere in frase if carattere not in string.punctuation)

  parole = frase.split()

  conteggio = Counter(parole)

  return dict(conteggio)

# Esempio di utilizzo
frase = "Ciao, ciao! Come stai? Ciao."

print(conta_parole(frase, maiuscolo_minuscolo=False)) 
print(conta_parole(frase, maiuscolo_minuscolo=True)) 

16.8 ➃ Creazione e gestione di file

16.8.1 Creazione di file di testo

Scrivere una funzione che crea un file di testo, scrive diverse righe al suo interno includendo interi, float, stringhe, liste e dizionari, e salva il file.

def crea_file_di_testo(nome_file):
1  with open(nome_file, 'w') as file:
2    file.write(f"Esempio di intero: {42}\n")

3    file.write(f"Esempio di float: {3.14}\n")

4    file.write(f"Esempio di stringa: {'Ciao, mondo!'}\n")
    
    lista = [1, 2, 3, 4]
5    file.write(f"Esempio di lista: {lista}\n")
    
    dizionario = {'chiave': 'valore', 'numero': 42}
6    file.write(f"Esempio di dizionario: {dizionario}\n")

# Esempio di utilizzo
crea_file_di_testo("esempio.txt")
1
Apre un file in modalità scrittura.
2
Scrive un esempio di intero nel file.
3
Scrive un esempio di float nel file.
4
Scrive un esempio di stringa nel file.
5
Scrive un esempio di lista nel file.
6
Scrive un esempio di dizionario nel file.
def crea_file_di_testo_writelines(nome_file):
1  with open(nome_file, 'w') as file:
    righe = [
2      f"Esempio di intero: {42}\n",

3      f"Esempio di float: {3.14}\n",

      f"Esempio di stringa: {'Ciao, mondo!'}\n",

      f"Esempio di lista: {[1, 2, 3, 4]}\n",

      f"Esempio di dizionario: {{'chiave': 'valore', 'numero': 42}}\n"
    ]

    file.writelines(righe)

# Esempio di utilizzo
crea_file_di_testo_writelines("esempio_writelines.txt")
1
Apre un file in modalità scrittura.
2
Definisce una lista di righe di testo, ognuna rappresentante un diverso tipo di dato.
3
Scrive tutte le righe nel file utilizzando writelines.

16.8.2 Creazione di file JSON

Scrivere una funzione che crea un file JSON, scrive alcuni dati al suo interno e salva il file.

1import json

def crea_file_json(nome_file, dati):
2  with open(nome_file, 'w') as file:
3    json.dump(dati, file, indent=4)

# Esempio di utilizzo
dati = {
  "intero": 42,
  "float": 3.14,
  "stringa": "Ciao, mondo!",
  "lista": [1, 2, 3, 4],
  "dizionario": {"chiave": "valore", "numero": 42}
}

crea_file_json("esempio.json", dati)
1
Importa il modulo json.
2
Apre un file in modalità scrittura.
3
Scrive i dati nel file JSON con indentazione.
1import json

def crea_file_json_formattato(nome_file, dati):
2  json_data = json.dumps(dati, indent=4)
  
3  with open(nome_file, 'w') as file:
4    file.write(json_data)

# Esempio di utilizzo
dati = {
  "intero": 42,
  "float": 3.14,
  "stringa": "Ciao, mondo!",
  "lista": [1, 2, 3, 4],
  "dizionario": {"chiave": "valore", "numero": 42}
}

crea_file_json_formattato("esempio_formattato.json", dati)
1
Importa il modulo json.
2
Converte i dati in una stringa JSON formattata con indentazione.
3
Apre un file in modalità scrittura.
4
Scrive la stringa JSON nel file.

16.8.3 Lettura di file JSON

Scrivere una funzione che legge un file JSON, riconosce i tipi di dato delle chiavi e dei valori e stampa i dati convertiti.

1import json

def converti_valore(valore):
  if isinstance(valore, str):
    try:
2      valore_convertito = int(valore)

    except ValueError:
      try:
3        valore_convertito = float(valore)
      except ValueError:
4        valore_convertito = valore

  else:
    valore_convertito = valore

  return valore_convertito

def leggi_file_json(nome_file):
5  with open(nome_file, 'r') as file:
6    dati = json.load(file)
    
    dati_convertiti = {}

    for chiave, valore in dati.items():
      chiave_convertita = converti_valore(chiave)

      if isinstance(valore, list):
        valore_convertito = [converti_valore(v) for v in valore]

      else:
        valore_convertito = converti_valore(valore)
          
      dati_convertiti[chiave_convertita] = valore_convertito
  
7    print(dati_convertiti)

def crea_file_json(nome_file):
  dati = {
    "nome": "Mario",
    "cognome": "Rossi",
    "eta": 30,  
    "altezza": 1.75,  
    "hobby": ["lettura", "pittura", "ciclismo"],  
    "punteggi": [8, 90, 78],  
    "info": {"stato_civile": "sposato", "figli": 2}  
  }
8  with open(nome_file, 'w') as file:
9    json.dump(dati, file, indent=2)

crea_file_json("esempio.json")

leggi_file_json("esempio.json")
1
Importa il modulo json.
2
Prova a convertire in intero.
3
Prova a convertire a valore in virgola mobile.
4
Mantiene come stringa.
5
Apre un file in modalità lettura.
6
Legge i dati dal file JSON.
7
Stampa i dati letti dal file, con chiavi e valori convertiti ai rispettivi tipi.
8
Apre un file in modalità scrittura.
9
Scrive i dati nel file JSON con un’indentazione di 2 spazi.

16.8.4 Creazione e gestione di cartelle e file

Scrivere una funzione che crea una cartella e un file al suo interno, crea un’altra cartella e un file al suo interno, e poi esegue operazioni di cancellazione di cartelle e file, nonché spostamento di file tra le cartelle.

1import os
2import shutil

def crea_cartelle_e_file():
3  os.makedirs("cartella1", exist_ok=True)

4  with open(os.path.join("cartella1", "file1.txt"), 'w') as file:
5    file.write("Questo è il file 1 nella cartella 1")

6  os.makedirs("cartella2", exist_ok=True)

7  with open(os.path.join("cartella2", "file2.txt"), 'w') as file:
8    file.write("Questo è il file 2 nella cartella 2")

def elimina_file_e_cartelle():
9  os.remove(os.path.join("cartella1", "file1.txt"))

10  os.rmdir("cartella1")

11  os.remove(os.path.join("cartella2", "file2.txt"))

12  os.rmdir("cartella2")

def sposta_file():
  crea_cartelle_e_file()

13  shutil.move(os.path.join("cartella2", "file2.txt"), os.path.join("cartella1", "file2.txt"))

  if os.path.exists(os.path.join("cartella1", "file2.txt")):
14    print("Spostamento riuscito!")

  else:
15    print("Spostamento fallito.")

  elimina_file_e_cartelle()

# Esempio di utilizzo
crea_cartelle_e_file()
sposta_file()
1
Importa il modulo os.
2
Importa il modulo shutil.
3
Crea la prima cartella, se non esiste già.
4
Crea un file all’interno della prima cartella.
5
Scrive del testo nel file della prima cartella.
6
Crea la seconda cartella, se non esiste già.
7
Crea un file all’interno della seconda cartella.
8
Scrive del testo nel file della seconda cartella.
9
Cancella il file nella prima cartella.
10
Cancella la prima cartella.
11
Cancella il file nella seconda cartella.
12
Cancella la seconda cartella.
13
Sposta il file dalla seconda cartella alla prima cartella.
14
Verifica se lo spostamento è riuscito.
15
Stampa un messaggio di errore se lo spostamento fallisce.

16.9 ➃ Espressioni regolari

16.9.1 Verifica di indirizzi email

Scrivere una funzione che verifica se una stringa è un indirizzo email valido utilizzando le espressioni regolari.

1import re

def verifica_email(email):
2  pattern = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'

3  if re.match(pattern, email):
4    return True

  else:
5    return False

# Esempio di utilizzo
email1 = "esempio@test.com"
email2 = "invalid-email"

print(verifica_email(email1))  # Output: True
print(verifica_email(email2))  # Output: False
1
Importa il modulo re.
2
Definisce il pattern per un indirizzo email.
3
Verifica se la stringa email corrisponde al pattern.
4
Restituisce True se l’indirizzo email è valido.
5
Restituisce False se l’indirizzo email non è valido.

16.9.2 Estrazione di numeri di telefono

Scrivere una funzione che estrae tutti i numeri di telefono da una stringa utilizzando le espressioni regolari.

1import re

def estrai_numeri_telefono(testo):
2  pattern = r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b'

3  numeri = re.findall(pattern, testo)

4  return numeri

# Esempio di utilizzo
testo = "Contattaci al 123-456-7890 o 098.765.4321."

print(estrai_numeri_telefono(testo))  # Output: ['123-456-7890', '098.765.4321']
1
Importa il modulo re.
2
Definisce il pattern per un numero di telefono.
3
Trova tutti i numeri di telefono nel testo.
4
Restituisce la lista dei numeri di telefono trovati.

16.10 ➃ Interazione con SQLite3

16.10.1 Creazione di un database e una tabella

Scrivere una funzione che crea un database SQLite e una tabella chiamata utenti con tre colonne: id, nome e email.

1import sqlite3

def crea_database(nome_db):
2  conn = sqlite3.connect(nome_db)

3  c = conn.cursor()

4  c.execute('''CREATE TABLE utenti (id INTEGER PRIMARY KEY, nome TEXT, email TEXT)''')

5  conn.commit()

6  conn.close()

# Esempio di utilizzo
crea_database("esempio.db")
1
Importa il modulo sqlite3.
2
Connette al database (crea il database se non esiste).
3
Crea un cursore per eseguire comandi SQL.
4
Esegue il comando SQL per creare la tabella utenti.
5
Salva le modifiche.
6
Chiude la connessione al database.

16.10.2 Inserimento di dati nella tabella

Scrivere una funzione che inserisce un nuovo utente nella tabella utenti.

1import sqlite3

def inserisci_utente(nome_db, nome, email):
2  conn = sqlite3.connect(nome_db)

3  c = conn.cursor()

4  c.execute('INSERT INTO utenti (nome, email) VALUES (?, ?)', (nome, email))

5  conn.commit()

6  conn.close()

# Esempio di utilizzo
inserisci_utente("esempio.db", "Mario Rossi", "mario.rossi@example.com")
1
Importa il modulo sqlite3.
2
Connette al database.
3
Crea un cursore per eseguire comandi SQL.
4
Esegue il comando SQL per inserire un nuovo utente.
5
Salva le modifiche.
6
Chiude la connessione al database.

16.10.3 Lettura di dati dalla tabella

Scrivere una funzione che legge tutti gli utenti dalla tabella utenti e li stampa.

1import sqlite3

def leggi_utenti(nome_db):
2  conn = sqlite3.connect(nome_db)

3  c = conn.cursor()

4  c.execute('SELECT * FROM utenti')

5  utenti = c.fetchall()

6  for utente in utenti:
7    print(utente)

8  conn.close()

# Esempio di utilizzo
leggi_utenti("esempio.db")
1
Importa il modulo sqlite3.
2
Connette al database.
3
Crea un cursore per eseguire comandi SQL.
4
Esegue il comando SQL per selezionare tutti gli utenti.
5
Recupera tutti i risultati della query.
6
Itera attraverso i risultati.
7
Stampa ogni utente.
8
Chiude la connessione al database.

16.10.4 Aggiornamento di dati nella tabella

Scrivere una funzione che aggiorna l’email di un utente nella tabella utenti.

1import sqlite3

def aggiorna_email(nome_db, id_utente, nuova_email):
2  conn = sqlite3.connect(nome_db)

3  c = conn.cursor()

4  c.execute('UPDATE utenti SET email = ? WHERE id = ?', (nuova_email, id_utente))

5  conn.commit()

6  conn.close()

# Esempio di utilizzo
aggiorna_email("esempio.db", 1, "nuovo.email@example.com")
1
Importa il modulo sqlite3.
2
Connette al database.
3
Crea un cursore per eseguire comandi SQL.
4
Esegue il comando SQL per aggiornare l’email dell’utente con l’ID specificato.
5
Salva le modifiche.
6
Chiude la connessione al database.

16.10.5 Eliminazione di dati dalla tabella

Scrivere una funzione che elimina un utente dalla tabella utenti.

1import sqlite3

def elimina_utente(nome_db, id_utente):
2  conn = sqlite3.connect(nome_db)

3  c = conn.cursor()

4  c.execute('DELETE FROM utenti WHERE id = ?', (id_utente,))

5  conn.commit()

6  conn.close()

# Esempio di utilizzo
elimina_utente("esempio.db", 1)
1
Importa il modulo sqlite3.
2
Connette al database.
3
Crea un cursore per eseguire comandi SQL.
4
Esegue il comando SQL per eliminare l’utente con l’ID specificato.
5
Salva le modifiche.
6
Chiude la connessione al database.