Hello, I think adding an optional "WHILE" clause in "FOR" loops might be useful sometimes (shorter code and/or improved readability): for #VAR# in #SEQUENCE# while #WATCHDOG_EXPRESSION#: #CODE_BLOCK# Examples: keepRunning = True for i in range(100) while keepRunning: keepRunning = do_some_work( i ) found = False for candidate in sequence while not found: try: process( candidate ) found = True except InvalidCandidate: pass retryCount = 7 for i in range(1,1+retryCount) while resource.acquire() == FAIL: sleep( i**2 ) At the moment, I usually implement this either with ugly breaks: for i in range(100): if not do_some_work( i ): break found = False for candidate in sequence: try: process_candidate() except InvalidCandidate: pass else: found = True break Or with while loops and counters (or counting-like expressions): i = 1 while i <= retryCount and not resource.acquired: if resource.acquire() == FAIL: sleep( i**2 ) i += 1 Of course, actual code tends to be more complex, with "keepRunning" being modified in some branches of "IF" blocks, and there might be nested loops where the exit condition for the outer one is set in the inner loop. Compare these two examples: found = False for filePath in glob( '*.data' ): for line in open( filePath, 'rt' ): if line.startswith( '#' ): continue if handle( line ): found = True break if found: break found = False for filePath in glob( '*.data' ) while not found: for line in open( filePath, 'rt' ) while not found: if line.startswith( '#' ): continue if handle( line ): found = True -- Alejandro
On Thu, Feb 20, 2014 at 12:34 AM, Alejandro López Correa
I think adding an optional "WHILE" clause in "FOR" loops might be useful sometimes (shorter code and/or improved readability):
for #VAR# in #SEQUENCE# while #WATCHDOG_EXPRESSION#: #CODE_BLOCK#
Suggestion: Look at REXX's loops for some ideas and use-cases. http://www.kilowattsoftware.com/tutorial/rexx/do.htm REXX lets you combine zero or more loop conditions, including "WHILE condition", "FOR iteration_count", and so on. You may also want to consider a filtered iteration, with "IF condition" (which would be like putting "if not condition: continue" at the top of the loop). There are definite use-cases for all of these. The question is, which ones are worth blessing with syntax? ChrisA
There are definite use-cases for all of these. The question is, which ones are worth blessing with syntax?
ChrisA
The addition of a while clause to for loops has the advantage that it
does not require any new keyword, and adds some extra power to the
limited for loops of python (compared to c/c++ for loops, for example)
in a natural way IMHO. Of course it is not a must-have feature or
something along these lines would have been already in place. For
example, I miss sometimes constructs from c or pascal (IIRC) like
"repeat STATEMENT until EXPRESSION" or "do STATEMENT while EXPRESSION"
because the expression is evaluated after one iteration and that means
vars in it do not need to be initialized before the loop. However, I
understand adding such keywords as "repeat" or "do" to the language
would break existing code that might use them as var names.
2014-02-19 15:46 GMT+01:00 Rob Cliffe
It seems to me this would be the same as
for #VAR# in #SEQUENCE#: if not (#WATCHDOG_EXPRESSION#): break #CODE_BLOCK#
which doesn't really seem to me to justify adding new syntax. Rob Cliffe
I was going to argue about higher readability and the case of nested loops, but then I've realised it might be unintuitive: sometimes it might seem natural that the first element in the sequence is consumed, sometimes the programmer might want the loop to not be entered at all if the expression is already false. This is of relevance in case of generators. # at least one element is extracted from a non-empty sequence for x in sequence while x > 0: pass # here it might be expected to not enter the loop at all if keepRunning is False, and thus leave the sequence untouched. for x in sequence while keepRunning: pass So forget about it. Sorry for the lost time. Alejandro
On 19/02/2014 13:34, Alejandro López Correa wrote:
Hello,
I think adding an optional "WHILE" clause in "FOR" loops might be useful sometimes (shorter code and/or improved readability):
for #VAR# in #SEQUENCE# while #WATCHDOG_EXPRESSION#: #CODE_BLOCK# It seems to me this would be the same as
for #VAR# in #SEQUENCE#: if not (#WATCHDOG_EXPRESSION#): break #CODE_BLOCK# which doesn't really seem to me to justify adding new syntax. Rob Cliffe
On 19 February 2014 13:34, Alejandro López Correa
Hello,
I think adding an optional "WHILE" clause in "FOR" loops might be useful sometimes (shorter code and/or improved readability):
for #VAR# in #SEQUENCE# while #WATCHDOG_EXPRESSION#: #CODE_BLOCK#
This idea comes up repeatedly. You might want to read some of the previous discussions about it: https://mail.python.org/pipermail/python-ideas/2013-January/018969.html https://mail.python.org/pipermail/python-ideas/2009-January/002466.html https://mail.python.org/pipermail/python-ideas/2013-June/021554.html Oscar
On Feb 19, 2014, at 5:34, Alejandro López Correa
Hello,
I think adding an optional "WHILE" clause in "FOR" loops might be useful sometimes (shorter code and/or improved readability):
for #VAR# in #SEQUENCE# while #WATCHDOG_EXPRESSION#: #CODE_BLOCK#
Examples:
keepRunning = True for i in range(100) while keepRunning: keepRunning = do_some_work( i )
found = False for candidate in sequence while not found: try: process( candidate ) found = True except InvalidCandidate: pass
retryCount = 7 for i in range(1,1+retryCount) while resource.acquire() == FAIL: sleep( i**2 )
At the moment, I usually implement this either with ugly breaks:
for i in range(100): if not do_some_work( i ): break
The only reason you think they're "ugly" is that you're thinking in C terms, not Python terms. This version is shorter, it's more explicit, and it has fewer places for you or after code maintainer to screw up and create bugs. (And yes, even in a trivial case like this, I've seen people write keepRunnig = ...) And this becomes even more apparent in the longer cases. You're relying on the fact that setting a flag _plus_ falling off the end of a loop (which isn't nearly as obvious or visible or explicit) equals break.
found = False for candidate in sequence: try: process_candidate() except InvalidCandidate: pass else: found = True break
Here, you don't need found at all. I suspect you're not using for...else because C doesn't have it?
Or with while loops and counters (or counting-like expressions):
i = 1 while i <= retryCount and not resource.acquired: if resource.acquire() == FAIL: sleep( i**2 ) i += 1
Of course, actual code tends to be more complex, with "keepRunning" being modified in some branches of "IF" blocks, and there might be nested loops where the exit condition for the outer one is set in the inner loop. Compare these two examples:
found = False for filePath in glob( '*.data' ): for line in open( filePath, 'rt' ): if line.startswith( '#' ): continue if handle( line ): found = True break if found: break
found = False for filePath in glob( '*.data' ) while not found: for line in open( filePath, 'rt' ) while not found: if line.startswith( '#' ): continue if handle( line ): found = True
-- Alejandro _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On 2014-02-19, at 14:34 , Alejandro López Correa
Hello,
I think adding an optional "WHILE" clause in "FOR" loops might be useful sometimes (shorter code and/or improved readability):
It seems judicious application of itertools can do the job.
for #VAR# in #SEQUENCE# while #WATCHDOG_EXPRESSION#: #CODE_BLOCK#
Examples:
keepRunning = True for i in range(100) while keepRunning: keepRunning = do_some_work( i )
found = False for candidate in sequence while not found: try: process( candidate ) found = True except InvalidCandidate: pass
retryCount = 7 for i in range(1,1+retryCount) while resource.acquire() == FAIL: sleep( i**2 )
At the moment, I usually implement this either with ugly breaks:
for i in range(100): if not do_some_work( i ): break
for i in takewhile(do_some_work, range(100)): pass
found = False for candidate in sequence: try: process_candidate() except InvalidCandidate: pass else: found = True break
for candidate in sequence: try: process_candidate() except InvalidCandidate: pass else: # found break else: # not found
Or with while loops and counters (or counting-like expressions):
i = 1 while i <= retryCount and not resource.acquired: if resource.acquire() == FAIL: sleep( i**2 ) i += 1
Of course, actual code tends to be more complex, with "keepRunning" being modified in some branches of "IF" blocks, and there might be nested loops where the exit condition for the outer one is set in the inner loop. Compare these two examples:
found = False for filePath in glob( '*.data' ): for line in open( filePath, 'rt' ): if line.startswith( '#' ): continue if handle( line ): found = True break if found: break
found = False for filePath in glob( '*.data' ) while not found: for line in open( filePath, 'rt' ) while not found: if line.startswith( '#' ): continue if handle( line ): found = True
# itertools's missing piece flatmap = lambda fn, *it: chain.from_iterable(imap(fn, *it)) lines = flatmap(open, iglob('*.data'), repeat('rb') non_comments = ifilter(lambda line: not line.startswith('#'), lines) matches = ifilter(handle, non_comments) match = next(matches, None) Alternatively the filters could be replaced by matches =(line for line in lines if not line.startswith('#') if handle(line))
participants (6)
-
Alejandro López Correa
-
Andrew Barnert
-
Chris Angelico
-
Masklinn
-
Oscar Benjamin
-
Rob Cliffe