Benvenuti a questa nuova lezione di Python: dopo aver affrontato le basi – come variabili, operatori, controllo del flusso, strutture dati e cicli – è arrivato il momento di fare un passo avanti. Questa lezione vi guiderà attraverso funzioni avanzate, moduli e librerie, gestione di strutture dati complesse e l’implementazione di piccoli progetti reali per consolidare le competenze.
Lo scopo è quello di prepararti ad applicare Python non solo per semplici script, ma anche per sviluppi più articolati, automatizzazioni, elaborazione dati e workflow ripetibili. Se hai letto i precedenti articoli relativi ai cicli (“Cicli for e while…”), alle strutture di controllo (“If, For, While spiegati”), e alle strutture dati (“liste, tuple, set e dizionari”), allora sei pronto per questa fase intermedia-avanzata.
1. Funzioni in Python: dal semplice al modulare
In Python, le funzioni rappresentano blocchi di codice che possono essere riutilizzati, semplificando lo sviluppo e migliorando la leggibilità. In questa sezione vedremo come definire funzioni semplici, passare parametri, usare valori di ritorno, applicare funzioni a più parametri, utilizzare argomenti opzionali e, soprattutto, come progettare funzioni modulari che possano essere riutilizzate all’interno di moduli più grandi.
1.1 Definizione di base e parametri
Una funzione si definisce con la parola chiave def
, seguita dal nome della funzione e da una coppia di parentesi. Ecco un esempio semplice:
def saluta(nome):
print(f"Benvenuto, {nome}!")
Qui la funzione saluta
prende un argomento nome
e stampa un messaggio. Puoi chiamarla così:
saluta("Maria") # Benvenuto, Maria!
Possiamo anche restituire un valore:
def somma(a, b):
return a + b
risultato = somma(3, 5)
print(risultato) # 8
1.2 Argomenti opzionali e valori di default
Le funzioni possono avere parametri con valori predefiniti, rendendo alcuni argomenti opzionali:
def saluta(nome="Amico", messaggio="Benvenuto"):
print(f"{messaggio}, {nome}!")
saluta() # Benvenuto, Amico!
saluta("Luca") # Benvenuto, Luca!
saluta("Luca","Ciao")# Ciao, Luca!
Questo rende le funzioni più flessibili e applicabili in diversi contesti.
1.3 Funzioni con numero variabile di argomenti
In Python è possibile definire funzioni che accettano un numero variabile di argomenti usando *args
e **kwargs
:
def stampa_tutti(*args):
for arg in args:
print(arg)
def dettaglio(**kwargs):
for key, value in kwargs.items():
print(f"{key} = {value}")
stampa_tutti(1, 2, 3, "ciao")
# 1
# 2
# 3
# ciao
dettaglio(nome="Anna", età=30)
# nome = Anna
# età = 30
Queste funzioni sono molto utili nei casi in cui non si conosce in anticipo il numero di parametri da passare, oppure quando si vuole trasferire argomenti a un’altra funzione.
1.4 Funzioni anonime (lambda) e funzioni come oggetti
In Python, le funzioni sono a tutti gli effetti oggetti di prima classe. Ciò significa che possiamo assegnarle a variabili, passarle come argomenti e restituirle da altre funzioni. Le funzioni anonime – definite con la parola chiave lambda
– sono utili per operazioni rapide e inline:
quad = lambda x: x * x
print(quad(5)) # 25
def operazione(f, x):
return f(x)
print(operazione(lambda y: y + 10, 7)) # 17
Questo approccio apre la strada alla programmazione funzionale in Python, spesso utile nella manipolazione di collezioni di dati.
1.5 Modularizzazione e importazione di funzioni
Quando il progetto cresce, è importante suddividere il codice in moduli separati e importabili. Si crea un file Python (ad es. utils.py
) con funzioni che vogliamo riutilizzare:
# utils.py
def saluta(nome):
print(f"Benvenuto, {nome}!")
# main.py
import utils
utils.saluta("Marco")
In alternativa, possiamo importare singole funzioni:
from utils import saluta
saluta("Beatrice")
In questo modo il codice risulta più organizzato, modulare e manutenibile.
2. Moduli e librerie standard in Python
Uno dei punti di forza di Python è la quantità e qualità delle librerie incluse nella distribuzione standard, e la facilità con cui installare librerie esterne. In questa sezione esploreremo alcune librerie standard fondamentali, l’installazione di pacchetti esterni con pip
e come progettare i propri moduli.
2.1 Lavorare con i moduli standard
Python viene fornito con numerosi moduli integrati, per esempio:
os
– per interagire con il sistema operativo;sys
– per accedere a variabili e funzioni dell’interprete;math
– funzioni matematiche;datetime
– gestire date e orari;json
– serializzazione/deserializzazione JSON.
Ecco un esempio d’uso:
import os
print(os.getcwd()) # mostra la cartella corrente
import datetime
oggi = datetime.datetime.now()
print(oggi.strftime("%Y-%m-%d %H:%M:%S"))
2.2 Installazione di pacchetti esterni con pip
Per estendere le capacità di Python, si utilizzano pacchetti esterni installabili tramite il comando:
pip install nome_pacchetto
Ad esempio, per installare requests
(per le richieste HTTP):
pip install requests
Una volta installato, si può importare ed utilizzare facilmente:
import requests
response = requests.get("https://api.example.com/data")
print(response.json())
2.3 Creare e distribuire il proprio modulo
Supponiamo di voler creare un modulo personalizzato mio_modulo.py
:
# mio_modulo.py
def saluta(nome):
return f"Ciao, {nome}!"
# utilizzo in un altro file
import mio_modulo
print(mio_modulo.saluta("Luca")) # Ciao, Luca!
Per rendere disponibile il modulo anche su altri sistemi, è possibile impacchettarlo e pubblicarlo su PyPI
(Python Package Index) seguendo le best-practice ufficiali.
3. Strutture dati avanzate e manipolazione
Abbiamo già affrontato le strutture dati base – liste, tuple, set e dizionari – ma in questa lezione esploreremo come gestire collezioni più complesse, annidate, e come manipolarle efficacemente con comprensioni, generatori e iteratori.
3.1 Comprensioni di lista, set e dizionario
Le comprensioni consentono di costruire nuove collezioni in modo compatto e leggibile. Ecco alcuni esempi:
numeri = [1, 2, 3, 4, 5]
quad = [x * x for x in numeri]
print(quad) # [1, 4, 9, 16, 25]
frutta = ["mela","banana","ciliegia"]
frutta_iniziale = {f[0] for f in frutta}
print(frutta_iniziale) # {'m','b','c'}
nome_pi = {"nome":"Paolo","età":30}
upper_keys = {k.upper():v for k,v in nome_pi.items()}
print(upper_keys) # {'NOME':'Paolo','ETÀ':30}
3.2 Generatori e iteratori personalizzati
I generatori permettono di produrre sequenze “lazy”, ovvero generate su richiesta, e sono utili quando lavoriamo con grandi dataset. Ecco un semplice generatore:
def conta_fino(n):
i = 1
while i <= n:
yield i
i += 1
for num in conta_fino(5):
print(num)
# 1
# 2
# 3
# 4
# 5
È anche possibile creare speciali iteratori estendendo la classe __iter__
e __next__
:
class MioContatore:
def __init__(self, massimo):
self.massimo = massimo
self.conta = 0
def __iter__(self):
return self
def __next__(self):
if self.conta < self.massimo:
self.conta += 1
return self.conta
else:
raise StopIteration
for i in MioContatore(3):
print(i)
# 1
# 2
# 3
3.3 Manipolazione avanzata dei dizionari annidati
Quando lavoriamo con dati strutturati – ad esempio JSON complessi – è utile gestire dizionari annidati. Ecco un esempio di funzione che “appiattisce” un dizionario:
def appiattisci_dict(d, separatore='_', prefisso=''):
elementi = {}
for k, v in d.items():
nuovo_nome = f"{prefisso}{k}" if prefisso else k
if isinstance(v, dict):
elementi.update(appiattisci_dict(v, separatore, f"{nuovo_nome}{separatore}"))
else:
elementi[nuovo_nome] = v
return elementi
dati = {
"utente": {"nome":"Alice","info":{"età":28,"città":"Milano"}},
"ruolo":"editor"
}
print(appiattisci_dict(dati))
# {'utente_nome':'Alice','utente_info_età':28,'utente_info_città':'Milano','ruolo':'editor'}
4. Progetto pratico: Automatizzare un report via Python
Adesso mettiamo insieme quanto appreso per costruire un piccolo progetto pratico: un report automatico che legge file CSV, filtra dati, genera statistiche e salva un output in formato Excel o PDF. Questo tipo di attività è molto comune nelle startup, nel marketing o nell’analisi dati.
4.1 Requisiti e librerie necessarie
Prima di iniziare, installa le librerie necessarie:
pip install pandas openpyxl matplotlib
Qui sono coinvolte:
pandas
– per la manipolazione di dati tabellari;openpyxl
– per generare file Excel;matplotlib
– per realizzare grafici.
4.2 Caricare e filtrare i dati
Supponiamo di avere un file vendite.csv
con colonne: data, prodotto, quantità, prezzo_unitario, regione. Ecco come leggere e filtrare i dati:
import pandas as pd
df = pd.read_csv("vendite.csv", parse_dates=["data"])
# Filtriamo le vendite della regione “Nord” dopo il 2024-01-01
filtro = (df["regione"] == "Nord") & (df["data"] >= "2024-01-01")
df_filtrato = df.loc[filtro]
4.3 Generare statistiche e grafici
Calcoliamo alcune statistiche e generiamo un grafico di esempio:
# Totale vendite per prodotto
df_filtrato["totale"] = df_filtrato["quantità"] * df_filtrato["prezzo_unitario"]
statistiche = df_filtrato.groupby("prodotto")["totale"].sum().reset_index()
import matplotlib.pyplot as plt
plt.figure(figsize=(8,5))
plt.bar(statistiche["prodotto"], statistiche["totale"], color="skyblue")
plt.title("Totale vendite per prodotto – Regione Nord")
plt.xlabel("Prodotto")
plt.ylabel("Totale (€)")
plt.tight_layout()
plt.savefig("vendite_prodotti_nord.png")
4.4 Salvare l’output in Excel
import openpyxl
# Salviamo il DataFrame in un file Excel
df_filtrato.to_excel("report_vendite_nord.xlsx", index=False)
4.5 Automatizzare l’intero processo
Infine, possiamo costruire uno script Python che esegue tutti i passaggi in sequenza:
import pandas as pd
import matplotlib.pyplot as plt
def carica_dati(file_csv):
return pd.read_csv(file_csv, parse_dates=["data"])
def filtra_dati(df, regione, data_minima):
return df.loc[(df["regione"] == regione) & (df["data"] >= data_minima)]
def genera_statistiche(df):
df["totale"] = df["quantità"] * df["prezzo_unitario"]
return df.groupby("prodotto")["totale"].sum().reset_index()
def crea_grafico(statistiche, nome_file):
plt.figure(figsize=(8,5))
plt.bar(statistiche["prodotto"], statistiche["totale"], color="skyblue")
plt.title(f"Totale vendite per prodotto – {statistiche.shape[0]} prodotti")
plt.xlabel("Prodotto")
plt.ylabel("Totale (€)")
plt.tight_layout()
plt.savefig(nome_file)
def salva_excel(df, nome_file):
df.to_excel(nome_file, index=False)
def main():
df = carica_dati("vendite.csv")
df_f = filtra_dati(df, "Nord", "2024-01-01")
stat = genera_statistiche(df_f)
crea_grafico(stat, "grafico_vendite.png")
salva_excel(df_f, "report_vendite_nord.xlsx")
if __name__ == "__main__":
main()
Con questo script, è possibile eseguire in modo automatizzato un report completo – carico dati, filtraggio, calcolo, creazione grafico e salvataggio. Un ottimo esercizio per mettere in pratica funzioni, moduli, librerie e strutture dati avanzate.
5. Best practice e consigli per progetti reali
Quando si lavora su progetti reali con Python, è bene tenere a mente alcune best practice che migliorano qualità, manutenibilità e scalabilità del codice.
5.1 Organizzazione del progetto
Struttura il progetto in modo chiaro:
project/
│– src/
│ │– __init__.py
│ │– main.py
│ │– utils.py
│– data/
│ │– vendite.csv
│– outputs/
│ │– report_vendite_nord.xlsx
│ │– grafico_vendite.png
│– requirements.txt
│– README.md
In questo modo si separano i sorgenti, i dati, gli output e la documentazione.
5.2 Ambiente virtuale e dipendenze
Usa un ambiente virtuale per isolare le dipendenze del progetto:
python -m venv env
source env/bin/activate # su Linux/Mac
env\Scripts\activate # su Windows
pip install pandas openpyxl matplotlib
pip freeze > requirements.txt
Questo aiuta a mantenere coerenza e facilità di distribuzione.
5.3 Testing e documentazione
Anche per piccoli script è utile scrivere test e documentazione:
# test_utils.py
from utils import saluta
def test_saluta():
assert saluta("Luca") == "Ciao, Luca!"
Documenta le funzioni con docstring:
def saluta(nome):
"""
Restituisce un saluto personalizzato.
:param nome: stringa con il nome della persona
:return: stringa di saluto
"""
return f"Ciao, {nome}!"
5.4 Logging e gestione errori
Per applicazioni reali, gestire eccezioni e registrare i log è fondamentale:
import logging
logging.basicConfig(filename='app.log', level=logging.INFO)
def carica_dati(file_csv):
try:
df = pd.read_csv(file_csv, parse_dates=["data"])
logging.info(f"Dati caricati da {file_csv}")
return df
except Exception as e:
logging.error(f"Errore caricamento dati: {e}")
raise
Questo migliora la robustezza e la tracciabilità dell’applicazione.
6. Conclusione e passaggi successivi
In questa lezione abbiamo affrontato aspetti intermedi-avanzati di Python: funzioni modulare, moduli e librerie standard/esterni, strutture dati avanzate e un progetto pratico per automatizzare un report. Ora sei in grado di progettare script più complessi e organizzati.
I passaggi successivi per consolidare le competenze sono:
- Creare un piccolo progetto personale (es. analisi dati, automazione, web scraping) utilizzando funzioni e moduli;
- Scoprire librerie più specializzate (ad esempio
numpy
,scipy
,requests
,beautifulsoup4
); - Implementare test automatici, documentazione e packaging del proprio modulo;
- Ottimizzare prestazioni, gestire eccezioni, usare logging;
- Condividere il progetto su GitHub o PyPI per esercitarsi anche nella distribuzione del codice.