开发者

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

An开发者_StackOverflow中文版yone know why we can reference a in the 2nd chunk of code, but not the 1st?


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.


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        


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