Historically there has been much resistance to proposals like this which only save a line. The existing code is, after all:
for n in range(100):
if n%2:
print(f'{n} is odd number')
You proposal also leads to a more ambiguous grammar because the following is currently allowed:
for n in range(100) if n%2 else range(n):
The ambiguity can be extended with multiple if's, compare:
for x in range(10) if n%2 if n else range(n):
for x in range(10) if n%2 if n else range(n) else n**2:
A work-around would be to raise something akin to the "SyntaxError: Generator expression must be parenthesized if not sole argument" that occurs with expressions like "f(b, a for a in range(3))", but that's a lot of work just to save a newline, two indents, and ":", isn't it?
"How is that ambiguity currently handled in comprehensions?"
A bit poorly. Compare:
>>> f(1, 2 for x in )
File "<stdin>", line 1
f(1, 2 for x in )
^
SyntaxError: invalid syntax
>>> f(1, 2 for x in r)
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
See how the first one gives the location of the error while the second does not? As I recall, this is because the first can be generated during parsing, while the second is done after the AST is generated, when the position information is no longer present.
That's why the following:
>>> f(2 for x in X) + g(1, 2 for y in Y) + h(z**2 for z in Z)
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
doesn't tell you which generation expression has the problem.
Yes, I meant that if 'n' is defined in an outer scope. The expression I gave is not a syntax error but a run-time error.
This does not answer my question, so I checked -- comprehensions simply do not accept the `else` clause:
>>> [a for a in range(10) if True else range(2)]
File "<stdin>", line 1
[a for a in range(10) if True else range(2)]
^
SyntaxError: invalid syntax
And this is the argument why I can't have my wish, because the standard `for` loops have always accepted `if else`, so it would be a backward incompatible change.
That said, I have another idea: an update to the comprehension syntax which would omitting duplication of variables, using a new "for in" construct. For example, this line:
Yes, that's what I've been using so far, especially filter, which works quite well with lambda. But if you have a separate function anyway it's better to make it into a generator:
def odd_range(count):
return (x for x in range(count) if x%2)
for n in odd_range(100):
...
As for the second one, I'm just not too happy with the implied two loops (even if it amounts to only one in practice).
It's not just repetitive; this particular example actually creates a list before starting the external loop -- imagine it with range(100000000) or something. It is better if you replace [] with (), which creates a generator.