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