Is it possible to find out in a finally clause whether there's an outstanding uncaught exception?
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.
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.
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.
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.
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.
... 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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With