简体   繁体   中英

Convert “with” statement to “try” statement

I wonder how with statements work. I am trying to convert the following:

with obj() as o:
    do_something()

into this:

o = obj.__enter__()
try:
    do_something()
except Exception as e:
    obj.__exit__(type(e),e, **I don't know what should be here**)
else:
    obj.__exit__(None, None , None)

So how it will be? If I am wrong in anywhere, please correct me. I want to know what to replace the
**I don't know what should be here** with.

According to PEP-343 , which introduced context managers, the code

with obj() as o:
    do_something()

is equivalent to

mgr = obj()
exit = type(mgr).__exit__
value = type(mgr).__enter__(mgr)
exc = True

try:
    try:
        o = value
        do_something()
    except:
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
finally:
    if exc:
        exit(mgr, None, None, None)

Some notes:

  1. We don't write o = type(mgr).__enter__(mgr) because the name o is only defined if __enter__ does not raise an exception, allowing us to enter the try statement at all. (There are other ways to handle this, but this is how I interpret PEP-343's translation.)
  2. __exit__ can be called in two different places. If we catch an exception, we pass information about that to __exit__ , which can prevent the calling code from seeing it if it returns True .
  3. The finally block ensures that __exit__ is called exactly once. Namely, we want to call it if no exceptions were raised, but not again if the first call swallowed an exception by returning True or raised an exception itself.

If just as a learning experiment this is fine. I don't think it shouldn't actually be used. You generally shouldn't need to call Python's magic methods directly.

You really want to call __exit__ in a finally block. The three arguments that you want to provide to __exit__ can be obtained by calling sys.exc_info .

import sys

o = obj.__enter__()
try:
    do_something()
finally:
    obj.__exit__(*sys.exc_info())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM