[Python-Dev] PEP 343 - multiple context managers in one statement
Nick Coghlan
ncoghlan at gmail.com
Wed Oct 26 00:20:50 CEST 2005
Paul Moore wrote:
> I have a deep suspicion that this has been done to death already, but
> my searching ability isn't up to finding the reference. So I'll simply
> ask the question, and not offer a long discussion:
>
> Has the option of letting the with statement admit multiple context
> managers been considered (and presumably rejected)?
>
> I'm thinking of
>
> with expr1, expr2, expr3:
> # whatever
Not rejected - deliberately left as a future option (this is the reason why
the RHS of an as clause has to be parenthesised if you want tuple unpacking).
> In some ways, this doesn't even need an extension to the PEP - giving
> tuples suitable __enter__ and __exit__ methods would do it. Or, I
> suppose a user-defined manager which combined a list of others:
>
> class combining:
> def __init__(*mgrs):
> self.mgrs = mgrs
> def __with__(self):
> return self
> def __enter__(self):
> return tuple(mgr.__enter__() for mgr in self.mgrs)
> def __exit__(self, type, value, tb):
> # first in, last out
> for mgr in reversed(self.mgrs):
> mgr.__exit__(type, value, tb)
>
> Would that be worth using as an example in the PEP?
The issue with that implementation is that the semantics are wrong - it
doesn't actually mirror *nested* with statements. If one of the later
__enter__ methods, or one of the first-executed __exit__ methods throws an
exception, there are a lot of __exit__ methods that get skipped.
Getting it right is more complicated (and this probably still has mistakes):
class nested(object):
def __init__(*mgrs):
self.mgrs = mgrs
self.entered = None
def __context__(self):
return self
def __enter__(self):
self.entered = deque()
vars = []
try:
for mgr in self.mgrs:
var = mgr.__enter__()
self.entered.push_front(mgr)
vars.append(var)
except:
self.__exit__(*sys.exc_info())
raise
return vars
def __exit__(self, *exc_info):
# first in, last out
# Behave like nested with statements
ex = exc_info
for mgr in self.entered:
try:
mgr.__exit__(*ex)
except:
ex = sys.exc_info()
if ex is not exc_info:
raise ex[0], ex[1], ex[2]
> PS The signature of __with__ in example 4 in the PEP is wrong - it has
> an incorrect "lock" parameter.
Thanks - I'll fix that when I incorporate the resolutions of the open issues
(which will be post the SVN migration).
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.blogspot.com
More information about the Python-Dev
mailing list