"else" with "while" and mysterious "break" [duplicate] - python

This question already has answers here:
Else clause on Python while statement
(13 answers)
Closed 7 years ago.
I was going through this. Coming from C environment, it hit me right in the face with utter surprise and disbelief. And, then I tried it for myself::
bCondition = True
while bCondition:
print("Inside while\n")
bCondition = False
else:
print("Inside else\n")
print("done\n")
This code renders the below output,
#Output
Inside while
Inside else
done
Ideone link
Now, my question is, Why? why do we need this? Why both the blocks are executed? Isn't if and else were made for each other, then what use case will make this design a useful design to implement?
Again if we just change the code to incorporate a break, the behavior is more mysterious. Ideone Link.
bCondition = True
while bCondition:
break
else:
print("Inside else\n")
print("done\n")
This code renders the below output,
#Output
done
Why both of the blocks are skipped? Isn't break made to break out of the loop only, then why is it breaking out of the else block?
I went through the documentation too, couldn't clear my doubts though.

The use of the else clause after a loop in python is to check whether some object satisfied some given condition or not.
If you are implementing search loops, then the else clause is executed at the end of the loop if the loop is not terminated abruptly using constructs like break because it is assumed that if break is used the search condition was met.
Hence when you use break, the else clause is not evaluated. However when you come out of the loop naturally after the while condition evaluates to false, the else clause is evaluated because in this case it is assumed that no object matched your search criteria.
for x in data:
if meets_condition(x):
print "found %s" % x
break
else:
print "not found"
# raise error or do additional processing

Related

Best way in python to check if a loop is not executed

The title might be misleading, so here is a better explanation.
Consider the following code:
def minimum_working_environment(r):
trial=np.arange(0,6)[::-1]
for i in range(len(trial)):
if r>trial[i]:
return i
return len(trial)
We see that if r is smaller than the smallest element of trial, the if clause inside the loop is never executed. Therefore, the function never returns anything in the loop and returns something in the last line. If the if clause inside the loop is executed, return terminates the code, so the last line is never executed.
I want to implement something similar, but without return, i.e.,
def minimum_working_environment(self,r):
self.trial=np.arange(0,6)[::-1]
for i in range(len(self.trial)):
if r>trial[i]:
self.some_aspect=i
break
self.some_aspect=len(self.trial)
Here, break disrupts the loop but the function is not terminated.
The solutions I can think of are:
Replace break with return 0 and not check the return value of the function.
Use a flag variable.
Expand the self.trial array with a very small negative number, like -1e99.
First method looks good, I will probably implement it if I don't get any answer. The second one is very boring. The third one is not just boring but also might cause performance problems.
My questions are:
Is there a reserved word like return that would work in the way that I want, i.e., terminate the function?
If not, what is the best solution to this?
Thanks!
You can check that a for loop did not run into a break with else, which seems to be what you're after.
import numpy as np
def minimum_working_environment(r):
trial = np.arange(0, 6)[::-1]
for i in range(len(trial)):
if r > trial[i]:
return i
return len(trial)
def alternative(r):
trial = np.arange(0, 6)[::-1]
for i in range(len(trial)):
if r > trial[i]:
break
else:
i = len(trial)
return i
print(minimum_working_environment(3))
print(minimum_working_environment(-3))
print(alternative(3))
print(alternative(-3))
Result:
3
6
3
6
This works because the loop controlling variable i will still have the last value it had in the loop after the break and the else will only be executed if the break never executes.
However, if you just want to terminate a function, you should use return. The example I provided is mainly useful if you do indeed need to know if a loop completed fully (i.e. without breaking) or if it terminated early. It works for your example, which I assume was exactly that, just an example.

Inline function hack just to use inline if else [duplicate]

This question already has answers here:
Why doesn't exec("break") work inside a while loop
(6 answers)
Closed 3 years ago.
A recent question made me think if it is possible to do something like:
def defA(flag) :
return "value = 'yes'" if flag else "continue"
flag = False
#n can be a reasonable number like 100
for x in range(n):
#some logic that may change the flag
exec(defA(flag))
here, you got a variable assignment if the flag is true, or continue the for loop otherwise, but it gives me an odd error:
SyntaxError: 'continue' not properly in loop
Is it possible or should I let it go?
Because exec doesn't carry the context over to the statement being executed.
pass can be used anywhere, so the context doesn't matter. continue can only be used in the context of a loop, but that context is not available to exec.
You can only use continue in an exec statement if the loop itself is also part of the executed code:
f = 'for x in range(n): if(flag) continue' exec f
In other words, you can only use exec for complete statements, where a single continue (or break) is not complete.

