2021年1月2日星期六

How does python contextmanager reraise an exception back into the decorated generator?

This is a question about how contextmanager does what it does, from python language's perspective.

contextmanger is a decorator that calls the decorated function (a generator) twice, in order to build the __enter__ and __exit__ functions, to be consumed by the with clause, so far so good. What I do not understand is -- when an exception is raised inside the with block, how come an except block inside the generator can catch it?

@contextmanager  def f():      try:          yield 'foo'      except Exception as e:          print('How can I ever reach here??')          print(e)      finally:          print('finally')    with f() as p:      print(p)      raise Exception('bar')  

output is

foo  How can I ever reach here??  bar  finally  

I think the magic happens in the @contextmanager, becuase if I remove the decorator, and just do a 'yield inside try block', the exception outside the generator is not caught inside the generator:

def f():      try:          yield 'foo'      except Exception as e:          print('How can I ever reach here??')          print(e)      finally:          print('finally')    g = f()  print(next(g))  raise Exception('bar')  

output is

foo  Traceback (most recent call last):  ...  Exception: bar  

I looked into the contextlib.contextmanager code but still couldn't figure out how this is even possible using pure python code. Something fundamental about the language I missed here?

https://stackoverflow.com/questions/65546002/how-does-python-contextmanager-reraise-an-exception-back-into-the-decorated-gene January 03, 2021 at 10:05AM

没有评论:

发表评论