[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
- Previous message: [Python-Dev] Why are contexts also managers? (was r45544 - peps/trunk/pep-0343.txt)
- Next message: [Python-Dev] Why are contexts also managers? (was r45544 - peps/trunk/pep-0343.txt)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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:
- a context is a thing with enter/exit methods (a block of code is "in" a context)
- the with statement delimits the block which is in a context
- the with statement asks a context manager for the context in which the block runs
- context managers have context methods to produce contexts (they manage the production of explicit context objects)
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
- the enter and exit methods are only present to allow the trick of returning self from context).
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:
- use the definitions above
- modify contextlib to have 2 decorators - @contextmanager producing a context manager, and @context producing a context. They can be the same under the hood, using an object that defines all 3 methods, but that's just an implementation detail (trick)
- amend the documentation of the Tag example in the contextlib docs to use the @context decorator.
- tidy up the PEP to reflect this approach
Or alternatively, I'm just confused, like the rest of you :-)
Paul.
- Previous message: [Python-Dev] Why are contexts also managers? (was r45544 - peps/trunk/pep-0343.txt)
- Next message: [Python-Dev] Why are contexts also managers? (was r45544 - peps/trunk/pep-0343.txt)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]