2016-02-10 230 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在現有對象上調用 - 它不關心調用者是全局還是本地。