Search code examples
pythonexceptiongeneratorexcept

Keeping try block small when catching exceptions in generator


How can I keep the try block as small as possible when I have to catch an exception which can occur in a generator?

A typical situation looks like this:

for i in g():
  process(i)

If g() can raise an exception I need to catch, the first approach is this:

try:
  for i in g():
    process(i)
except SomeException as e:
  pass  # handle exception ...

But this will also catch the SomeException if it occurs in process(i) (this is what I do not want).

Is there a standard approach to handle this situation? Some kind of pattern?

What I am looking for would be something like this:

try:

  for i in g():

except SomeException as e:
  pass  # handle exception ...

    process(i)

(But this is syntactic nonsense of course.)


Solution

  • You could convert exceptions occurring in the inner block:

    class InnerException(Exception):
      pass
    
    try:
      for i in g():
        try:
          process(i)
        except Exception as ex:
          raise InnerException(ex)
    except InnerException as ex:
      raise ex.args[0]
    except SomeException as e:
      pass  # handle exception ...
    

    Another option is to write a local generator that wraps g:

    def safe_g():
      try:
        for i in g():
          yield i
      except SomeException as e:
        pass  # handle exception ...
    for i in safe_g():
      process(i)