2011-07-26 107 views
3
def Test(value): 
    def innerFunc(): 
     print value 
    innerFunc() 

def TestWithAssignment(value): 
    def innerFunc(): 
     print value 
     value = "Changed value" 
    innerFunc() 

Test("Hello 1") 
# Prints "Hello 1" 

TestWithAssignment("Hello 2") 
# Throws UnboundLocalError: local variable 'value' referenced before assignment 
# on the "print value" line 

爲什麼第二個失敗,因爲唯一的區別是之後之後的打印語句?我對此很困惑。混淆範圍的變化 - 發生了什麼?

+0

http://stackoverflow.com/q/855493/287976的可能的複製 – brandizzi

回答

8

的問題是,Python的希望你是明確的,你想成爲隱式的。 Python使用的execution model將綁定名稱綁定到最接近的可用,範圍爲

def Test(value): 
    # Local Scope #1 
    def innerFunc(): 
     # Local Scope #2 
     print value 
     # No immediate local in Local Scope #2 - check up the chain 
     # First find value in outer function scope (Local Scope #1). 
     # Use that. 
    innerFunc() 

def TestWithAssignment(value): 
    # Local Scope #1 
    def innerFunc(): 
     # Local Scope #2 
     print value 
     # Immediate local variable found in Local Scope #2. 
     # No need to check up the chain. 
     # However, no value has been assigned to this variable yet. 
     # Throw an error. 
     value = "Changed value" 
    innerFunc() 

沒有(據我所知)走了在Python 2.x的範圍的方式 - 你必須globals()locals() - 但全球和局部範圍之間的任何範圍無法訪問(如果這不是真的,我會待糾正)。

但是,您可以通過局部變量value到你內心的局部範圍:

def TestWithAssignment(value): 
    def innerFunc(value): 
     print value 
     # Immediate local **and assigned now**. 
     value = "Changed value" 
     # If you need to keep the changed value 
     # return value 
    innerFunc(value) 
    # If you need to keep the changed value use: 
    # value = innerFunc(value) 

在Python 3中,你可以用來指包含範圍內(感謝@Thomas k上的新nonlocal聲明)。

def TestWithAssignment(value): 
    def innerFunc(): 
     nonlocal value 
     print value 
     value = "Changed value" 
    innerFunc() 
+0

爲什麼/如何知道即時本地的python,即使它稍後分配在函數中?這對我來說看起來很奇怪 - 如果「價值」在第一個函數的範圍內,我希望它在第二個函數的範圍內。 – combatdave

+1

@Sean:從Python 3開始,您可以使用'nonlocal value'綁定到外部作用域中的名稱。但我不知道有什麼方法可以訪問像globals()和locals()這樣的外部作用域。 –

+0

@combatdave - 它在兩個範圍內 - 首先完成範圍界定。關鍵在於我提供的鏈接「A * block *」是一個作爲一個單元執行的Python程序文本塊,下面是塊:一個模塊,一個**函數體**和一個類定義...如果在一個塊中定義了一個局部變量,那麼它的範圍就包含該塊,如果定義發生在一個功能塊中,則該範圍擴展到包含在定義塊中的任何塊,除非包含的塊爲該名稱引入了不同的綁定**「。 –

0

這應該修復它:

def Test(value): 
    def innerFunc(value): 
     print value 
    innerFunc(value) 
+3

我不認爲他在問如何解決它,而是它爲什麼壞了。另外,你必須更新'innerFunc'才能將值作爲參數來工作。 – thegrinner

+0

是的,有幾種方法可以解決這個問題,但我想知道第一個工作正常的原因和第二個失敗的原因。 – combatdave