Ish
Ish

Reputation: 145

Python variable resolving

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?

Upvotes: 6

Views: 136

Answers (4)

Mark Byers
Mark Byers

Reputation: 838416

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.

Upvotes: 2

S.Lott
S.Lott

Reputation: 391872

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        

Upvotes: 1

rbp
rbp

Reputation: 45020

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.

Upvotes: 0

Jeff Mercado
Jeff Mercado

Reputation: 134901

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.

Upvotes: 0

Related Questions