看一看這段代碼:Python和關閉變量
def closure():
value = False
def method_1():
value = True
def method_2():
print 'value is:', value
method_1()
method_2()
closure()
我希望它來打印「值:真」,但事實並非如此。這是爲什麼?解決方案是什麼?
看一看這段代碼:Python和關閉變量
def closure():
value = False
def method_1():
value = True
def method_2():
print 'value is:', value
method_1()
method_2()
closure()
我希望它來打印「值:真」,但事實並非如此。這是爲什麼?解決方案是什麼?
發生這種情況是因爲method_1
在聲明變量的地方有自己的本地作用域。 Python看到value = True
,並認爲你正在創建一個名爲value
的新變量,本地地址爲method_1
。
Python這樣做的原因是爲了避免使用內部函數中的變量來污染外部作用域的本地。 (您不希望在常規的模塊級函數中進行賦值,導致創建全局變量!)
如果您沒有分配給value
,那麼Python將搜索外部範圍尋找變量(因此讀取該變量按預期工作,如method_2
所示)。要解決這個問題
一種方式是通過使用可變對象,而不是分配新建分配FY的:
result = { 'value': False }
def method_1():
result['value'] = True
在Python 3,nonlocal
statement(見docs)加入正是這種情況:
def method_1():
nonlocal value
value = True # Works as expected -- assigns to `value` from outer scope
在method_1
中,Python假設(相當明智!)value
是一個局部變量。每當你在一個函數內賦值給一個變量名時,假定該變量名是一個新的局部變量。如果你希望它是全局的,那麼你必須聲明它爲global
,如果你希望它是「非本地的」,在Python 3中,你可以聲明它爲nonlocal
,但在Python 2中,你必須做一些事情:將值存儲在容器中。這避免了必須重新分配變量名稱,從而避免了範圍模糊。
def method_1_global():
global value
value = True
def method_1_nonlocal_P3():
nonlocal value
value = True
value = [False]
def method_1_nonlocal_P2():
value[0] = True
當您分配給變量時,它假定該變量屬於本地範圍。所以value
在method_1
不是value
在closure
。
如果你想讓它在Python 3上工作,請在method_1
上添加一行:nonlocal value
。
在Python 2中,
def closure():
value = [False]
def method_1():
value[0] = True
def method_2():
print 'value is:', value
method_1()
method_2()
closure()
是一個可能的方法。
這是因爲你實際上沒有修改閉合變量 - 你用一個具有相同名稱的新變量掩蓋它。在Python 2.x中沒有簡單的解決方法,這就是爲什麼nonlocal
關鍵字被添加到python 3.
但是,這可以解決使用像列表和字典這樣的可變類型。有一個good example in this answer。
爲了避免這種情況,您可以使用列表。
value = [False]
def method_1():
value[0] = True
什麼Python不現在在更高水平範圍的搜索爲值是不是在局部變量可用。由於值是一個列表,Python將其引用爲相對於* method_1 *的全局變量,因此您可以將的值視爲,它是一個列表。
此主題是爲什麼五分鐘免費編輯有時很糟糕的完美例子。 – agf
@agf:爲什麼它不好? – Cameron