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 05:51

I agree, it's more like an 'elif not [condition(s) raising break]'.

I know this is an old thread, but I am looking into the same question right now, and I'm not sure anyone has captured the answer to this question in the way I understand it.

For me, there are three ways of "reading" the else in For... else or While... else statements, all of which are equivalent, are:

  1. else == if the loop completes normally (without a break or error)
  2. else == if the loop does not encounter a break
  3. else == else not (condition raising break) (presumably there is such a condition, or you wouldn't have a loop)

So, essentially, the "else" in a loop is really an "elif ..." where '...' is (1) no break, which is equivalent to (2) NOT [condition(s) raising break].

I think the key is that the else is pointless without the 'break', so a for...else includes:

for:
    do stuff
    conditional break # implied by else
else not break:
    do more stuff

So, essential elements of a for...else loop are as follows, and you would read them in plainer English as:

for:
    do stuff
    condition:
        break
else: # read as "else not break" or "else not condition"
    do more stuff

As the other posters have said, a break is generally raised when you are able to locate what your loop is looking for, so the else: becomes "what to do if target item not located".

Example

You can also use exception handling, breaks, and for loops all together.

for x in range(0,3):
    print("x: {}".format(x))
    if x == 2:
        try:
            raise AssertionError("ASSERTION ERROR: x is {}".format(x))
        except:
            print(AssertionError("ASSERTION ERROR: x is {}".format(x)))
            break
else:
    print("X loop complete without error")

Result

x: 0
x: 1
x: 2
ASSERTION ERROR: x is 2
----------
# loop not completed (hit break), so else didn't run

Example

Simple example with a break being hit.

for y in range(0,3):
    print("y: {}".format(y))
    if y == 2: # will be executed
        print("BREAK: y is {}\n----------".format(y))
        break
else: # not executed because break is hit
    print("y_loop completed without break----------\n")

Result

y: 0
y: 1
y: 2
BREAK: y is 2
----------
# loop not completed (hit break), so else didn't run

Example

Simple example where there no break, no condition raising a break, and no error are encountered.

for z in range(0,3):
     print("z: {}".format(z))
     if z == 4: # will not be executed
         print("BREAK: z is {}\n".format(y))
         break
     if z == 4: # will not be executed
         raise AssertionError("ASSERTION ERROR: x is {}".format(x))
else:
     print("z_loop complete without break or error\n----------\n")

Result

z: 0
z: 1
z: 2
z_loop complete without break or error
----------
查看更多
临风纵饮
3楼-- · 2018-12-31 05:55

A common construct is to run a loop until something is found and then to break out of the loop. The problem is that if I break out of the loop or the loop ends I need to determine which case happened. One method is to create a flag or store variable that will let me do a second test to see how the loop was exited.

For example assume that I need to search through a list and process each item until a flag item is found and then stop processing. If the flag item is missing then an exception needs to be raised.

Using the Python for...else construct you have

for i in mylist:
    if i == theflag:
        break
    process(i)
else:
    raise ValueError("List argument missing terminal flag.")

Compare this to a method that does not use this syntactic sugar:

flagfound = False
for i in mylist:
    if i == theflag:
        flagfound = True
        break
    process(i)

if not flagfound:
    raise ValueError("List argument missing terminal flag.")

In the first case the raise is bound tightly to the for loop it works with. In the second the binding is not as strong and errors may be introduced during maintenance.

查看更多
宁负流年不负卿
4楼-- · 2018-12-31 05:55

I was just trying to make sense of it again myself. I found that the following helps!

• Think of the else as being paired with the if inside the loop (instead of with the for) - if condition is met then break the loop, else do this - except it's one else paired with multiple ifs!
• If no ifs were satisfied at all, then do the else.
• The multiple ifs can also actually be thought of as if-elifs!

查看更多
千与千寻千般痛.
5楼-- · 2018-12-31 05:56

I read it something like:

If still on the conditions to run the loop, do stuff, else do something else.

查看更多
梦该遗忘
6楼-- · 2018-12-31 05:58

I read it like "When the iterable is exhausted completely, and the execution is about to proceed to the next statement after finishing the for, the else clause will be executed." Thus, when the iteration is broken by break, this will not be executed.

查看更多
泪湿衣
7楼-- · 2018-12-31 06:00

Since the technical part has been pretty much answered, my comment is just in relation with the confusion that produce this recycled keyword.

Being Python a very eloquent programming language, the misuse of a keyword is more notorious. The else keyword perfectly describes part of the flow of a decision tree, "if you can't do this, (else) do that". It's implied in our own language.

Instead, using this keyword with while and for statements creates confusion. The reason, our career as programmers has taught us that the else statement resides within a decision tree; its logical scope, a wrapper that conditionally return a path to follow. Meanwhile, loop statements have a figurative explicit goal to reach something. The goal is met after continuous iterations of a process.

if / else indicate a path to follow. Loops follow a path until the "goal" is completed.

The issue is that else is a word that clearly define the last option in a condition. The semantics of the word are both shared by Python and Human Language. But the else word in Human Language is never used to indicate the actions someone or something will take after something is completed. It will be used if, in the process of completing it, an issue rises (more like a break statement).

At the end, the keyword will remain in Python. It's clear it was mistake, clearer when every programmer tries to come up with a story to understand its usage like some mnemonic device. I'd have loved if they have chosen instead the keyword then. I believe that this keyword fits perfectly in that iterative flow, the payoff after the loop.

It resembles that situation that some child has after following every step in assembling a toy: And THEN what Dad?

查看更多
登录 后发表回答