I happened to read the interesting "Idioms and Anti-Idioms"
HOWTO, and saw the '\' continuation character labeled an
anti-idiom. I already generally avoided it, so I just nodded.
Unfortunately, the new "nested" with statement (which I also read
about today) forces me into this anti-idiom. When replacing an
appearance of contextlib.nested with the 3K with statement, I
ended up with an unexpected syntax error.
with (open(roster_path, 'r') as roster_file,
open(disb_path, 'w') as out_file,
open(report_path, 'w') as report_file):
The result was:
File "C:\project\codxml.py", line 184
with (open(roster_path, 'r') as roster_file,
^
SyntaxError: invalid syntax
Unless I'm missing something, I have to subject my code to a bit
of contintuation:
with open(roster_path, 'r') as roster_file,\
open(disb_path, 'w') as out_file,\
open(report_path, 'w') as report_file:
I was thinking about submitting a enhancement request to the
HOWTO, explaining that continuation my be required in this
context. Am I missing anything obvious?
--
Neil Cerutti
with_stmt ::= "with" with_item ("," with_item)* ":" suite
with_item ::= expression ["as" target]
Parentheses only work around an expression or when they are expected by
the syntax, eg in function calls.
In this case it sees the '(' and thinks that it's the start of a
parenthesised expression. It parses the expression, then sees 'as',
hence a SyntaxError. I suppose it could've complained about a missing
')' instead.
I wonder whether an end-of-line could be ignored after a comma in a
'with' statement, and, for consistency, in any similar cases.
Right. The first open paren is illegal.
> Unless I'm missing something, I have to subject my code to a bit
> of contintuation:
>
> with open(roster_path, 'r') as roster_file,\
> open(disb_path, 'w') as out_file,\
> open(report_path, 'w') as report_file:
with open(roster_path, 'r') as roster_file, open(
disb_path, 'w') as out_file, open(report_path, 'w') as report_file:
would work ;-)
> I was thinking about submitting a enhancement request to the
> HOWTO, explaining that continuation my be required in this
> context. Am I missing anything obvious?
I would suggest replacing
"It is usually much better to use the implicit continuation inside
parenthesis:", <should be parentheses>
which says both too much and too little, with something like
"When the desired linebreak is within an expression, it is usually much
better to use implicit continuation inside parentheses, brackets, or
braces. If necessary, the whole expression can be surrounded by a new
pair of parentheses."
I would not mention 'with' specifically since there are many other
non-expression contexts where one cannot randomly add parentheses.
I believe that '\ \n' would always be harmless or a SyntexError outside
of expressons. I believe 'subtly wrong' only applies within expressions.
So I would not call \ continuation an anti-pattern outside
expressions. So you might suggest that the whole entry specify
expression context to begin with. To me, your example shows why blanket
condemnation is wrong.
You might separately request that with-item sequences be optionally
surrounded by parens, but I have a suspicion that this was considered
and rejected on either technical grounds and/or the grounds that \
continuation was purposefully left in the language in 3.x to be used
when implicit continuation is not appropriate, as in this situation.
The HOWTOs are not scripture.
Terry Jan Reedy
Then a line ending with ', ' would be different from one ending with
',', useless space and tabs at ends of lines were *always* ignored. Not
sure whether that would create problems though.
I like your suggestion. Changing the title of the anti-idiom to
"Using Backslash to Continue Expressions" seems like a good fix.
I submitted it as issue 7391.
I've done a search of the PEP's, Python-Dev, and Python-Ideas,
but I couldn't find much official discussion. The change was made
because contextlib.nested was not semantically equivalent to
actual nested with statments.
GvR noted in Python Ideas that he liked the idea of making the
new syntax parallel to the import statement sytax variant:
"import" module ["as" name] ( ", " ["as" name] )*
So that's where the 'multi-with' statement found its model.
--
Neil Cerutti