Monday, January 14, 2008

Pitfalls in handling multiple exceptions: UnboundLocalError: local: 'ValueError'

The below code raised UnboundedLocalException for 'ValueError' which is builtin. I wondered how it could be unbounded and tried to figure out what went wrong and this is what I got.
              try:
#code to do something
if (condition):
raise ValueError
except java.lang.NullPointerException, ValueError:
#code to print exception message
continue



UnboundLocalError: local: 'ValueError'


This is when I learnt about one of the inner workings of python.

The python interpretor scans the code block once. if a name is bound to a variable with out being specified as global, it is considered local.
e.g:

x = 2
def func():
x = 3
print x
func()
print x


will print

3

2

This is because in func, x is bound locally to the variable containing the value <3>.

But the same function with the small difference will fail with 'UnBoundLocalError: local: x':
x = 2
def func():
print x
x = 3
func()
print x


This is again because, the interpreter first scans func. It sees x is bound locally as it is assigned a value 3 within the innerscope. When it tries to execute, the print statement precedes the binding statement. At the point, x is a free variable with no binding. Hence the error.

Now in the case of the exception handling,

The construct is


try:
#Do something
except Exception, e:
#e is bound to exception obj.
#Do something with e


e is actually bound to the instance of the class Exception and becomes a local variable.

Now considering the initial scenario, the ValueError name is bound to the instance of the 'java.lang.NullPointerException' exception. This overrides the scope of the global builtins and makes ValueError a binding to local variable and the binding happens at the except line. So when raise ValueError is called an UnboundLocalError is thrown.

So how to we handle multiple exceptions?

              try:
#code to do something
if (condition):
raise ValueError
except (java.lang.NullPointerException, ValueError):
#code to print exception message
continue



For more interesting patterns see here.

No comments: