[Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body
Nick Coghlan
ncoghlan at gmail.com
Sun Mar 15 21:40:00 CET 2009
Nick Coghlan wrote:
> Rough spec for the concept:
>
> Implementing __enter__/__exit__ on a CM would work as per PEP 343.
>
> Implementing __with__ instead would give the CM complete control over
> whether or not to execute the block.
>
> The implementation of contextlib.GeneratorContextManager would then
> change so that instead of providing __enter__/__exit__ as it does now it
> would instead provide __with__ as follows:
Expansion in the previous message wasn't quite right since it didn't
give the executed block access to the result of __enter__().
Mark II:
def __with__(self, exec_block):
try:
enter_result = self.gen.next()
except StopIteration:
pass
else:
try:
exec_block(enter_result)
except:
exc_type, value, traceback = sys.exc_info()
try:
self.gen.throw(type, value, traceback)
raise RuntimeError("generator didn't stop after throw()")
except StopIteration, exc:
# Suppress the exception *unless* it's the same exception that
# was passed to throw(). This prevents a StopIteration
# raised inside the "with" statement from being suppressed
return exc is not value
except:
# only re-raise if it's *not* the exception that was
# passed to throw(), because __exit__() must not raise
# an exception unless __exit__() itself failed. But throw()
# has to raise the exception to signal propagation, so this
# fixes the impedance mismatch between the throw() protocol
# and the __exit__() protocol.
if sys.exc_info()[1] is not value:
raise
else:
try:
self.gen.next()
except StopIteration:
return
else:
raise RuntimeError("generator didn't stop")
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
More information about the Python-Dev
mailing list