Why are nested control statements on the same line not working in python?

I am trying to convert simple execution, for example:

for x in xrange(10): if x % 2 == 0: print x, 'is even' 

single-layer 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 do not see any ambiguity here. Is there a special reason why this fails?

+4
source share
6 answers

From formal grammar to 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 suite allowed compound_stmt , then what you offer will be accepted. But it will also allow you to do something like this:

 if True: try: # do something except: # handle foo() 

Is this except outside the closing if ? Calling foo outside if ? I think this shows that we really do not want inline formulations to be allowed by formal grammar. Just adding suite: compound_stmt makes the grammar ambiguous when I read it, where the same code can be interpreted with two or more different values, none of which are unprovable.

Basically, by design, what you ask for is a parsing error. Recycling formal grammar could lead the code in your example so that it works without other funny things, but it requires close attention to ambiguity and other problems.

See also Dangling Else , a grammar issue that affects the standard Algol-60 language. Finding such problems is not always easy, so a healthy fear of changing working grammar is good.

+3
source

This is simply not allowed by grammar . Relevant Manufacturing:

 for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT 

As you can see, after for you can either put a simple statement or a “set”, that is, a pending block. The if is a compound statement, not a simple one.

Two lines is 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 occupy only one line, for example

 for x in xrange(0, 10, 2): print x, "is even" 

or any other single line liner sent in response to this question.)

+5
source

try something like:

 In [14]: from __future__ import print_function In [17]: for x in xrange(10): print (x,'is even') if x%2==0 else None ....: 0 is even 2 is even 4 is even 6 is even 8 is even 
+1
source

You can try the following:

 for y in (x for x in xrange(10) if x % 2 == 0): print y 
+1
source

If you want something like this, use a list comprehension:

 print '\n'.join('{0} is even'.format(x) for x in xrange(10) if x % 2 == 0) 

Print

 0 is even 2 is even 4 is even 6 is even 8 is even 
+1
source

Python docs about compound statements talk about a reason for deciding why this grammar forbids the following:

A set can be one or more simple statements, separated by a semicolon, on the same line as the heading after a colon colon, or it may be one or more indentation in subsequent lines. Only the last set form can contain nested compound statements; the following is illegal, mainly because it would not be clear to what if the following else clause should belong :

 if test1: if test2: print x 

So, in wberry, the answer was right about Dangling Else .

+1
source

Source: https://habr.com/ru/post/1440368/


All Articles