I had a thought that might be pepworthy. Might we be able to break outer loops using an iter-instance specific StopIteration type?
This is the desired, if not desirable, syntax::
import string letters = iter(string.lowercase) for letter in letters: for number in range(10): print letter, number if letter == 'a' and number == 5: raise StopIteration() if letter == 'b' and number == 5: raise letters.StopIteration()
The first StopIteration would halt the inner loop. The second StopIteration would halt the outer loop. The inner for-loop would note that the letters.StopIteration instance is specifically targeted at another iteration and raise it back up.
For this output::
a 0 a 1 a 2 a 3 a 4 a 5 b 0 b 1 b 2 b 3 b 4 b 5
This could be incrementally refined with the addition of an "as" clause to "for" that would be bound after an iterable is implicitly iter()ed::
import string for letter in string.lowercase as letters: … raise letters.StopIteration()
I took the liberty to create a demo using a "for_in" decorator instead of a "for" loop::
former_iter = iter
class iter(object): def __init__(self, values): if hasattr(values, 'next'): self.iter = values else: self.iter = former_iter(values) class Stop(StopIteration): pass if hasattr(values, 'StopIteration'): self.StopIteration = values.StopIteration else: self.StopIteration = Stop
def for_in(values): def decorate(function): iteration = iter(values) while True: try: function(iteration.next()) except iteration.StopIteration: break except StopIteration, exception: if type(exception) is StopIteration: break else: raise return decorate
import string letters = iter(string.lowercase)
@for_in(letters) def _as(letter): @for_in(range(10)) def _as(number): print letter, number if letter == 'a' and number == 5: raise StopIteration() if letter == 'b' and number == 5: raise letters.StopIteration()
I imagine that this would constitute a lot of overhead in StopIteration type instances, but perhaps a C implementation would use flyweight StopIteration types for immutable direct subtypes of the builtin StopIteration.
On Jun 10, 10:07 am, "Kris Kowal" <kris.ko...@cixar.com> wrote:
> I had a thought that might be pepworthy. Might we be able to break > outer loops using an iter-instance specific StopIteration type?
> This is the desired, if not desirable, syntax::
> import string > letters = iter(string.lowercase) > for letter in letters: > for number in range(10): > print letter, number > if letter == 'a' and number == 5: > raise StopIteration() > if letter == 'b' and number == 5: > raise letters.StopIteration()
It contains exactly this idea, but using 'break letters' rather than 'raise letters.StopIteration()'. I think I like the PEP's syntax better than yours, but anyway, it was rejected.
> It contains exactly this idea, but using 'break letters' rather than > 'raise letters.StopIteration()'. I think I like the PEP's syntax > better than yours, but anyway, it was rejected.
I concur that "break letters" is better than "raise letters.StopIteration()". Perhaps the novelty of the implementation idea (adding another exception case to the "while: try" that must already be there, and the specialized exception type) can wake this dead issue. Maybe "break letters" could under the hood raise the specialized StopIteration.
But, then again. Guido has said, "No", already on other, albeit subjective, grounds. I'll drop it or champion it if there's interest.
> I had a thought that might be pepworthy. Might we be able to break > outer loops using an iter-instance specific StopIteration type?
> This is the desired, if not desirable, syntax::
> import string > letters = iter(string.lowercase) > for letter in letters: > for number in range(10): > print letter, number > if letter == 'a' and number == 5: > raise StopIteration() > if letter == 'b' and number == 5: > raise letters.StopIteration()
I must say, I don't even like the idea of having a 'break', but I kind of like this proposal.
However, it may be ambiguous [is that a word?] if the outer and inner for loop over the same object. Weird/unlikely situation, I know... but so is having a deep break :D.
On Jun 9, 8:07 pm, "Kris Kowal" <kris.ko...@cixar.com> wrote:
> I had a thought that might be pepworthy. Might we be able to break > outer loops using an iter-instance specific StopIteration type?
> This is the desired, if not desirable, syntax::
> import string > letters = iter(string.lowercase) > for letter in letters: > for number in range(10): > print letter, number > if letter == 'a' and number == 5: > raise StopIteration() > if letter == 'b' and number == 5: > raise letters.StopIteration()
You can break out of outer loops now with the proper (ab)use of exceptions:
class BreakOuter(Exception): pass
try: for letter in string.lowercase: for number in xrange(10): print letter, number if letter == 'a' and number == 5: break if letter == 'b' and number == 5: raise BreakOuter() except BreakOuter: pass
Or, for consistency:
class BreakInner(Exception): pass
class BreakOuter(Exception): pass
try: for letter in string.lowercase: try: for number in xrange(10): print letter, number if letter == 'a' and number == 5: raise BreakInner() if letter == 'b' and number == 5: raise BreakOuter() except BreakInner: pass except BreakOuter: pass
> I had a thought that might be pepworthy. Might we be able to break > outer loops using an iter-instance specific StopIteration type?
> This is the desired, if not desirable, syntax::
> import string > letters = iter(string.lowercase) > for letter in letters: > for number in range(10): > print letter, number > if letter == 'a' and number == 5: > raise StopIteration() > if letter == 'b' and number == 5: > raise letters.StopIteration()
> The first StopIteration would halt the inner loop. The second > StopIteration would halt the outer loop. The inner for-loop would > note that the letters.StopIteration instance is specifically targeted > at another iteration and raise it back up.
For the record: I share GvR's opinion on the general usefulness.
Additionally, your syntax is impossible. There isn't always a containing variable for the iterable.
And if you meant "letter", it's ambigous. It is perfectly legal in python to do this:
class Foo(object): StopIteration = StopIteration
for letter in [Foo(), Foo()]: for number in range(10): raise letter.StopIteration
> On Jun 9, 8:07 pm, "Kris Kowal" <kris.ko...@cixar.com> wrote:
> > I had a thought that might be pepworthy. Might we be able to break > > outer loops using an iter-instance specific StopIteration type?
> You can break out of outer loops now with the proper (ab)use of > exceptions:
> class BreakInner(Exception): > pass > class BreakOuter(Exception): > pass > try: > for letter in string.lowercase: > try: > for number in xrange(10): > print letter, number > if letter == 'a' and number == 5: > raise BreakInner() > if letter == 'b' and number == 5: > raise BreakOuter() > except BreakInner: > pass > except BreakOuter: > pass
I prefer having a new function wrapping the inner loop and using both break and return, but this doesn't allow you to "break 1 loop up and 2 loops up", and doesn't help to continue a particular loop further up
def innerLoop(letter): for number in xrange(10): print letter, number if letter == 'a' and number == 5: break if letter == 'b' and number == 5: return
for letter in string.lowercase: innerLoop(letter)
In response to the suggested syntax, I have found occasions where I iterate through the same variable [say searching for duplicates within some tolerance to merge into one item] in an inner loop. I also don't see how it would extend to something like:
for evenNumber in [x*2+1 for x in xrange(5)]: print evenNumber