Hi all,
can someone say why this is stuck in a infinite loop?
Code
while True:
print("why is this happening")
try:
break
finally:
continue
Output
why is this happening
why is this happening
why is this happening
...
Hi all,
can someone say why this is stuck in a infinite loop?
while True:
print("why is this happening")
try:
break
finally:
continue
why is this happening
why is this happening
why is this happening
...
Because control flow statements (break
, continue
, return
, raise
) in finally
suites overwrite whatever else would have happened if executed. This is almost always a bad idea and will lead to confusing code.
Is that documented somewhere?
Thatâs of course where I had immediately looked. Where there exactly is this behavior documented? I donât see it.
This exact edge case is not directly listed. IMO it follows well enough from
If the
finally
clause executes areturn
,break
orcontinue
statement, the saved exception is discarded:
And
When a
return
,break
orcontinue
statement is executed in thetry
suite of atry
âŚfinally
statement, thefinally
clause is also executed âon the way out.â
The return value of a function is determined by the lastreturn
statement executed.
But I donât think anyone would mind if you suggest an improvement of the docs there.
I had seen all that and I disagree that any of that documents this case. The âon the way outâ even rather sounds like the opposite to me.
Good, then we disagree. Go propose a change if you care.
Maybe combining with this sentence in the documentation of break
When
break
passes control out of atry
statement with afinally
clause, thatfinally
clause is executed before really leaving the loop.
I guess one can think, or not, that the break
s get queued for execution after the finally
is done. The effect is the same, the break
would only happen after the loop completes, which in this case is never.
FWIW, it works the same way in other languages that have the same suite of try
, finally
etc. keywords.
Similar to the âon the way outâ, to me that rather sounds like the âleaving the loopâ is still happening. Otherwise itâd be âinstead of really leaving the loopâ in this case. I think itâs just not clear either way. Unlike the double return
, which is explicitly and clearly covered:
The return value of a function is determined by the last return statement executed. Since the finally clause always executes, a return statement executed in the finally clause will always be the last one executed: [example]
âon the way outâ of try, not the loop itâs all there
Whatâs the point of repeating that as if we hadnât discussed it already?
sorry, I must have missed some of it, I was just curious about the implementation problem prior to 3.8 ? Is that outside this post
You can probably check the changelog of 3.8 and from there search back through the PRs/issues.
check this documentation link
I would look at it this way: there is a virtual program counter that determines which statement is executed next. The value of this counter isnât actually used until it is time to determine what to next execute, which doesnât happen until the finally
clause executes. Thus, in a sense, continue
overwrites the value written by break
before the value of the program counter is requested.
That is, the break
statement says âSet the program counter to 7â, but before you actually go to line 7, you have to execute continue
, which says âSet the program counter to line 2â. Now that the try
statement is complete, you look at the program counter to see where to go next, and the program counter is set to 2.
That is consistent with the result of unwrapping the loop into (infinitely many prints, followed by infinitely many break)
print("why is this happening")
print("why is this happening")
print("why is this happening")
...
break
break
break
...
We get this (\omega\cdot 2)-list of instructions, since each finally
does a continue
âbefore leaving the loopâ. So, all passes over the loopâs code get done before all the âleaving of the loopâ.