Why does python use 'else' after for and w

2018-12-31 05:16发布

I understand how this construct works:

for i in range(10):
    print(i)

    if i == 9:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

But I don't understand why else is used as the keyword here, since it suggests the code in question only runs if the for block does not complete, which is the opposite of what it does! No matter how I think about it, my brain can't progress seamlessly from the for statement to the else block. To me, continue or continuewith would make more sense (and I'm trying to train myself to read it as such).

I'm wondering how Python coders read this construct in their head (or aloud, if you like). Perhaps I'm missing something that would make such code blocks more easily decipherable?

19条回答
怪性笑人.
2楼-- · 2018-12-31 06:11

Because they didn't want to introduce a new keyword to the language. Each one steals an identifier and causes backwards compatibility problems, so it's usually a last resort.

查看更多
时光乱了年华
3楼-- · 2018-12-31 06:11

To make it simple, you can think of it like that;

  • If it encounters the break command in the for loop, the else part will not be called.
  • If it does not encounters the break command in the for loop, the else part will be called.

In other words, if for loop iteration is not "broken" with break, the else part will be called.

It is so simple.

查看更多
初与友歌
4楼-- · 2018-12-31 06:15

There's an excellent presentation by Raymond Hettinger, titled Transforming Code into Beautiful, Idiomatic Python, in which he briefly addresses the history of the for ... else construct. The relevant section is "Distinguishing multiple exit points in loops" starting at 15:50 and continuing for about three minutes. Here are the high points:

  • The for ... else construct was devised by Donald Knuth as a replacement for certain GOTO use cases;
  • Reusing the else keyword made sense because "it's what Knuth used, and people knew, at that time, all [for statements] had embedded an if and GOTO underneath, and they expected the else;"
  • In hindsight, it should have been called "no break" (or possibly "nobreak"), and then it wouldn't be confusing.*

So, if the question is, "Why don't they change this keyword?" then Cat Plus Plus probably gave the most accurate answer – at this point, it would be too destructive to existing code to be practical. But if the question you're really asking is why else was reused in the first place, well, apparently it seemed like a good idea at the time.

Personally, I like the compromise of commenting # no break in-line wherever the else could be mistaken, at a glance, as belonging inside the loop. It's reasonably clear and concise. This option gets a brief mention in the summary that Bjorn linked at the end of his answer:

For completeness, I should mention that with a slight change in syntax, programmers who want this syntax can have it right now:

for item in sequence:
    process(item)
else:  # no break
    suite

* Bonus quote from that part of the video: "Just like if we called lambda makefunction, nobody would ask, 'What does lambda do?'"

查看更多
无与为乐者.
5楼-- · 2018-12-31 06:15

You could think of it like, else as in the rest of the stuff, or the other stuff, that wasn't done in the loop.

查看更多
琉璃瓶的回忆
6楼-- · 2018-12-31 06:15

Here's another idiomatic use case besides searching. Let's say you wanted to wait for a condition to be true, e.g. a port to be open on a remote server, along with some timeout. Then you could utilize a while...else construct like so:

import socket
import time

sock = socket.socket()
timeout = time.time() + 15
while time.time() < timeout:
    if sock.connect_ex(('127.0.0.1', 80)) is 0:
        print('Port is open now!')
        break
    print('Still waiting...')
else:
    raise TimeoutError()
查看更多
梦醉为红颜
7楼-- · 2018-12-31 06:16

The easiest way I found to 'get' what the for/else did, and more importantly, when to use it, was to concentrate on where the break statement jumps to. The For/else construct is a single block. The break jumps out of the block, and so jumps 'over' the else clause. If the contents of the else clause simply followed the for clause, it would never be jumped over, and so the equivalent logic would have to be provided by putting it in an if. This has been said before, but not quite in these words, so it may help somebody else. Try running the following code fragment. I'm wholeheartedly in favour of the 'no break' comment for clarity.

for a in range(3):
    print(a)
    if a==4: # change value to force break or not
        break
else: #no break  +10 for whoever thought of this decoration
    print('for completed OK')

print('statement after for loop')
查看更多
登录 后发表回答