Line-continuation "Anti-Idiom" and with statement

N

Neil Cerutti

I installed Python 3.1 today, and I've been porting my small
library of programs to the new system.

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?
 
M

MRAB

Neil said:
> I installed Python 3.1 today, and I've been porting my small
> library of programs to the new system.
>
> 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?
>
The relevant syntax is:

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.
 
T

Terry Reedy

Neil said:
I installed Python 3.1 today, and I've been porting my small
library of programs to the new system.

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

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
 
T

Terry Reedy

MRAB said:
Neil said:
I installed Python 3.1 today, and I've been porting my small
library of programs to the new system.

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?
The relevant syntax is:

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.

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.
 
N

Neil Cerutti

Right. The first open paren is illegal.

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.

The HOWTOs are not scripture.

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top