I am pretty new to both programming and Python. A few times now, I have created what feels like an awkward program flow, and I am wondering if I am following best practices. This is conceptually what I have wanted to do:
def pseudocode():
while some condition is true:
do some stuff
if a condition is met:
break out of the while loop
now do a thing once, but only if you never broke out of the loop above
What I've ended up doing works, but feels off somehow:
def pseudocode():
while some condition is true:
do some stuff
if some condition is met:
some_condition_met = True
break out of the while loop
if some_condition_met is False:
do a thing
Is there a better way?
You're looking for while-else loop:
def pseudocode():
while some condition is true:
do some stuff
if a condition is met:
break out of the while loop
else:
now do a thing once, but only if you never broke out of the loop above
From docs:
while_stmt ::= "while" expression ":" suite
["else" ":" suite]
A break statement executed in the first suite terminates the loop
without executing the else clause’s suite.
Use an else clause to the while loop:
while some_condition:
do_stuff()
if a_condition_is_met:
break
else:
executed_when_never_broken
See the while statement documentation:
A break statement executed in the first suite terminates the loop without executing the else clause’s suite.
If you think about it, you might already have a perfectly good condition to use without setting a flag: the condition at the top of the while loop (or, rather, the not of it). Assuming you don't change the truthiness of your condition during the same iteration as a break, this gives you:
while something:
do_stuff()
if something_else:
break
if not something:
more_stuff()
This makes sense if you think of while as a repeated if: instead of happening once, a while keeps going until the condition becomes falsey.
But, like the other answers have mentioned, the analogy goes further: just like you don't have to spell all your ifs as
if a:
a_stuff()
if not a:
b_stuff()
while accepts an else that is executed if the condition at the top is tested and found to be falsey. So,
while something:
do_stuff()
if something_else:
break
else:
more_stuff()
And, same as the if/else case, this doesn't imply any further tests of the condition than what would happen anyway. In the same way that an else attached to if a won't run if the true-branch makes a falsey, an else attached to a while will never run after a break since that explicitly skips ever checking the condition again. This makes the else: equivalent to a decicated flag in every case.
This also extends to for loops, even though the analogy breaks - but it executes under similar enough rules: the else is run if the loop ends by having run its course rather than hitting a break.
Related
who can say me:
What is the difference between writing code inside else or just after the loops?
for x in range(6):
print('hello')
print('bye')
or
for x in range(6):
print('hello')
else:
print('bye')
From for/else documentation:
The else clause executes after the loop completes normally. This means that the loop did not encounter a break statement.
This means that in your specific example there is no difference in using else or not.
In the second example you're using conditional statement, Whereas in the first scenario after the loop completes, It automatically executes the next line.
Basically your post is an example of getting same result with alternative solutions.
Though your first solution can be considered as valid practice comparing with second one.
Although I would suggest you to read this article before posting any questions on stack overflow.
In a for loop with break statements I can add an else statement at the end, which will be triggered if my for loop never hits a break statement.
My question is, how does continue affect this?
continue does not affect the else: clause. The else clause is run if the loop terminated normally, that is, if a StopIteration is (implicitly) raised by the iterator.
The continue statement does nothing for the particular iteration, however it does not prevent the iterator from being exhausted.
No, else clause execution is not affected by continue.
The only thing that prevents an else statement (after a for loop) from being triggered is a break statement (or your code returning or exiting or raising an exception before it finishes the for loop).
for i in range(5):
continue
else:
print("else triggered")
Will print else triggered.
See the docs:
Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the list (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement
[...]
When used with a loop, the else clause has more in common with the else clause of a try statement than it does that of if statements: a try statement’s else clause runs when no exception occurs, and a loop’s else clause runs when no break occurs.
Only break is mentioned as preventing the else clause from running, continue isn't.
I'm not sure how the continue statement is interpreted when it is inside a for loop with an else clause.
If the condition is true, the break will exit from a for loop and else part will not be executed. And if the condition is False then else part will be executed.
But, what about continue statement? I tested it seems that the after the continue statement is reached, the else part will be executed. Is this true?? Here is a code example:
# when condition found and it's `true` then `else` part is executing :
edibles = ["ham", "spam", "eggs","nuts"]
for food in edibles:
if food == "spam":
print("No more spam please!")
continue
print("Great, delicious " + food)
else:
print("I am so glad: No spam!")
print("Finally, I finished stuffing myself")`
If I remove "spam" from the list, now the condition is always false and never found but still the else part is executed:
edibles = ["ham","eggs","nuts"]
for food in edibles:
if food == "spam":
print("No more spam please!")
continue
print("Great, delicious " + food)
else:
print("I am so glad: No spam!")
print("Finally, I finished stuffing myself")
With a for loop in Python, the else block is executed when the loop finishes normally, i.e. there is no break statement. A continue does not affect it either way.
If the for loop ends because of a break statement, then else block will not execute. If the loop exits normally (no break), then the else block will be executed.
From the docs:
When used with a loop, the else clause has more in common with the else clause of a try statement than it does that of if statements: a try statement’s else clause runs when no exception occurs, and a loop’s else clause runs when no break occurs.
I always remember it because of how Raymond Hettinger describes it. He said it should have been called nobreak instead of else. (That's also a good video that explains the usefulness of the for-else construct)
Example:
numbers = [1,2,3]
for number in numbers:
if number == 4:
print("4 was found")
break
else:
print("4 was not found")
When you run the above code, since 4 is not in the list, the loop will not break and the else clause will print. If you add 4 to the list and run it again, it will break and the else will not print. In most other languages, you would have to add some sentinel boolean like found and make it True if you find a 4, then only print the statement after the loop if found is False.
Your else part will be executed in both cases.
else part executed when loop terminate when condition didn't found.Which is what is happening in your code. But it will also work same without continue statement.
now what about break statement's else part, Break statement's else part will be executed only if:
If the loop completes normally without any break.
If the loop doesn't encounter a break.
I've been doing something that needs to run an infinite while loop inside another infinite while loop (don't judge) and breaks if some sort of event happens. I need to run a statement once when the inside loop breaks, without having it modified in the external loop.
I need something like this:
while True:
while condition:
do stuff
<run some code when the inside while finishes>
continue running external loop without running the line inside <>
Basically, the reverse of a while-else construct.
Edit: I've changed the code to relate to the real problem. I'm really sorry for the mistake. Was bombarded by other stuff and wasn't thinking right.
If you only need the statement to run once when the internal while breaks, why not just put it in the if block?
while True:
while condition:
if other-condition:
<code to run when the inside loop breaks>
break
<continue external loop>
EDIT: In order to run only once after the inner loop is finished (without an if other_condition: ...; break) you should use the following:
while True:
has_run = False
while condition:
<loop code>
if not has_run:
<code to run when inner loop finishes>
has_run = True
<rest of outer loop code>
Add a boolean that you switch after the code has been executed once! This way you can always make things happen just once in a loop. Also, if you want to run the external loop again, the internal loop will start again, and it will break again, so are you sure you only want to run that line once?
broken = False
while True:
while condition:
if other-condition:
break
if not broken:
broken = True
<run some code when the inside while breaks>
continue running external loop without running the line inside <>
If you need continue code after while loop than use variable was_break
while True:
was_break = False
while condition:
if other-condition:
was_break = True
break
if was_break:
<run some code when the inside while breaks>
continue running external loop without running the line inside <>
Pythonic way for this is to use else with while loop. This is how it should be done.
If the else statement is used with a while loop, the else statement is executed when the condition becomes false.
x=1
while x:
print "in while"
x=0
#your code here
else:
print "in else"
I cannot figure out why the following statements dont work.
randomKey = random.choice(list(topic.keys()))
randomValue = random.choice(topic[randomKey])
current = "-" * len(randomValue)
while current != randomValue:
(statements)
else:
(statements)
However, if i alter the 1st line to
while current == randomValue:
the statement after 'else' executes correctly. Otherwise, the statement after 'else' does not execute. Any idea why what may be causing the strange behaviour? Full code has been excluded for it will run through this entire page.
It is part of the Python grammar. From the documentation:
This [a while statement] repeatedly tests the expression and, if it is true, executes the first suite; if the expression is false (which may be the first time it is tested) the suite of the else clause, if present, is executed and the loop terminates.
So in the first case, it must be that the while condition never evaluates to false, while in the second it eventually does. Note that explicitly breaking out of the loop will not execute the else clause.
else, when used with while, runs after the while expression evaluates to a falsy value if the while loop finishes by the expression being false, instead of being broken out of by a break statement (or execution leaving the function via a return or raise-ing an exception). Your while condition in your second example must fail, so there's no opportunity for a break to occur, the function to return or an exception to be thrown, so the else statements will always run.
docs for while