I found myself needing a contextual behavior inside the loop, for instance, a for loop going over a generator, which upon encountering an exception (anything but StopIteration), logs it and continues to the next item.
The problem is, that generators’ implementation doesn’t support any contextual behavior apart from
__exit__ which only apply for the loop as a whole, and not for each iteration by itself.
I wonder how broad is this need, whether or not you folks think this is a problem worth addressing, and finally, if theres any simple solution i’m missing?
all the best, be gentle with me it’s my first ever post here
This isn’t really to do with loops, but generators themselves: if a
generator raises an exception, it terminates, like any other function.
So there’s no “resume” for the for-loop to continue with; the
Possibly the simplest solution is that the generator doesn’t raise an
exception but yields it inline with whatever other values it in
for ch in 'abc':
assert ch != 'b'
except AssertionError as e:
This would yield:
AssertionError # an AssertionError instance
chars = 
for ch in gen():
if isinstance(ch, Exception):
warning("got an exception: %s", ch)
or something like that.
Cameron Simpson firstname.lastname@example.org
of course this solves this specific instance of the question, but not nearly covers the scope.
I think a more generic approach is to use a contextmanager inside the loop, wrapping the indented block, but what I was suggesting is to solve it in the generator, in a specifically dedicated functions resembling the enter and exit mechanisms but in finer granularity
Can you write an example of what hypothetical syntax you’d like to have
Cameron Simpson email@example.com
Of course, in the for loop itself i expect no modifications, however, inside the generator class I would expect a function looking something like this:
def __enter_iteration__(self, item):
# Here will be a hook for each running immediately after the "next" function invocation
def __exit_iteration__(self, item):
# Here will be a hook for each running at the end of the current iteration
Couldn’t you achieve the same thing with this?
for ch in "abc":
# __exit_iteration__ logic
Isn’t this all logic that can be put in
__next__ now, without any changes to the iterator protocol?
# Stuff from __enter_iteration__
rv = ...
# Stuff from __exit_iteration__
# No loop necessary; the try statement wraps the yield statement no matter
# where it occurs.
In the worst case scenario, you just don’t use a
for loop (which “hides” the call to
next that raises the exception), but use a
while loop to iterate.
# Equivalent of
# for v in your_iterable:
itr = iter(your_iterable) # Exception unlikely, but you can put this in a try statement
v = next(itr)
This is all pretty broad; if there’s a use case you have in mind that doesn’t fit well into any of these three examples, I’d be interested to see it.
Yep that solves it can’t think of a case not covered here.
Could you expand a bit on how this solves the problem you describe in the OP?
Namely, blankly catching any exception but
StopIteration, logging it and proceeding to the next item in the iterable.
I am interest in this.