I have been trying to convert a simple execution such as:
for x in xrange(10):
if x % 2 == 0:
print x, 'is even'
to a one liner version:
for x in xrange(10): if x % 2 == 0: print x, 'is even'
which gives me:
File "foo.py", line 1
for x in xrange(10): if x % 2 == 0: print x, 'is even'
^
SyntaxError: invalid syntax
I don't see any ambiguity in here. Is there a particular reason why this fails?
It's simply not allowed by the grammar. The relevant productions are:
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
As you can see, after a for
you can either put a simple statement or a "suite", i.e. an indented block. An if
statement is a compound statement, not a simple one.
Two lines are the minimum to express this program:
for x in xrange(10):
if x % 2 == 0: print x, 'is even'
(Of course, you can write equivalent programs that take only one line, such as
for x in xrange(0, 10, 2): print x, "is even"
or any of the other one-liners posted in response to this question.)
From the formal grammar for 2.7:
compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt |
import_stmt | global_stmt | exec_stmt | assert_stmt)
If the suite
had allowed a compound_stmt
then what you suggest would be accepted. But that would also allow something like this:
if True: try:
# do something
except:
# handle
foo()
Is that except
outside the enclosing if
? Is the call to foo
outside the enclosing if
? I think this shows that we really don't want in-lining compound statements to be allowed by the formal grammar. Simply adding suite: compound_stmt
makes the grammar ambiguous as I read it, where the same code can be interpreted with two or more different meanings, neither disprovable.
Basically, it's by design that what you ask is a parse error. Reworking the formal grammar could allow the code in your example to work without other funny stuff, but it requires careful attention to ambiguity and other problems.
See also Dangling Else, a grammar problem that afflicted the standard Algol-60 language. It's not always easy to find these kinds of problems, so a healthy fear of changing a working grammar is a good thing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With