[Python-Dev] Must objects with __enter__/__exit__ also supply __context__?

Nick Coghlan ncoghlan at gmail.com
Wed Apr 26 11:53:38 CEST 2006

Guido van Rossum wrote:
> I'm not convinced.

Phillip managed to capture most of my reasons for documenting it that way. 
However, trying to find a better term than the "with statement context" phrase 
used in the latest docs is causing me to have doubts.

The term I'm currently favouring is "managed context" because of the obvious 
relationship with "context manager". But with the current documentation, it's 
potentially unclear which object is doing the managing, as all managed 
contexts are required to serve as context managers as well. So the term ends 
up potentially a little confusing (is the manager of a managed context the 
original context manager, or the managed context itself?). I'd have to 
actually try it out to see if the terminology could be kept clear.

OTOH, if the two protocols are made orthogonal, then it's clear that the 
manager is always the original object with the __context__ method. Then the 
three cases are:

  - a pure context manager (only provides __context__)
  - a pure managed context (only provides __enter__/__exit__)
  - a managed context which can be its own context manager (provides all three)

In the standard library, decimal.Context and threading.Condition would be 
examples of the first, decimal.ManagedContext would be an example of the 
second, and contextlib.GeneratorContext, contextlib.closing, files and the 
various threading module lock objects would be examples of the third.

The final thing that occurred to me is that if we do find a use case for 
mixing and matching context managers and managed contexts, it would be easy 
enough to add a function to contextlib to assist in doing so:

     class SimpleContextManager(object):
         def __init__(ctx):
             self.context = ctx
         def __context__(self):
             return self.context

     def contextmanager(obj):
         if hasattr(obj, "__context__"):
             return obj
         if hasattr(obj, "__enter__") and hasattr(obj, "__exit__"):
             return SimpleContextManager(obj)
         raise TypeError("Require a context manager or a managed context")

The ability to add that function if we eventually decide we need it means that 
we don't have to worry about inadvertently ruling out use cases we simply 
haven't thought of yet (which was one of my concerns).

Since I can supply reasonable answers to all of my earlier reservations, I now 
believe we could drop this requirement and still end up with comprehensible 

Whether it's a good idea to do so. . . I'm not sure. I still quite like the 
idea of having to describe only two kinds of object instead of three, but 
making the protocols orthogonal has its merits, too.


> On 4/25/06, Phillip J. Eby <pje at telecommunity.com> wrote:
>> At 11:29 PM 4/25/2006 -0400, Phillip J. Eby wrote:
>>> See, if @contextfactory functions return a thing *with* a __context__
>>> method, how is that usable with "with"?  It isn't, unless the thing also
>>> happens to have __enter__/__exit__ methods.  This was the hole in the
>>> documentation that caused Nick to seek to revisit the decorator name in the
>>> first place.
>> Argh.  I seem to be tongue-tied this evening.  What I mean is, if
>> @contextfactory functions' return value is usable as a "with" expression,
>> that means it must have a __context__ method.  But, if you are using
>> @contextfactory to *define* a __context__ method, the return value should
>> clearly have __enter__ and __exit__ methods.
>> What this means is that if we describe the one method and the two methods
>> as independent things, there is no *single* name we can use to describe the
>> return value of a @contextfactory function.  It's a wave and a particle, so
>> we either have to start talking about "wavicles" or have some detailed
>> explanation of why @contextfactory function return values are both waves
>> and particles at the same time.
>> However, if we say that particles are a kind of wave, and have all the same
>> features as waves but just add a few others, then we can simply say
>> @contextfactory functions return particles, and the waviness is implied,
>> and all is right in the world.  At least, until AMK comes along and asks
>> why you can't separate the particleness from the waveness, which was what
>> started this whole thing in the first place...  :)
> --
> --Guido van Rossum (home page: http://www.python.org/~guido/)
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/ncoghlan%40gmail.com

Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-Dev mailing list