5

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.

Community
  • 1
  • 1
Fish Monitor
  • 4,155
  • 3
  • 32
  • 53

2 Answers2

7

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 f1 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 f2 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.

Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
-1

Could you try to do something like this :

def f(a):
    a += 1
    print a

def g():
    a = 3
    f(a)

g()
lokoko
  • 5,785
  • 5
  • 35
  • 68