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

Phillip J. Eby pje at telecommunity.com
Wed Apr 26 05:29:46 CEST 2006


At 08:09 PM 4/25/2006 -0700, Guido van Rossum wrote:
>On 4/25/06, Phillip J. Eby <pje at telecommunity.com> wrote:
> > At 05:20 PM 4/25/2006 -0700, Guido van Rossum wrote:
> > >I would augment #1 to clarify that if you have __enter__ and __exit__
> > >you may not have __context__ at all; if you have all three,
> > >__context__ must return self.
> >
> > Well, requiring the __context__ allows us to ditch the otherwise complex
> > problem of why @contextfactory functions' return value is usable by "with",
> > without having to explain it separately.
>
>Really? I thought that that was due to the magic in the decorator (and
>in the class it uses).

Actually, I got that explanation backwards above.  What I meant is that the 
hard thing to explain is why you can use @contextfactory to define a 
__context__ method.  All other examples of @contextfactory are perfectly 
fine, it's only the fact that you can use it to define a __context__ method.

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.


>But that *still* doesn't explain why we are recommending that
>everything providing __enter__/__exit__ must also provide __context__!

Because it means that users never have to worry about which kind of object 
they have.  Either you pass a 1-method object to "with", or a 3-method 
object to "with".  If you have a 2-method object, you can never pass it to 
"with".

Here's the thing: you're going to have 1-method objects and you're going to 
have 3-method objects, we know that.  But the only time a 2-method object 
is useful is if it's a tag-along to a 1-method object.  It's easier from a 
documentation perspective to just say "you can have one method or three", 
and not get into this whole "well, you can also have two, but only if you 
use it with a one".  And if you rule out the existence of the two-method 
variant, you don't have to veer into any complex questions of when you 
should use three methods instead of two, because the answer is simply 
"always use three".

This isn't a technical problem, in other words.  I had exactly the same POV 
as you on this until I read enough of Nick's rants on the subject to 
finally see it from the education perspective; it's easier to explain two 
things, one of which is a subtype of the other, versus explaining two 
orthogonal things that sometimes go together and sometimes don't, and the 
reasons that you might or might not want to put them together are tricky to 
explain.

Of course, this approach opens a new hole, which is how to deal with people 
asking "why does it have to have a __context__ method if it's never 
called".  So far, Nick's answer is "because we said so" (aka "deliberate 
design decision"), which isn't great, but at least it's honest.  :)



More information about the Python-Dev mailing list