Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check whether break condition was triggered

Is there an elegant way in Python to detect whether a break condition was engaged at the last iteration or never at all?

C++ example:

int k, n = 10;
for (k = 0; k < n; k++)
    if (condition) break;

if (k == n) cout << "Never broke\n";
else        cout << "Broke at " << k << '\n';

Python example:

n = 10
for k in range(n):
    if condition: break

if k == n: print("Never broke")
else:      print("Broke at", k)

In Python, we don't know whether condition was true at the last iteration since k is 9 in both cases.

Why not just use range(n + 1) instead? Because on some contexts, we might get an "index out of range" error when k is n.

One possible workaround is to use a sentinel value as shown below, but is there a better way?

n, flag = 10, True
for k in range(n):
    if condition:
        flag = False
        break

if flag: print("Never broke")
else:    print("Broke at", k)
like image 306
visitor Avatar asked Oct 16 '25 07:10

visitor


2 Answers

Use for/else. That's specifically what it's for.

for k in range(n):
    if condition:
       print("Broke at", k)
       break
else:
    print("Never broke")
like image 150
kindall Avatar answered Oct 17 '25 21:10

kindall


Not necessarily better, but often you can condense the loop into a use of any or all (for when you only care if a value was found) or next (for when you care about the value found).

For example, to find the first item satisfying some test, or None if no such item exists, you can use two-arg next plus a generator expression:

needle = next((x for x in haystack if isneedle(x)), None)
if needle is not None:
    ... do stuff with needle ...
else:
    ... no needle ...

or roughly equivalently with one-arg next and exception handling:

try:
    needle = next(x for x in haystack if isneedle(x))
except StopIteration:
    ... no needle ...
else:
    ... do stuff with needle ...

A realistic use case might be identifying a prime number via trial division. In that case, you don't care what factor you found, you just care that there was a factor, so you could write a testing function as:

num = ...
isnumprime = num >= 2 and all(num % f != 0 for f in range(2, int(num ** 0.5) + 1))

for/else is a perfectly adequate way to do this (see other answers), but any/all/next (usually with generator expressions) can be cleaner in specific contexts.

like image 34
ShadowRanger Avatar answered Oct 17 '25 22:10

ShadowRanger