Immemorial desire for "do-while"-like construction
Hello, The issue has been coming back repeatedly: How we could elegantly and pythonic'ly avoid repeating ourselves if we need the control flow structure that e.g. in PASCAL has the form: repeat ... until CONDITION In Python we must use while-loop in not very DRY (Don't Repeat Yourself) manner: SOME ACTIONS HERE ... while CONDITION: THE SAME ACTIONS AGAIN ... (See also: http://www.python.org/dev/peps/pep-0315/ http://mail.python.org/pipermail/python-dev/2006-February/060718.html http://preview.tinyurl.com/nodgwt ) Maybe here the simplest approach can lead us to the solution? I.e.: repeat while CONDITION: SOME ACTIONS HERE ... In human language it'd mean: do ACTIONS once unconditionally, then *repeat* them while the CONDITION is true. Additional advantage is that probably for many people associate 'repeat' with such construction (from experience with other languages). What do you think about the idea? -- Jan Kaliszewski <zuo@chopin.edu.pl>
On Wed, Jul 15, 2009 at 3:50 PM, Jan Kaliszewski<zuo@chopin.edu.pl> wrote:
Hello,
The issue has been coming back repeatedly:
How we could elegantly and pythonic'ly avoid repeating ourselves if we need the control flow structure that e.g. in PASCAL has the form:
repeat ... until CONDITION
In Python we must use while-loop in not very DRY (Don't Repeat Yourself) manner:
SOME ACTIONS HERE ... while CONDITION: THE SAME ACTIONS AGAIN ...
You can fix that by just writing it as: while True: SOME ACTIONS HERE if not CONDITION: break Cheers, Chris -- http://blog.rebertia.com
Chris Rebert wrote:
On Wed, Jul 15, 2009 at 3:50 PM, Jan Kaliszewski<zuo@chopin.edu.pl> wrote:
Hello,
The issue has been coming back repeatedly:
How we could elegantly and pythonic'ly avoid repeating ourselves if we need the control flow structure that e.g. in PASCAL has the form:
repeat ... until CONDITION
In Python we must use while-loop in not very DRY (Don't Repeat Yourself) manner:
SOME ACTIONS HERE ... while CONDITION: THE SAME ACTIONS AGAIN ...
You can fix that by just writing it as:
while True: SOME ACTIONS HERE if not CONDITION: break
If we were going to add 'repeat' then it could be: repeat: SOME ACTIONS HERE while CONDITION If 'while' starts a loop it ends with a colon and the body of the loop follows either on the same line or indented on the next lines. If 'while' ends a 'repeat' loop it doesn't end with a colon and there isn't anything following on the same line or indented on the next lines.
16-07-2009 o 00:54 Chris Rebert <pyideas@rebertia.com> wrote:
You can fix that by just writing it as:
while True: SOME ACTIONS HERE if not CONDITION: break
Yeah, but it's not the same :) because eyes must look for the actual loop condition somewhere-within-the-loop (after all, "while True" is common idiom with large field of usage, not only in such situations...). Another solution I invented for myself is to use object which once evaluates to True, then always to False, e.g.: from itertools import chain, repeat class FirstTrue(object): def __init__(self): self._iter = chain([True], repeat(False)) def __nonzero__(self): # __bool__ for Py3k return next(self._iter) Usage: first = FirstTrue() while first or CONDITION: SOME ACTIONS HERE or, if we want to *evaluate* CONDITION also at first time: first = FirstTrue() while CONDITION or first: SOME ACTIONS HERE Wouldn't be nice to have such factory as built-in or in itertools? Best regards, *j -- Jan Kaliszewski <zuo@chopin.edu.pl>
On Wed, Jul 15, 2009 at 5:16 PM, Jan Kaliszewski<zuo@chopin.edu.pl> wrote:
16-07-2009 o 00:54 Chris Rebert <pyideas@rebertia.com> wrote:
You can fix that by just writing it as:
while True: SOME ACTIONS HERE if not CONDITION: break
Yeah, but it's not the same :) because eyes must look for the actual loop condition somewhere-within-the-loop (after all, "while True" is common idiom with large field of usage, not only in such situations...).
Another solution I invented for myself is to use object which once evaluates to True, then always to False, e.g.:
from itertools import chain, repeat class FirstTrue(object): def __init__(self): self._iter = chain([True], repeat(False)) def __nonzero__(self): # __bool__ for Py3k return next(self._iter)
Usage:
first = FirstTrue() while first or CONDITION: SOME ACTIONS HERE
or, if we want to *evaluate* CONDITION also at first time:
first = FirstTrue() while CONDITION or first: SOME ACTIONS HERE
I usually do: FIRST = 1 while CONDITION or FIRST: FIRST = 0 SOME ACTIONS HERE I use 1/0 instead of True/False because older Pythons loaded numeric constants faster than the names True/False (is that still the case?) - Josiah
Wouldn't be nice to have such factory as built-in or in itertools?
Best regards, *j
-- Jan Kaliszewski <zuo@chopin.edu.pl> _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
On Thu, 16 Jul 2009 10:32:01 am Josiah Carlson wrote:
I use 1/0 instead of True/False because older Pythons loaded numeric constants faster than the names True/False (is that still the case?)
From Python 2.6.1:
import dis dis.dis(compile("while 1: break", "", "exec")) 1 0 SETUP_LOOP 4 (to 7) >> 3 BREAK_LOOP 4 JUMP_ABSOLUTE 3 >> 7 LOAD_CONST 0 (None) 10 RETURN_VALUE dis.dis(compile("while True: break", "", "exec")) 1 0 SETUP_LOOP 13 (to 16) >> 3 LOAD_NAME 0 (True) 6 JUMP_IF_FALSE 5 (to 14) 9 POP_TOP 10 BREAK_LOOP 11 JUMP_ABSOLUTE 3 >> 14 POP_TOP 15 POP_BLOCK >> 16 LOAD_CONST 0 (None) 19 RETURN_VALUE
True is a constant in Python 3.0. -- Steven D'Aprano
Steven D'Aprano wrote:
On Thu, 16 Jul 2009 10:32:01 am Josiah Carlson wrote:
I use 1/0 instead of True/False because older Pythons loaded numeric constants faster than the names True/False (is that still the case?)
From Python 2.6.1:
import dis dis.dis(compile("while 1: break", "", "exec")) 1 0 SETUP_LOOP 4 (to 7) >> 3 BREAK_LOOP 4 JUMP_ABSOLUTE 3 >> 7 LOAD_CONST 0 (None) 10 RETURN_VALUE dis.dis(compile("while True: break", "", "exec")) 1 0 SETUP_LOOP 13 (to 16) >> 3 LOAD_NAME 0 (True) 6 JUMP_IF_FALSE 5 (to 14) 9 POP_TOP 10 BREAK_LOOP 11 JUMP_ABSOLUTE 3 >> 14 POP_TOP 15 POP_BLOCK >> 16 LOAD_CONST 0 (None) 19 RETURN_VALUE
True is a constant in Python 3.0.
In 3.1
dis.dis(compile("while True: break", "", "exec")) 1 0 SETUP_LOOP 4 (to 7) >> 3 BREAK_LOOP 4 JUMP_ABSOLUTE 3 >> 7 LOAD_CONST 0 (None) 10 RETURN_VALUE
Same as while 1 tjr
As Xavier noticed, my second example is buggy -- pls forget about it...
or, if we want to *evaluate* CONDITION also at first time:
first = FirstTrue() while CONDITION or first: SOME ACTIONS HERE
It means it's time for me to go to bed :) [02:36] Cheers, *j
On Wed, Jul 15, 2009 at 2:16 PM, Jan Kaliszewski<zuo@chopin.edu.pl> wrote:
16-07-2009 o 00:54 Chris Rebert <pyideas@rebertia.com> wrote:
You can fix that by just writing it as:
while True: SOME ACTIONS HERE if not CONDITION: break
Yeah, but it's not the same :) because eyes must look for the actual loop condition somewhere-within-the-loop (after all, "while True" is common idiom with large field of usage, not only in such situations...).
I think we can just piggyback off of Python's existing optional support for braces, BEGIN, END, etc.: while True: #DO WHILE COND { something # } if cond: break :-D My favorite proposal out of the last discussion of do-while was to make "while:" mean "while True:". Combined with Python's optional support for braces, it sounds like a winner to me! :-D Optionally-yrs, -- Carl Johnson
On Thu, 16 Jul 2009 08:50:06 am Jan Kaliszewski wrote:
Hello,
The issue has been coming back repeatedly:
And not very long ago at that. Please have a read of this thread: http://mail.python.org/pipermail/python-ideas/2009-April/004306.html and (if I may be so immodest to link to my own post) especially this one where I discuss various possible ways of spelling the loop: http://mail.python.org/pipermail/python-ideas/2009-April/004326.html
Maybe here the simplest approach can lead us to the solution? I.e.:
repeat while CONDITION: SOME ACTIONS HERE ...
(1) I dislike that it puts the test at the top of the loop even though it is not tested until the bottom. (2) I dislike that it has two keywords back-to-back. (3) I prefer to swap the sense of the test. Rather than end the loop when CONDITION becomes false, I'd prefer the Pascal semantics of ending the loop when CONDITION becomes true. Using your proposed syntax, that would become: repeat until CONDITION: block Now we can discard the redundant double keyword and just write: until CONDITION: block which is still funny because the test is at the top of the block although it's not tested until the bottom.
In human language it'd mean: do ACTIONS once unconditionally, then *repeat* them while the CONDITION is true.
Additional advantage is that probably for many people associate 'repeat' with such construction (from experience with other languages).
Other people associate 'do' with such a construction. I suspect we are doomed to keep re-visiting this question until Python5K, because (1) there are so many ways of spelling a do...until loop and the differences are (almost entirely) just aesthetic; and (2) there is no overwhelming advantage to do...until compared to a while loop with an explicit break. -- Steven D'Aprano
Steven D'Aprano wrote:
On Thu, 16 Jul 2009 08:50:06 am Jan Kaliszewski wrote:
Hello,
The issue has been coming back repeatedly:
And not very long ago at that.
So often that there's even a PEP* that documents the pros and cons of different ideas and points out that a viable syntactic challenger to the "while True with inner break" approach has yet to be found. The current idiom does have the downside of potentially hiding the termination condition, but it otherwise handles generalised looping very nicely. (Putting the break on a separate line also helps a great deal with the visibility of the termination condition) Cheers, Nick. * http://www.python.org/dev/peps/pep-0315/ -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
participants (8)
-
Carl Johnson
-
Chris Rebert
-
Jan Kaliszewski
-
Josiah Carlson
-
MRAB
-
Nick Coghlan
-
Steven D'Aprano
-
Terry Reedy