2016-02-10 166 views
3

我想更好地理解Python中的范围。我有以下的玩具例子:从Python全局范围解析变量

a = 1 
print "in global: " + str(a) 

def g(): 
    a += 1 
    print "in g(): " + str(a) 


def f(): 
    a += 1 
    print "in f(): " + str(a) 
    g() 

f() 

我预计运行和2然后再2打印出来1然后。但是,相反,我得到的连接错误:

UnboundLocalError: local variable 'a' referenced before assignment 

我还以为这两个g()f()会拉a从全球范围。不正确的?

更新: 谢谢你的答案,但有什么不清楚的是:如果我想刚才读全局变量a并将其分配到一个局部变量,我创造,还被评为a这可能吗?

我这样做的原因是我想弄清楚g()在被调用的时候是否继承了f()的范围,或者它的全局范围在哪里定义?

回答

5

你正试图改变a在功能的外部范围,a不在当前函数的范围,这就是为什么你会得到这样的错误,因为你的函数什么都不知道约a。如果你想从函数内部改变a你需要使用'全球':

a = 1 
print "in global: " + str(a) 

def g(): 
    global a 
    a += 1 
    print "in g(): " + str(a) 


def f(): 
    global a 
    a += 1 
    print "in f(): " + str(a) 
    g() 

打印出全球a使用这种方式:

def f(): 
    print a 
    new_a = a 
    print new_a 

有一个关于globalhere一个很好的例子

而且,如果要使用局部变量a,其值为全球a,请使用globals

def g(): 
    a = globals()['a'] 
    a += 1 
    print "in g(): " + str(a) 
+1

在你的第二段代码中,你不需要'global' – gil

+0

@gill更正,谢谢 – tinySandy

4

您需要使用global关键字。

>>> a = 1   
>>> def g():  
...  global a 
...  a += 1  
...  print a 
...    
>>> g()   
2  
4

你缺少的函数g全局工作和f 这样的:

a = 1 

def g(): 
    global a 
    a += 1 
    print "in g(): " + str(a) 

def f(): 
    global a 
    a += 1 
    print "in f(): " + str(a) 

你可以找到更多关于全局和局部变量在documentation herestack overflow here

1

当您询问变量值时,Python遵循LEGB规则:local,enclosing,global,built-in。

但是当你分配一个变量,它是在局部范围内产生从头(假设变量赋值是内部功能),丢弃任何值之前绑定到它:

a = 5 
def f(x): 
    print a # Prints `5`, because name `a` can be found following LEGB rule in Global scope. 
    print x # Prints whatever value `x` was having, found following LEGB rule in Local scope. 
    x = 123 # Forgets previous value of `x`, re-assign it to `123` in the Local scope. 

你的问题与无约束变量出现在这里:a += 1只是一个语法糖a = a + 1。当你这样做a = a + 1,Python中捕捉任何a是本地的,所以它的字节码产生LOAD_FAST命令:

import dis 
a = 1 
def f(): 
    a += 1 
print dis.dis(f) 

      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 

LOAD_FAST用于局部变量取。但是当您调用LOAD_FAST时,您在本地范围内没有a,因此命令失败。

其实,如果你没有分配到a,但是想从本地范围修改它,你可以通过方法调用来完成。不幸的是,int没有修改的方法,所以我给带班为例:

class Number(object): 
    def __init__(self, x): 
     self.x = x 
    def add_one(self): 
     self.x += 1 

a = Number(1) 
def f(): 
    a.add_one() 
    print a.x 


print a.x 
f() 
print a.x 

1 
2 
2 

在这里,你基本上是做a=a+1,但在更复杂的方式。这是因为对a的调用被解析为全局(并且工作正常),并且您不在f()内执行任何分配。方法add_one在现有对象上调用 - 它不关心调用者是全局还是本地。