On Sat, 21 May 2016 05:20 pm, Erik wrote: > On 20/05/16 01:06, Steven D'Aprano wrote: > >> In my experience, some people (including me) misunderstand "for...else" >> to mean that the else block runs if the for block *doesn't*. It took me >> the longest time to understand why this didn't work as I expected: >> >> for x in seq: >> pass >> else: >> print("seq is empty") > > So why don't we consider if that should be a syntax error - "else" > clause on "for" loop with no "break" in its body? I know that doesn't > change your fundamental mental model, but it's a hint that it's wrong :)
Just for the record, that's not my mental model *now*. It took me a long time to work out what for...else was actually doing, but some years ago I finally managed to do so. It's my argument that had the keyword been "then" (implying that the `then` block is unconditionally executed after the `for` block, which is the actual behaviour of the interpreter) rather than "else" implying that it is an alternative to the `for` block) I wouldn't have come up with the wrong mental model in the first place. And I'm not the only one who has come up with the same, wrong, model. But you do ask a good question. Why isn't for...else with no break a syntax error? I suppose it could be. But that's a *stylistic* question, and Python generally treats that as "none of the compiler's business". It's not the business of the compiler to enforce good code, only legal code. We can legally write lots of code of questionable value: while 0: print("surprise!") n = 1 + int(x) - 1 x = x try: something() finally: pass without the compiler judging us and making it a syntax error. Why should for...else be any different? The behaviour is perfectly well defined: - first the `for` block runs, as many times as needed; - then the `else` block runs, once. Of course, the usual four keywords (continue, break, return, raise) will change the order of execution by jumping to: - the top of the for loop; - past the for...else blocks; - out of the current function; - the nearest exception handler respectively. But in the absence of a jump, for...else works as specified, regardless of whether there is a break in it or not. > As it's backwards-incompatible, it could be introduced using a > __future__ import (a precedent is 'generators' and the "yield" keyword > back in the day) which those who would like the new check could add to > the top of their sources. Sure, we *could* do this, but as I said, it does go against the usual philosophy that the compiler shouldn't make judgements on what is good code and what isn't. > But also, as you say, any instances of that construct in the wild is > almost certainly a bug, I don't think it was me calling it a bug. > so it would be good to be able to test code > using a command-line or similar switch to turn on the behaviour by > default for testing existing bodies of code. I think that switch is called "use Pylint, PyChecker, Jedi or some other opinionated linter or style-checker". > I notice that pylint complains about this (as a warning). Is there any > reason why this should _not_ just be considered an error and be done > with it? Because there's nothing actually broken with it. There's lots of code which a human programmer would recognise as "silly", or "wrong", but is well-defined and legal. Just because you can't think of a reason to do something doesn't mean it should be prohibited. -- Steven -- https://mail.python.org/mailman/listinfo/python-list