On Wed, Oct 31, 2012 at 6:38 AM, Barry Warsaw <ba...@python.org> wrote:This seemed kind of icky when I read it, and I think Nick Coghlan
> This seems analogous to using parens to wrap long if-statements, but maybe
> there's some subtle corner of the grammar that makes this problematic (like
> 'with' treating the whole thing as a single context manager).
stated the reason best.
Is there a reason the tokenizer can't ignore newlines and
indentation/deindentation between with/etc. and the trailing colon?
This would solve the problem in general, without ambiguous syntax.
On Wed, Oct 31, 2012 at 8:33 AM, Eli Bendersky <eli...@gmail.com> wrote:It's already context-dependent in some sense, but this wouldn't make
>> Is there a reason the tokenizer can't ignore newlines and
>> indentation/deindentation between with/etc. and the trailing colon?
>> This would solve the problem in general, without ambiguous syntax.
>
> At the expense of making the tokenizer context dependent?
it any moreso. For example, the tokenizer already ignores
indents/dedents when inside parens/braces/brackets, and handling this
only slightly more complex than that. In particular, the trailing
colon is the one not inside braces or brackets.
Also, I'd avoid the term "context-dependent". It sounds too similar to
"context-sensitive" !
Anyway, it looks like this isn't how the tokenizer treats
braces/brackets (it ignores indent/dedent, but not newlines (I guess
the grammar handles those)). What I meant to suggest was, treat "with
... :" similarly to how the OP suggests treating "with (...) :".
IWBNI you could write it like this:
with (open('/etc/passwd') as p1,
open('/etc/passwd') as p2):
pass
This seems analogous to using parens to wrap long if-statements, but maybe
there's some subtle corner of the grammar that makes this problematic (like
'with' treating the whole thing as a single context manager).
Of course, you can wrap with backslashes, but ick!
I've been remiss in not mentioning the new alternative in 3.3 for
handling nesting of complex context management stacks:
with contextlib.ExitStack() as cm:
p1 = cm.enter_context(open('/etc/passwd'))
p2 = cm.enter_context(open('/etc/passwd'))
(Note: ExitStack is really intended for cases where the number of
context managers involved varies dynamically, such as when you want to
make a CM optional, but you *can* use it for static cases if it seems
appropriate)
Go was one of the reference points for the ExitStack design (it's a large part of why the API also supports providing callbacks directly to the exit stack, not just as context managers).
Cheers,
Nick.
--
Sent from my phone, thus the relative brevity :)
>
> Yuval Greenfield
To my mind one of the attractive features of the current syntax is thatforgetting the colon causes an immediate complaint.
I understand the attractiveness here, but I think I would prefer staying
with the status quo (overt brackets or icky trailing sloshes) to extend
the lines in a condition over opening the syntax to complaints far beyond
the mistake.
because of the pop_all() operation (which moves all of the registeredYep. You can also do some pretty interesting things with ExitStack
operations to a *new* ExitStack instance).
I wrote up a few of the motivating use cases as examples and recipes
in the 3.3 docs:
http://docs.python.org/3/library/contextlib#examples-and-recipes
I hope to see more interesting uses over time as more people explore
the possibilities of a dynamic tool for composing context managers
without needing to worry about the messy details of unwinding them
correctly (ExitStack.__exit__ is by far the most complicated aspect of
the implementation).
Cheers,
Nick.