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.

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I think the error has nothing to do with the assignment in g. I have edited the question removing unrelated statements.
@fossilet - apologies that I mistook your question - I've update my answer, let me know if it helps.
-1

Could you try to do something like this :

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

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

g()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.