[Python-Dev] PEP 343 and __with__
Nick Coghlan
ncoghlan at gmail.com
Tue Oct 4 12:21:43 CEST 2005
Jason Orendorff wrote:
> Phillip J. Eby writes:
>
>>You didn't offer any reasons why this would be useful and/or good.
>
>
> It makes it dramatically easier to write Python classes that correctly
> support 'with'. I don't see any simple way to do this under PEP 343;
> the only sane thing to do is write a separate @contextmanager
> generator, as all of the examples do.
Hmm, it's kind of like the iterable/iterator distinction. Being able to do:
class Whatever(object):
def __iter__(self):
for item in self.stuff:
yield item
is a very handy way of defining "this is how you iterate over this class". The
only cost is that actual iterators then need to define an __iter__ method that
returns 'self' (which isn't much of a cost, and is trivial to do even for
iterators written in C).
If there was a __with__ slot, then we could consider that as identifying a
"manageable context", with three methods to identify an actual context manager:
__with__ that returns self
__enter__
__exit__
Then the explanation of what a with statement does would simply look like:
abc = EXPR.__with__() # This is the only change
exc = (None, None, None)
VAR = abc.__enter__()
try:
try:
BLOCK
except:
exc = sys.exc_info()
raise
finally:
abc.__exit__(*exc)
And the context management for decimal.Context would look like:
class Context:
...
@contextmanager
def __with__(self):
old = decimal.getcontext()
new = self.copy() # Make this nesting and thread safe
decimal.setcontext(new)
try:
yield new
finally:
decimal.setcontext(old)
And for threading.Lock would look like:
class Lock:
...
def __with__(self):
return self
def __enter__(self):
self.acquire()
return self
def __exit__(self):
self.release()
Also, any class could make an existing independent context manager (such as
'closing') its native context manager as follows:
class SomethingCloseable:
...
def __with__(self):
return closing(self)
> As for the second proposal, I was thinking we'd have one mental model
> for context managers (block template generators), rather than two
> (generators vs. enter/exit methods). Enter/exit seemed superfluous,
> given the examples in the PEP.
Try to explain the semantics of the with statement without referring to the
__enter__ and __exit__ methods, and then see if you still think they're
superfluous ;)
The @contextmanager generator decorator is just syntactic sugar for writing
duck-typed context managers - the semantics of the with statement itself can
only be explained in terms of the __enter__ and __exit__ methods. Indeed,
explaining how the @contextmanager decorator itself works requires recourse to
the __enter__ and __exit__ methods of the actual context manager object the
decorator produces.
However, I think the idea of have a distinction between manageable contexts
and context managers similar to the distinction between iterables and
iterators is one well worth considering.
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.blogspot.com
More information about the Python-Dev
mailing list