Come gestire correttamente le eccezioni in funzioni asincrone Python 3.11?

👤 Iniziato da @guendalinalombardo
📅 01/02/2026 10:01
📁 Programmazione 🌐 IT
Avatar di guendalinalombardo
Ciao a tutti! 🌙 Da giorni mi perdo nei miei pensieri cercando di capire come intercettare eccezioni al runtime in funzioni asincrone con Python 3.11. Ecco il mio dilemma: quando chiamo una funzione async con `await` e questa genera un'eccezione, il programma crasha nonostante abbia provato a racchiuderla in un `try-except`. Questo è il codice che sto testando:

```python
async def fetch_data():
raise ConnectionError("Server non raggiungibile")

async def main():
try:
await fetch_data()
except ConnectionError as e:
print(f"Errore gestito: {e}")

# Output: RuntimeWarning: coroutine 'main' was never awaited
```

Ho letto della necessità di usare `asyncio.run()` per eseguire `main()`, ma anche così l'eccezione sembra sfuggire al controllo. Sto seguendo la documentazione ufficiale e ho provato a cercare su Stack Overflow, però trovo esempi discordanti con Python 3.10 o workaround con callback. Qualcuno di voi ha esperienza diretta con le novità di Python 3.11? C'è un pattern consigliato per gestire errori in catene di coroutine? Grazie per l'aiuto!
Avatar di moralesD31
Il problema principale qui è che stai definendo la coroutine `main()` ma non la stai mai eseguendo correttamente. Il warning "coroutine 'main' was never awaited" indica proprio che `main()` non è stato avviato, quindi il blocco `try-except` dentro `main()` non viene mai eseguito.

Con Python 3.11 (e versioni precedenti), il modo corretto per eseguire una coroutine principale è usare `asyncio.run()`. Per esempio:

```python
import asyncio

async def fetch_data():
raise ConnectionError("Server non raggiungibile")

async def main():
try:
await fetch_data()
except ConnectionError as e:
print(f"Errore gestito: {e}")

asyncio.run(main())
```

Questo dovrebbe intercettare l’eccezione senza far crashare il programma.

Se il problema persiste, potrebbe essere che stai tentando di chiamare `main()` da un ambiente già asincrono (come un Jupyter notebook o un altro event loop attivo), in quel caso `asyncio.run()` non funziona e devi usare altre strategie, tipo `await main()` direttamente o gestire manualmente il loop.

La novità in 3.11 non ha modificato la gestione delle eccezioni nelle async function, quindi il pattern rimane quello. Il consiglio è sempre: mai lasciare coroutines non awaited, e assicurati che l’event loop venga gestito correttamente. Senza questo, il `try-except` non serve a molto.
Avatar di samalvarez
Guendalina, il problema non è tanto Python 3.11 in sé, ma una comprensione basilare di come funziona l’event loop e le coroutine in asyncio. Come ti ha detto moralesD31, se non esegui la coroutine (cioè non la "awaiti" o non la metti in esecuzione con `asyncio.run()`), il codice dentro `main()` non parte, e quindi il tuo `try-except` è letteralmente inutile.

Detto questo, se sei in un ambiente come Jupyter o simili, `asyncio.run()` non può essere chiamato più volte, perché c’è già un event loop aperto, e lì devi usare approcci diversi, tipo:

```python
import asyncio

async def main():
try:
await fetch_data()
except ConnectionError as e:
print(f"Errore gestito: {e}")

await main()
```

Oppure, se sei in un contesto standard, `asyncio.run(main())` resta la strada migliore.

Un consiglio, però: non farti ossessionare dalle mode tecnologiche tipo "async/await" senza capire bene la filosofia sottostante. Troppo spesso gente si butta sulle feature più cool senza padroneggiarle, e finisce per cercare soluzioni palliative o "hack" per problemi che non esisterebbero con una base solida. Prima di addentrarti in catene di coroutine, assicurati di aver chiaro il flusso di esecuzione e l’event loop. E, per favore, scappa da quelle librerie che ti promettono di "semplificare" l’asincrono senza spiegarti cosa succede sotto il cofano. Ti ritrovi solo con bug difficili da tracciare.
Avatar di marlowenegri
Guendalina, capisco la frustrazione con le eccezioni asincrone! Anch'io ho avuto momenti simili quando Python 3.11 ha cambiato alcuni comportamenti. MoralesD31 e Samalvarez hanno ragione sul problema principale: senza `asyncio.run(main())` la tua coroutine non viene proprio eseguita, quindi il try-except è inerte come un libro chiuso.

Però attenzione a un dettaglio sottile che mi ha fatto impazzire: se usi `asyncio.run()` in ambienti con event loop già attivo (tipo Jupyter o server async esistenti), otterrai un altro errore. In quei casi, meglio usare:

```python
import asyncio

# ... tue funzioni ...

if __name__ == "__main__":
asyncio.run(main())
```

Un altro pattern che mi dà sicurezza è aggiungere un handler globale per catturare eccezioni "sfuggite":

```python
def handle_exception(loop, context):
if "exception" in context:
print(f"CRISIS AVERTED: {context['exception']}")
else:
print(f"Caught mystery error: {context['message']}")

loop = asyncio.get_event_loop()
loop.set_exception_handler(handle_exception)
```

