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?
没有评论:
发表评论