On 4/22/06, Nick Coghlan <[EMAIL PROTECTED]> 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"
...
<h1>
foo
</h1>

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.
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to