[Python] throw ad un generatore: perché non riparte dall'inizio?
Marco Giusti
marco.giusti a posteo.de
Gio 28 Lug 2022 09:37:21 CEST
On 28.07.2022 08:56, Marco De Paoli wrote:
> ciao lista!
> ho una domanda sui generatori
> Mi farebbe molto comodo usare la possibilità di mandare una eccezione
> ad un generatore: ma mi trovo con un comportamento imprevisto
> Qui sotto trovate un frammento di codice che riproduce una sorta di
> "caso minimo" di quella che mi sembra una anomalia
> Se avete voglia di provarlo credo che il codice sia più o meno
> autoesplicativo.
> Quello che mi lascia perplesso è: perché il generatore, dopo aver
> gestito l'eccezione, non riparte dal restituire il valore "A"?
Ciao Marco,
ho aggiunto qualche print in piu' e come vedi dopo aver lanciato
l'eccezione,
due print sono eseguite prima di produrre il valore "A". Quello che
sospetto
sia il flusso di esecuzione e' il seguente.
1. un'eccezione e' lanciata all'interno del generatore, il flusso
ritorna
all'inizio del ciclo. La prima print e' eseguita cosi' come la prima
yield;
2. fuori dal generatore il codice non consuma il valore generato usando
una
chiamata a "next", ma invece manda un altro valore (None) usando una
send.
Il generatore avanza, genera il valore "B" e questo e' il valore di
ritorno
della send e quello che viene stampato a schermo.
Questa e' una presentazione [1] che lessi tempo addietro. La trovai
illuminante
all'epoca e trovo che sia sempre attuale. Questa e' la slide 31:
* Despite some similarities, Generators and
coroutines are basically two different concepts
* Generators produce values
* Coroutines tend to consume values
* It is easy to get sidetracked because methods
meant for coroutines are sometimes described as
a way to tweak generators that are in the process
of producing an iteration pattern (i.e., resetting its
value). This is mostly bogus.
La slide 32 e' similare al tuo esempio, e come vedi un valore e' perso
esattamente come nel tuo caso.
Spero di essere stato d'aiuto.
Marco
[1] http://www.dabeaz.com/coroutines/Coroutines.pdf
# test_gen.py
def gen():
while True:
print("begin of the loop")
try:
print("before the first yield")
yield "A"
print("after the first yield")
yield "B"
yield "C"
except Exception as ex:
print("catched exception", ex)
g = gen()
you_can_specify_any_number_of_steps = 3
for idx in range(you_can_specify_any_number_of_steps):
print("result:", g.send(None))
print("throw...")
g.throw(Exception("BOOM"))
print("result:", g.send(None), "*** I was expecting A and I get B,
why?!? ***")
print("result:", g.send(None))
# output
$ python3.10 test_gen.py
begin of the loop
before the first yield
result: A
after the first yield
result: B
result: C
throw...
catched exception BOOM
begin of the loop
before the first yield
after the first yield
result: B *** I was expecting A and I get B, why?!? ***
result: C
Maggiori informazioni sulla lista
Python