I have the following code:
def foo():
e = None
try:
raise Exception('I wish you would except me for who I am.')
except Exception as e:
print(e)
print(e)
foo()
In Python 2.7, this runs as expected and prints:
I wish you would except me for who I am.
I wish you would except me for who I am.
However in Python 3.x, the first line is printed, but the second line is not. It seems to delete the variable in the enclosing scope, giving me the following traceback from the last print statement:
Traceback (most recent call last):
File "python", line 9, in <module>
File "python", line 7, in foo
UnboundLocalError: local variable 'e' referenced before assignment
It is almost as if a del e
statement is inserted after the except
block. Is there any reasoning for this sort of behavior? I could understand it if the Python developers wanted except blocks to have their own local scope, and not leak into the surrounding scope, but why must it delete a variable in the outer scope that was previously assigned?
Enclosing (or nonlocal) scope is a special scope that only exists for nested functions. If the local scope is an inner or nested function, then the enclosing scope is the scope of the outer or enclosing function. This scope contains the names that you define in the enclosing function.
The scope defines the accessibility of the python object. To access the particular variable in the code, the scope must be defined as it cannot be accessed from anywhere in the program. The particular coding region where variables are visible is known as scope.
A variable is only available from inside the region it is created. This is called scope.
Variables that are defined inside a function body have a local scope, and those defined outside have a global scope. This means that local variables can be accessed only inside the function in which they are declared, whereas global variables can be accessed throughout the program body by all functions.
Quoting the documentation of try
,
When an exception has been assigned using
as target
, it is cleared at the end of the except clause. This is as ifexcept E as N: foo
was translated to
except E as N: try: foo finally: del N
This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.
This is covered in these two PEPs.
PEP 3110 - Catching Exceptions in Python 3000
PEP 344 - Exception Chaining and Embedded Tracebacks
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