[Python-ideas] if in for-loop statement
Steven D'Aprano
steve at pearwood.info
Thu Feb 23 23:28:10 EST 2017
On Thu, Feb 23, 2017 at 11:07:49PM +0100, Sven R. Kunze wrote:
> >If the use of two lines and two indents is truly a problem, to the point
> >that you really need to refactor to a single line, that's a code smell:
> >your function is probably too big, too complex and does too much, and
> >should be refactored.
>
> May I disagree with you here? I write many functions with a single for
> loop + a single if+continue on a daily basis (usually generators).
> They don't seem to look like code-smell to me.
I'm sorry, I didn't explain myself well enough.
There is nothing wrong with a nested for...if pair of statements. But
that does take two lines, and two indents, rather than one:
block
for ...
if ...
block
versus hypothetical:
block
for ... if ...
block
The proposed syntax saves one line, and one indent. That is a saving,
but it is not a big saving. If one line and one indent *really* makes a
difference to a piece of code, it is probably because you are already
deeply nested:
class ...
def ...
def ...
try ...
try ...
while ...
try ...
if ...
with ...
if ...
while ...
for ...
if ...
# not enough
# room here
That is already so deeply nested that saving one indent might be
important. But the problem isn't the for...if section, it is the ten or
a dozen *previous* statements. "I have run out of horizontal space" is
the code-smell, not "I have a for loop and an if branch".
Most of the time, "save one line of code" or "save one indent" is not a
big win. It it insignificant: most of the time, extra lines are cheap,
and there is plenty of room for all the indent levels needed.
There is one obvious exception to the rule:
if ...
else:
if ...
else:
if ...
else:
if ...
That can get pretty costly in terms of indent levels very quickly. And
that is why Python has elif:
if ...
elif ...
elif ...
elif ...
So don't misunderstand me. I do appreciate that sometimes saving indents
and lines is important. But what I am saying is that in *this* case, it
is rarely important enough to matter, and when it does matter, your code
probably has bigger problems than just the for...if blocks.
> Not saying they justify this feature but it's easier to read a positive
> (including) if than a negative one (skipping).
>
> >Deeply nested for...for...for...if...if...if...for... blocks look ugly
> >because they are ugly. Allowing them all on one line makes the Python
> >language worse, not better. It is unfortunate that comprehensions, by
> >their nature, must allow that sort of thing, but that doesn't mean we
> >have to allow it elsewhere.
>
> Another disagreement here. Just because it's possible to do ugly stuff
> with a hammer shouldn't mean we cannot allow hammers. It's an argument
> neither in favor of nor against the proposal.
Since code is read more often than it is written, good programming
languages are pretty programming languages. That's why most of us choose
Python: its not the most efficient language, or fastest running
language, or most powerful language, but it is fast enough, efficient
enough, powerful enough, and most importantly, it is pretty. By which I
mean it is relatively easy to read (at least for English-readers), which
makes it easy to write, debug and maintain.
If we want to keep Python pretty, we should discourage things which are
ugly. Discourage, or even outright ban them.
Some features are on the borderline. There is a grey area where it comes
to the subjective aesthetic judgement of the language Dictator. I think
that this is one of those areas, and I hope that we are correctly
channelling the BDFL.
Because for...if...for...if... is on the boundary, we can allow it in
one case (comprehensions) and forbid it in another (statements):
- in a series of nested statements, the benefit of allowing the
for...if all on one line is not enough to make up for the risk
of people misusing it;
- in a comprehension, the benefit is greater, which is enough to
make up for the risk of people misusing it.
Because a comprehension is an expression, adding an extra line and an
extra indent is not usually helpful. It may mess up the expression it is
embedded in and lead to messy code:
result = some_function(arg, [comprehension
that goes over
multiple
lines and
indents],
spam, eggs, cheese) + 1
print(result)
That's probably not helpful, and possibly even confusing. So for
comprehensions, we can relax the rule about one indent level per for or
if statement.
The reason we have different syntax for comprehensions and statements is
that they are different kinds of code, used in different ways.
--
Steve
More information about the Python-ideas
mailing list