Python for-else relationship [duplicate]

This question already has answers here:
Why does python use 'else' after for and while loops?
(24 answers)
Closed 9 years ago.
I can run the below python script without errors.
for n in range(3):
print n
else:
print "done"
But I am puzzled about the else without a matching if.
It does not make sense.
Can some one explain why this works ?
The else clause of for and while only executes if the loop exits normally, i.e. break is never run.
for i in range(20):
print i
if i == 3:
break
else:
print 'HAHA!'
And the else clause of try only executes if no exception happened.
try:
a = 1 / 2
except ZeroDivisionError:
do_something()
else:
print '/golfclap'
The body of the else is executed after the for loop is done, but only if the for loop didn't terminate early by break statements.

Understanding python try catch else finally clause behavior

Python 2.6.5 (r265:79063, Oct 1 2012, 22:07:21)
I have this:
def f():
try:
print "a"
return
except:
print "b"
else:
print "c"
finally:
print "d"
f()
This gives:
a
d
and not the expected
a
c
d
If I comment out the return, then I will get
a
c
d
How do I remember this behavior in python?
When in doubt, consult the docs:
The optional else clause is executed if and when control flows off the end of the try clause
Currently, control “flows off the end” except in the case of an exception or the execution of a return, continue, or break statement.
Since you're returning from the body of the try block, the else will not be executed.
finally blocks always happen, save for catastrophic failure of the VM. This is part of the contract of finally.
You can remember this by remembering that this is what finally does. Don't be confused by other control structures like if/elif/else/while/for/ternary/whatever statements, because they do not have this contract. finally does.
The else block hooked up to a try block is not special in terms of exception mechanics - it's similar to just putting code in the body of the function after the try block. The only function is being able execute "normal" code between a try block and a finally block. This does mean however that if the function returns before getting to the else block it will never execute.
Take a look at Python documentation!
You would use this for exception handling, bookmark this page!
http://docs.python.org/2/tutorial/errors.html
You enter the try block.
You print "a".
You encounter the return statement and the function returns.
Since finally blocks always execute, though, everything in the finally block happens before the function actually ends its execution.
The else block is only entered if the try block has been completed and no exception occurred. Because you returned in the try block, it wasn't completed, even though no exception occurred nonetheless. It is as if you never had a try/else block at all, and you put all the code on the same level of indentation.
try/else exists more for the sake of code organization; unless a finally block is added, it is the same thing as using no else block at all. The following are functionally equivalent:
try:
print "foo"
except:
print "woops"
else:
print "bar"
try:
print "foo"
except:
print "woops"
print "bar"
However, you must use else if you are going to use finally. This has no meaning:
try:
print "foo"
except:
print "woops"
print "bar"
finally:
print "done"
What was the finally supposed to refer to in this case? Ergo you must use else if you are going to use finally unless you did not intend for anything to happen after the try block but before the finally.
When a return, break or continue statement is executed in the try suite of a try…finally statement, the finally clause is also executed ‘on the way out.’ A continue statement is illegal in the finally clause. (The reason is a problem with the current implementation — this restriction may be lifted in the future).
This is actually from the documentation.

What is the best way on Python to identify if a break occurred on the last element iteration due to a condition within?

I saw some similar questions to this but none seems to address this is specific question so I don't know if I am overlooking something since I am new to Python.
Here is the context for the question:
for i in range(10):
if something_happens(i):
break
if(something_happened_on_last_position()):
# do something
From my C background, if I had a for (i=0;i<10;i++) doing the same thing with a break, then the value of i would be 10, not 9 if the break didn't occur, and 9 if it occurred on the last element. That means the method something_happened_on_last_position() could use this fact to distinguish between both events. However what I noticed on python is that i will stop on 9 even after running a successful loop without breaks.
While make a distinction between both could be as simple as adding a variable there like a flag, I never liked such usage on C. So I was curious, is there another alternative to do this or am I missing something silly here?
Do notice that I can't just use range(11) because this would run something_happens(10). It is different on C on this since '10' would fail on the condition on the for loop and would never execute something_happens(10) (since we start from index 0 here the value is 10 on both Python and C).
I used the methods just to illustrate which code chunk I was interest, they are a set of other conditions that are irrelevant for explaining the problem.
Thank you!
It works the other way:
for i in range(10):
if something_happens(i):
break
else: # no break in any position
do whatever
This is precisely what the else clause is for on for loops:
for i in range(10):
if something_happens(i):
break
else:
# Never hit the break
The else clause is confusing to many, think of it as the else that goes with all those if's you executed in the loop. The else clause happens if the break never does. More about this: For/else

Categories