Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python exception handling inside with block

Is the following code doing anything wrong with with statement and exception handling of python3? If no, what is the correct way of writing my expected output?

from contextlib import contextmanager

@contextmanager
def test():
    print("Hello")
    yield
    print("goodbye")

try:
    with test():
        print("inside test")
        raise KeyError
except KeyError:
    print("KeyError")
else:
    print("else")
finally:
    print("finally")

and the output is

Hello
inside test
KeyError
finally

and I expect the output is:

Hello
inside test
goodbye
KeyError
finally

which I believe other people write similarly in the hope that the file would be closed when an exception was raised during the processing of the file.

My python3 version is:

Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print(sys.version)
3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609]
like image 942
wh0 Avatar asked Jun 06 '18 08:06

wh0


People also ask

What are the blocks used in exception handling in Python?

The except block lets you handle the error. The else block lets you execute code when there is no error. The finally block lets you execute code, regardless of the result of the try- and except blocks.

What happens if an exception occurs inside a try block?

When an exception occurs inside a try block, control goes directly to the catch block, so no other code will be executed inside the try block and the value of res will not change. Also when a method throws an exception it does not return anything.

Can we have multiple except blocks while handling exceptions?

In Python, try-except blocks can be used to catch and respond to one or multiple exceptions. In cases where a process raises more than one possible exception, they can all be handled using a single except clause.


1 Answers

The exception from within the block governed by the with statement is propagated to your generator context manager through generator.throw() as shown in PEP 343: "Generator Decorator", which raises the exception at the point where the generator was paused. In other words you should wrap the yield in a try/except or try/finally:

@contextmanager
def test():
    print("Hello")
    try:
        # The block of the with statement executes when the generator yields
        yield

    finally:
        print("goodbye")

To quote the official documentation on the subject:

...If an unhandled exception occurs in the block, it is reraised inside the generator at the point where the yield occurred. Thus, you can use a try…except…finally statement to trap the error (if any), or ensure that some cleanup takes place. If an exception is trapped merely in order to log it or to perform some action (rather than to suppress it entirely), the generator must reraise that exception. Otherwise the generator context manager will indicate to the with statement that the exception has been handled, and execution will resume with the statement immediately following the with statement.

like image 63
Ilja Everilä Avatar answered Oct 22 '22 05:10

Ilja Everilä