try:
...
except (SomeError) as err:
...
else:
...
finally:
if err:
...
This gives an error: 'err not defined'. Because the exception argument - err - is not defined as far as the finally block is concerned. It appears then that the exception argument is local to the exception block.
You can get round it by copying err to another variable defined outside the block:
teleport = ""
try:
...
except (SomeError) as err:
teleport = err
else:
...
finally:
if teleport:
...
But why can't you simply reference the exception argument in the finally block? (Assuming I've not overlooked something else.)
try blocks will execute code that could possibly raise an exception. except block will execute the moment an exception is raised. The else block executes if no except is raised, and the finally block is executed no matter what.
There is no point in checking for an exception in the finally block when you can just do that in the else block.
Aside from that, the variable was likely garbage collected at the end of execution of the except block. It's similar to what happens with with blocks. This is why you can't do if err:
You cannot access just because exception is not raised and so variable is not defined, hence the undefined variable error. Besides there is no point in dealing with exception in your final block, you should do that stuff in except block itself.
Related
I have a function within a module, that does something like this:
def some_func():
try:
# do some error-prone thing
raise ValueError
return 'calculated foo'
except AttributeError as err:
# handle it
pass
except:
print('Some other error happened, let\'s reraise it....')
raise
else:
pass
finally:
return 'default foo'
Then within my main program,
try:
val = some_func()
print('val=', val)
except:
print('In main except')
raise
else:
print('In main else')
pass
finally:
print('And we\'re done')
My output is:
Some other error happened, let's reraise it....
val= default foo
In main else
And we're done
No exception is raised.
At the risk of missing something obvious, why isn't the ValueError being reraised within my main? It almost seems like the return within my finally in some_func() is causing the exception not to be reraised, but this seems odd to me and I can't find any documentation of it. Here's what I think should be happpening, would like to understand where I'm off.
I call some_func() within my main program
some_func() raises ValueError
The ValueError is caught within the some_func() except, prints "Some other error happened" and reraises it.
Back in main, I thought the reraised ValueError should get caught by the except, should print 'In main except', reraise, and then the exception itself should be uncaught causing the program to halt. But I get no exception raised and wind up in the else clause instead.
This is intended behavior and described in the documentation:
If finally is present, it specifies a ‘cleanup’ handler. (...) If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. (...) If the finally clause executes a return, break or continue statement, the saved exception is discarded
This question already has an answer here:
Why do I get a `NameError` (or `UnboundLocalError`) from using a named exception after the `except` block?
(1 answer)
Closed 3 years ago.
Consider the following piece of code:
import shutil
import time
t = time.time()
exception = None
while time.time() < (t + 10.0):
try:
shutil.rmtree('/path-to-non-existent-directory')
break
except OSError as exception:
pass
time.sleep(0.1)
else:
if exception:
raise exception
In Python 2.7 this code is perfectly valid but in Python 3.7 I get the following warning:
Local variable exception might be referenced before assignment
In the else clause.
Does anyone have an idea what is wrong with this snippet when run in Python 3.7?
In Python 3, to resolve a circular reference issue caused by the introduction of the __traceback__ attribute, an except target is automatically deleted at the end of an except block. It behaves as if you had written
except OSError as exception:
pass
del exception
This is documented in PEP 3110.
If you want to preserve the exception object, you should save it to a second variable:
except OSError as exception:
saved_exception = exception
exception will still be deleted, but you can use saved_exception to inspect the exception object after the except block is over.
Python is a block scoped language, you can't reference a variable outside of the block in which it was defined and you can't use a new value outside of the block in which that variable was updated.
In other words, you can't reference the exception variable's error data outside of the except block, if you try to do so, the value of the exception variable will be None (which you set at the top-level).
Try moving the contents of your else block to the except block and get rid of the exception = None and if exception, like this:
timer = Timer(10.0)
while timer.alive:
try:
shutil.rmtree(cls.workspace)
break
except OSError as exception:
raise exception
time.sleep(0.1)
If you don't want fatal errors, you could just use the print() function instead of the raise keyword:
timer = Timer(10.0)
while timer.alive:
try:
shutil.rmtree(cls.workspace)
break
except OSError as exception:
print(exception)
time.sleep(0.1)
Here is another example (which won't work):
def hello():
message = "Hello World"
print(message)
Because it'll raise the the following error:
NameError: name 'message' is not defined
NOTE: I'd advice against calling your exception exception, because there's an error class called Exception and doing so could lead to confusion later on.
Good luck.
When I run this code:
i=0
while i<5:
i=i+1;
try:
SellSta=client.get_order(symbol=Symb,orderId=SellOrderNum,recvWindow=Delay)
except client.get_order as e:
print ("This is an error message!{}".format(i))
#End while
I got this error:
TypeError: catching classes that do not inherit from BaseException is not allowed
I read this tread Exception TypeError warning sometimes shown, sometimes not when using throw method of generator and this one Can't catch mocked exception because it doesn't inherit BaseException also read this https://medium.com/python-pandemonium/a-very-picky-except-in-python-d9b994bdf7f0
I kind of fix it with this code:
i=0
while i<5:
i=i+1;
try:
SellSta=client.get_order(symbol=Symb,orderId=SellOrderNum,recvWindow=Delay)
except:
print ("This is an error message!{}".format(i))
#End while
The result it's that ignores the error and go to the next while but I want to catch the error and print it.
I post the question in Spanish Stack with better results.
To translate and sum up:
The error occurs because in the exception clause you must indicate which exception you capture. An exception is a class that inherits (directly or indirectly) from the base class Exception.
Instead I have put client.get_order where python expected the name of the exception, and what you have put is a method of an object, and not a class that inherits from Exception.
The solution goes this way
try:
SellSta=client.get_order(symbol=Symb,orderId=SellOrderNum,recvWindow=Delay)
except Exception as e:
if e.code==-2013:
print ("Order does not exist.");
elif e.code==-2014:
print ("API-key format invalid.");
#End If
You'll need to code for every exception in here
When I put in a finally clause, the raise statement in except doesn't work.
So the except block doesn't produce an Exception.
What am I missing? What do I need to do if I want to re-raise the Exception after the finally clause returns the value?
def test():
res = 1
try:
raise Exception
res = 2
except:
print('ha fallado')
raise
finally:
return res
test()
Solution:
def test():
res = 1
try:
raise Exception
res = 2
except:
print('ha fallado')
raise
finally:
# ... finally code that need to exec
pass
return res
print(test())
In this way if a Exception happened, the except block handle the exception and then raise it.
If not exception happened return the value.
Thanks for all the answers! So quick :)
Here is an answer that quotes the relevant part of the documentation:
The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception it is re-raised at the end of the finally clause. If the finally clause raises another exception, the saved exception is set as the context of the new exception. If the finally clause executes a return or break statement, the saved exception is discarded:
>>> def f():
... try:
... 1/0
... finally:
... return 42
...
>>> f()
42
P.S. I don't quite understand what you actually want to achieve; as noted in the top answer linked by zmbq, you can't really have both.
That's because you put a return statement in the finally block. It means you really want to return a value, even if an exception is thrown.
See here for more information.
I find myself doing this when I want to catch an exception, always run some specific code, then re-raise the original exception:
try:
error = False
# do something that *might* raise an exception
except Exception:
error = True
finally:
# something I *always* want to run
if error:
raise
I am using the flag because calling raise without a previous exception raises a TypeError. Is there a more Pythonic way to do with without the flag?
Raise the exception in the except handler:
try:
# do something that *might* raise an exception
except Exception:
raise
finally:
# something I *always* want to run
The finally suite is always going to be executed wether or not you re-raised the exception.
From the documentation:
If finally is present, it specifies a ‘cleanup’ handler. The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception it is re-raised at the end of the finally clause.
Note that if the finally suite uses a break or return statement, the saved exception is discarded:
If the finally clause executes a return or break statement, the saved exception is discarded:
def f():
try:
1/0
finally:
return 42
>>> f()
42
but if you issue a break, continue or return in the try suite, the finally suite is executed still:
When a return, break or continue statement is executed in the try suite of a try...finally statement, the finally clause is also executed ‘on the way out.’
Note that before Python 2.5, you could not even combine except and finally suites in the same try statement; see PEP 341: Unified try/except/finally. Instead, you were expected to nest try statements:
try:
try:
# some code that could raise an exception
except SomeException:
# exception handler
finally:
# cleanup code, always executed
finally will always execute, no matter what happens in the try or except block, or whether the except block is even present.
Both of these will work:
try:
# do something that *might* raise an exception
finally:
# something I *always* want to run
try:
# do something that *might* raise an exception
except Exception:
raise
finally:
# something I *always* want to run