6

Given the following code:

a = 0
def foo():
  # global a
  a += 1
foo()

When run, Python complains: UnboundLocalError: local variable 'a' referenced before assignment

However, when it's a dictionary...

a = {}
def foo():
  a['bar'] = 0
foo()

The thing runs just fine...

Anyone know why we can reference a in the 2nd chunk of code, but not the 1st?

4 Answers 4

2

The difference is that in the first example you are assigning to a which creates a new local name a that hides the global a.

In the second example you are not making an assignment to a so the global a is used.

This is covered in the documentation.

A special quirk of Python is that – if no global statement is in effect – assignments to names always go into the innermost scope.

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

1 Comment

I wonder why they decided to describe it as a 'special quirk'? Contrast with javascript where a = 1 automatically assigns to global scope! The only good thing about that is that you can quickly recognize garbage code by the absences of var a = 1
1

The question is one of update.

You cannot update a because it is not a variable in your function's local namespace. The update-in-place assignment operation fails to update a in place.

Interestingly, a = a + 1 also fails.

Python generates slightly optimized code for these kind of statements. It uses a "LOAD_FAST" instruction.

  2           0 LOAD_FAST                0 (a)
              3 LOAD_CONST               1 (1)
              6 INPLACE_ADD         
              7 STORE_FAST               0 (a)
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE        

Note that the use of a on left and right side of the equal sign leads to this optimization.

You can, however, access a because Python will search local and global namespaces for you.

Since a does not appear on the left side of an assignment statement, a different kind of access is used, "LOAD_GLOBAL".

  2           0 LOAD_CONST               1 (0)
              3 LOAD_GLOBAL              0 (a)
              6 LOAD_CONST               2 ('bar')
              9 STORE_SUBSCR        
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE        

Comments

0

a += 1 is equivalent to a = a + 1. By assigning to variable a, it is made local. The value you attempt to assign a + 1 fails because a hasn't been bound yet.

Comments

0

That's a very common Python gotcha: if you assign to a variable inside a function (as you do, with +=), anywhere at all (not necessarily before you use it some other way), it doesn't use the global one. However, since what you're doing is effectively "a = a + 1", you're trying to access a (on the right-hand side of the expression) before assigning to it.

Try using global a at the beginning of your function (but beware that you'll overwrite the global a value).

On your second example, you're not assigning the the variable a, but only to one of its items. So the global dict a is used.

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.