11

I was watching python lecture by Raymond Hettinger on youtube. And he showed the right way to exit for loop:

def find(seq, target):
    for i, value in enumerate(seq):
        if value == target:
            break
    else:
        return -1
    return i

I dont get why bother with else statement and not just do:

def find(seq, target):
    for i, value in enumerate(seq):
        if value == target:
            return i
    return -1

Am I missing something or it is just good idea to sometimes add this else/break statement for whatever reason?

Taku
  • 31,927
  • 11
  • 74
  • 85
user8856277
  • 185
  • 2
  • 9
  • 3
    My guess is it's probably purely for pedagogical purpose to show the way to do cleaning up after completing a for loop. – Haochen Wu Nov 05 '17 at 18:16

2 Answers2

6

Condensed answer: Once you use return you are out of your function. Break means the code continue to run and you can add more things. So you are right in your example, but what if you want to do more things if nothing was found:

Raise an error:

def find(seq, target):
    for i, value in enumerate(seq):
        if value == target:
            break
    else:
        raise ValueError("Nothing found in {}".format(seq))
    return i


find("hello","a")

Or write to a file:

def find(seq, target):
    for i, value in enumerate(seq):
        if value == target:
            break
    else:
        with open("output.txt", "w") as f:
            f.write("Nothing found :(((")
    return i


find("hello","a")

Developping further (@Joe Iddon):

You maybe want to continue further too:

def find(seq, target):
    for i, value in enumerate(seq):
        if value == target:
            break
    else:
        return "Nothing found"

    # calculate more things
    a = [1,2,3]
    if i in a:
        return i
    else:
        return "Not in a"


find("hello","a")

So for this small purpose it wasn't necessary. But if you are building something upon that, the else clause can be useful.

Anton vBR
  • 18,287
  • 5
  • 40
  • 46
0

I think the example was too short and the "why bother?" question is fully logical in that case.

However it the found value was going to be further processed, the difference would become obvious (but also requiring more presentation time)

Pythonic way:

def find1(seq, target):
    for i, value in enumerate(seq):
        if value == target:
            break
    else:
        return -1
    i = some_preprocessing(i)
    func(i)
    i = final_adjustment(i)
    logging_result(i)
    return i

Without the else - processing code appears inside the search loop. Also the code is indented a lot to the right.

def find2(seq, target):
    for i, value in enumerate(seq):
        if value == target:
            i = some_preprocessing(i)
            func(i)
            i = final_adjustment(i)
            logging_result(i)
            return i
    return -1

Alternatively, code using a flag - the example Mr. Hettinger started with - is inferior too:

def find2(seq, target):
    found = False
    for i, value in enumerate(seq):
        if value == target:
            found = True
            break
    if not found:
        return -1
    i = some_preprocessing(i)
    func(i)
    i = final_adjustment(i)
    logging_result(i)
    return i
VPfB
  • 14,927
  • 6
  • 41
  • 75