Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between throwing GeneratorExit and calling close() in python

Thank you for opening my question. I tried to make my question clear but if there are still unclear parts because of my English, please let me know.

I am studying on Python coroutine and have read that calling a close() method on generator is similar to throwing GeneratorExit to the generator. So I tried like below.

def gen(n):
    while True:
        yield n

test = gen(10)
next(test)
test.throw(GeneratorExit)

Then GeneratorExit exception occurred. However when I tried test.close(), it did not raise any exception.

So I modified above code slightly;

def gen(n):
    while True:
        try:
            yield n
        except GeneratorExit:
            break
test = gen(10)
next(test)
test.throw(GeneratorExit)

As GeneratorExit was handled, it was not raised but StopIteration exception occurred. I understand that if there is no more yield, StopIteration exception rises. However it was not raised when I tried test.close() again with the modified code.

Could you let me know what the difference between throwing GeneratorExit and calling close() method is?

To be more precise, I can understand why StopIteration and GeneratorExit exception occur with test.throw(GeneratorExit) but don't know why those exceptions are not raised when using test.close()

Thanks.

like image 862
JUSEOK KO Avatar asked Jan 21 '26 09:01

JUSEOK KO


1 Answers

GeneratorExit occurs in one of two cases:

  • When you're calling close
  • When python calls the garbage collector for that generator.

(see the documentation)

You can see that in the following code:

def gen(n):
    while True:
        try:
            yield n
        except GeneratorExit:
            print("gen caught a GeneratorExit exception")
            break # (throws a StopIteration exception)

def gen_rte(n):
    while True:
        try:
            yield n
        except GeneratorExit:
            print("gen_rte caught a GeneratorExit exception")
            # No break here - we'll get a runtime exception

test = gen(10)
print(next(test))
==> 10

test.close()
==> gen caught a GeneratorExit exception  


test = gen(15)
print(next(test))
==> 15
test.throw(GeneratorExit)

==> gen caught a GeneratorExit exception Traceback (most recent call last): File "...", line 20, in test.throw(GeneratorExit) StopIteration (this is the result of the 'break' statement

test = gen_rte(20)
print(next(test))
==> 20

test.close()
==> 
    gen_rte caught a GeneratorExit exception
    Traceback (most recent call last):
      File "...", line 24, in <module>
        test.close()
    RuntimeError: generator ignored GeneratorExit

Finally, there's another GeneratorExit exception before the program ends - I believe it's a result of the garbage collector. gen_rte caught a GeneratorExit exception Exception ignored in: RuntimeError: generator ignored GeneratorExit

like image 84
Roy2012 Avatar answered Jan 23 '26 00:01

Roy2012