In Python 2.7, running the following code:
def f():
a = a + 1
f()
gives the following result:
Traceback (most recent call last):
File "test.py", line 4, in <module>
f()
File "test.py", line 2, in f
a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment
But if I change the code to below:
def f():
a[0] = a[0] + 1
f()
I get the different error:
Traceback (most recent call last):
File "test.py", line 4, in <module>
f()
File "test.py", line 2, in f
a[0] = a[0] + 1
NameError: global name 'a' is not defined
Why is Python considering a
is a local variable when it is an int
, global when list
? What's the rationale behind this?
P.S.: I was experimenting after reading this thread.
Local variables can only be accessed within the function or module in which they are defined, in contrast to global variables, which can be used throughout the entire program. In Python, a Global variable can be defined using the global Keyword, also we can make changes to the variable in the local context.
The main difference between Global and local variables is that global variables can be accessed globally in the entire program, whereas local variables can be accessed only within the function or block in which they are defined.
In python, nonlocal variables refer to all those variables that are declared within nested functions. The local scope of a nonlocal variable is not defined. This essentially means that the variable exists neither in the local scope nor in the global scope. Here, the inner() function is nested in nature.
Python allows the declaration of Local variable with the same name as Global variable. But in C#, if the variable is declared with a name, it doesn't allow to declare a variable with the same name inside the function and within the class.
The key is found in the documentation on the assignment statement:
Assignment of an object to a single target is recursively defined as follows.
If the target is an identifier (name) (e. g.
a = a + 1
):
- If the name does not occur in a global statement in the current code block: the name is bound to the object in the current local namespace.
- Otherwise: the name is bound to the object in the current global namespace.
The name is rebound if it was already bound. This may cause the reference count for the object previously bound to the name to reach zero, causing the object to be deallocated and its destructor (if it has one) to be called.
...
If the target is a subscription (e. g.
a[0] = a[0] + 1
): The primary expression in the reference is evaluated. It should yield either a mutable sequence object (such as a list) or a mapping object (such as a dictionary). Next, the subscript expression is evaluated.
In f
1 Python sees that you are binding some value to a
, sees that a
has not been used in a global a
statement in this scope and prepares a local variable. Then it attempts to evaluate the expression a + 1
, looks up the variable a
and finds an uninitialized local variable. This results in the UnboundLocalError
.
In f
2 Python sees that you are assigning some value to a subscription of the variable a
. It looks up that variable in the local namespace and fails to find it. It then walks up the non-local namespaces (closures) until it reaches the global namespace. Once it fails to find a
in the global namespace it throws a NameError
.
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