Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

try yield finally - did we raise an exception?

TL;DR

Is it possible to find out in a finally clause whether there's an outstanding uncaught exception?

Background

I want to iterate over items to do some relatively expensive processing on them, which is likely to break and raise an exception. So I'd like to save my place. But saving state is also pretty expensive - so I'd rather not do it every single time, just when there's an exception in the code I yield to.

I'm imagining something vaguely shaped like:

def get_things(my_iterator):
    for items in my_iterator:
        try:
            yield item
        finally:
            if something_went_wrong():  # magic oracle function for failure
                save_state(item)
        continue_normal_processing()

but I don't know whether that's even possible. Notably, except Exception: doesn't raise anything, because the exception isn't in this function.

like image 716
Dragon Dave Avatar asked Apr 28 '14 17:04

Dragon Dave


People also ask

How do you catch an exception in try finally statement?

Alternatively, you can catch the exception that might be thrown in the try block of a try - finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try - finally statement, or in the method that calls that method, or in any method in the call stack.

How do you use try in a try statement?

A try statement includes keyword try, followed by a colon (:) and a suite of code in which exceptions may occur. It has one or more clauses. During the execution of the try statement, if no exceptions occurred then, the interpreter ignores the exception handlers for that specific try statement.

How do you raise an exception in an except clause?

In an except clause, we can use a "raise" statement with no argument. This reraises the exception. Here: The "raise" statement the exception not to be captured. The print-statement is executed before the program terminates.

What is the use of Try...Finally in C++?

The try...finally expression enables you to execute clean-up code even if a block of code throws an exception. The try...finally expression can be used to execute the code in expression2 in the preceding syntax regardless of whether an exception is generated during the execution of expression1.


2 Answers

... seems I was totally wrong about except's behaviour.

def f():
    for i in range(10):
        try:
            yield i
        except Exception:
            print "Nope, this broke"
            raise


for x in f():
    print x
    if x == 2:
        raise IndexError

returns

0
1
2
Nope, this broke
Traceback (most recent call last):
...
IndexError
like image 170
Dragon Dave Avatar answered Sep 21 '22 03:09

Dragon Dave


This should be similar to what you want:

class CatchingExceptionsIterator:
    def __init__(self, generator):
        self.generator = generator
        self.error = None
    def __enter__(self):
        return self
    def next(self):
        if self.error is None:
            return next(self.generator)
        else:
            error = self.error
            self.error = None
            return self.generator.throw(*error)
    __next__ = next
    def __exit__(self, ty, err, tb):
        if ty is not None:
            self.error = ty, err, tb
            return True
    def __iter__(self):
        return self


def f():
    for i in range(10):
        try:
            print("yield")
            yield i
            print("returnFomYield")
        except:
            import traceback
            traceback.print_exc()


c = CatchingExceptionsIterator(f())
for i in c:
    with c:
        print(i)
        if i == 5:
            nameerror

It must be adjusted to fit the exact usecase.
The output is:

yield
0
returnFomYield
yield
1
returnFomYield
yield
2
returnFomYield
yield
3
returnFomYield
yield
4
returnFomYield
yield
5
Traceback (most recent call last):
  File "withiteration.py", line 27, in f
    yield i
  File "withiteration.py", line 39, in <module>
    nameerror
NameError: name 'nameerror' is not defined
yield
6
returnFomYield
yield
7
returnFomYield
yield
8
returnFomYield
yield
9
returnFomYield

An additional finally clause would also be executed.

Is it possible to find out in a finally clause whether there's an outstanding uncaught exception?

Why? You could use except. Explain this in more detail.

like image 35
User Avatar answered Sep 22 '22 03:09

User