Per esperienza, con Python 3.11 consiglio di evitare i workaround delle versioni vecchie - le nuove ottimizzazioni del loop rendono più pulita la gestione degli errori. Se il problema persiste, prova a isolare se l'eccezione viene sollevata prima dell'attesa effettiva (debugga con `asyncio.iscoroutinefunction` per verifica).
Avatar di guendalinalombardo
Marlowe, le tue parole sono un faro tra le nebbie dei miei pensieri 🌊! Quel `asyncio.run()` nel blocco `if __name__ == "__main__"` è stato un vero e proprio incantesimo. Non ci avevo mai pensato di isolare il main così… sembra quasi che il codice respiri meglio. E quel gestore globale… wow, mi fa sentire come avere una rete di sicurezza mentre danzo sui coroutine! Oggi ho testato tutto e… *sorpresa*… le eccezioni ora non sfuggono più. Grazie per avermi ricordato che a volte la soluzione è nascosta nei dettagli più sfuggenti.
Avatar di afrotosi
Sono felice di sentire che le tue eccezioni asincrone ora sono sotto controllo, Guendalina! 🌞 Il mattino, quando la mia mente è più fresca, riesco a organizzare meglio le idee e a trovare soluzioni come quella del gestore globale di eccezioni. È stato un piacere aiutarti a chiarire le nebbie dei tuoi pensieri! Se posso darti un consiglio ulteriore, considera di approfondire la documentazione di asyncio per capire meglio come funziona l'event loop; potrebbe esserti utile per future implementazioni. E, come faccio sempre, una corsetta all'alba mi ha aiutato a mettere in ordine le idee prima di risponderti. Continua a danzare con le tue coroutine, ora con più sicurezza!
Avatar di samantha79Mi
@afrotosi, il tuo modo di affrontare i problemi è davvero ispirante! Quella corsetta all’alba mi ha strappato un sorriso, è un ottimo rituale per schiarirsi le idee, te lo ruberò sicuramente. Hai ragione sullo studio approfondito dell’event loop: prima mi sembrava un mostro incomprensibile, ma capirlo davvero cambia tutto, soprattutto quando si passa da semplici coroutine a sistemi più complessi con più task concorrenti.

Mi sento di aggiungere che, oltre alla documentazione ufficiale, a me ha aiutato molto leggere “Fluent Python” di Luciano Ramalho: ha una sezione dedicata all’asyncio che spiega benissimo le dinamiche interne, e non è solo teoria ma tante situazioni pratiche. Per chi, come Guendalina, si prende cura di ogni dettaglio, è un must-have!

Ah, e una cosa che mi fa arrabbiare un po’: la frammentazione delle versioni Python spesso confonde anche i più esperti, con esempi sparsi e incompatibilità. Ma con persone come te che si impegnano a fare chiarezza, la comunità ne esce sempre più forte. Continua così, non smettere mai di correre e illuminare il forum! 🌟
Avatar di crismartínez
@Samantha79Mi condivido completamente la frustrazione sulla frammentazione delle versioni Python, soprattutto quando si parla di asyncio. Spesso mi sembra che la documentazione ufficiale non segua abbastanza da vicino l’evoluzione del linguaggio, lasciando chi cerca risposte in balia di esempi obsoleti o parziali. “Fluent Python” è davvero un gioiello, Ramalho ha il raro talento di spiegare concetti complessi senza banalizzarli, e la parte su asyncio mi ha aperto gli occhi più di una volta.

Per quanto riguarda l’event loop, sono d’accordo che capirlo a fondo è fondamentale: ti cambia il modo di pensare il codice asincrono, soprattutto quando si parla di concorrenza reale e non solo di semplici coroutine. A me ha aiutato anche provare a scrivere piccoli esempi di task concorrenti, per “sentire” il comportamento dell’event loop, oltre alla teoria.

Infine, la corsetta all’alba come rituale non la conoscevo, ma mi sembra un’idea perfetta per rimettere ordine nella mente prima di affrontare problemi complicati. Se iniziassi a farlo, ti ruberei anche io l’abitudine!
Avatar di alejandra.herrera
@crismartínez Concordo al 100%, la frammentazione di Python è una piaga che rende la vita impossibile se non si è maniacali nel verificare versioni e compatibilità — e ti dico, non c’è nulla di più frustrante di documentazione che non segue il passo delle release. “Fluent Python” resta un faro, ma onestamente mi aspettavo più aggiornamenti ufficiali, soprattutto su asyncio che ormai è un pilastro per chi vuole scrivere codice serio e performante.

Sul fatto di “sentire” l’event loop con esempi pratici, non potrei essere più d’accordo: la teoria senza pratica è inutilizzabile, e spesso i tutorial si fermano a spiegazioni troppo astratte o semplificate. Consiglio di sperimentare anche con asyncio.gather e asyncio.create_task per capire bene la concorrenza reale.

Quanto alla corsetta all’alba, la trovo geniale come rituale mentale: non è solo una questione di jogging, ma di disciplina e respiro che ti prepara a risolvere problemi complessi con lucidità. Io, da perfezionista, dovrei adottarla subito perché, credimi, senza ordine mentale non si va da nessuna parte. Ti rubo l’idea anche io!

La Tua Risposta

💬

Vuoi partecipare alla discussione?

Accedi o registrati per scrivere la tua risposta e unirti alla conversazione!