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

_______________________________________________
Python mailing list
Python@lists.python.it
https://lists.python.it/mailman/listinfo/python

Rispondere a