[Python-Dev] Why are contexts also managers? (was r45544 - peps/trunk/pep-0343.txt) (original) (raw)

Paul Moore p.f.moore at gmail.com
Sat Apr 22 13:40:49 CEST 2006


On 4/22/06, Nick Coghlan <ncoghlan at gmail.com> wrote:

Alternatively, I could have a go at clearing it up for next week's alpha2, and we can ask Anthony to make an explicit request for review of those docs in the announcement. . .

I've just had a very quick scan through the 2.5a1 documentation. I did not look at the PEP, just the official documentation. I've been reading the messages going round on the subject, but I'm getting pretty confused, so I'd still count myself as "unprejudiced"... :-)

My immediate reaction was that the docs make reasonable sense:

The contextlib.contextmanager decorator starts off looking fine as well:

@contextmanager def tag(name): print "<%s>" % name yield print "</%s>" % name

Yes, that's a context manager - you pass it to a with statement:

with tag("h1"): ... print "foo" ...

foo

But then things go wrong:

class Tag: def init(self, name): self.name = name

@contextmanager
def __context__(self):
    print "<%s>" % self.name
    yield self
    print "</%s>" % self.name

h1 = Tag("h1")

That's bizarre: context isn't the context manager I'm trying to create - those are the instances of Tag. I think this is where the terminology comes unstuck, and it's simply because this is an "abuse" (a bit strong, that - bear with me) of the contextmanager decorator.

The thing is, context should be a function which returns a context. But we defined it with the decorator as a context manager - an object whose context method produces a context! It works, because context managers produced by the decorator return themselves - that is, they are both context managers and contexts....... No, I just got lost.

BUT - the point is that everything was fine until the point where the context method got defined using @contextmanager. Maybe all we need is to have two decorators - @context to generate a context (this would be @contextmanager but without the context method) and @contextmanager as now (actually, it only needs the context method

Then, the definitions are easy:

context manager - has context producing a context context - has enter and exit methods, used by the with statement

Things with all 3 methods are just a convenience trick to avoid defining 2 objects - there's no need for them (unlike iterators, where "iter(it) is it" is an important defining characteristic of an iterator over an iterable).

So my proposal:

Or alternatively, I'm just confused, like the rest of you :-)

Paul.



More information about the Python-Dev mailing list