看板 Python 關於我們 聯絡資訊
※ 引述《gardenest (股海尋燈)》之銘言: : 因為一樣是變數的問題,所以我直接回這個標題。 : 1、 : a = 1 : class testing: : def test(self): : a = 0 : print a : def test2(self): : print a : obj = testing() : obj.test() : obj.test2() : print a : ----------output : 0 : 1 : 1 : ----------- : 看起來像是最上面第一行a的值並沒有被test()改成0,所以後面印出來的還是1。 : 2、 : 但是當我將a改成list的型態時,它似乎會被改變了。 : a = [1] : class testing: : def test(self): : a.append(2) : print a : def test2(self): : print a : obj = testing() : obj.test() : obj.test2() : print a : ---------output : [1,2] : [1,2] : [1,2] : --------- : 看起來a在test()裡被改變了。 : 以上這2個例子讓我感到很困惑,一個會被改,一個不會被改, : 想請問為什麼會有這樣子的差異呢? 以下是我目前的理解,如果有什麼錯的地方還請各位指正^^ 先簡化一下問題 def function1(): a=1 print a return def function2(): print a return a=0 function1() function2() print a 結果是 1 0 0 因為python沒有變數宣告 所以當你在函式內assign一個值給某個變數時 它就當作在這個函式內產生一個區域變數 所以function1的a就被當成是區域變數,後面的print就是print區域變數的值 而function2內沒有名為a的區域變數,所以它就會去外面找最近的a來print 同樣的 def function1(): a=[1] print a return def function2(): print a return a=[0] function1() function2() print a 這樣會得到 [1] [0] [0] 還有一個有趣的行為是 def function1(): print a a=1 print a return a=0 function1() 它會回應: UnboundLocalError: local variable 'a' referenced before assignment 即是說,只要函式中任何一個位置assign了a的值,a就會在整個函式中被當成 區域變數(不管是assign前還是assign後),所以你就不能在assign之前對a取值 但是如果妳在函數中調用變數的method的話,因為函式中沒有同名的區域變數 所以它就會去外面找最近的同名變數 比如說 def function1(): a[0]=1 print a return a=[0] function1() print a 就會得到 [1] [1] 因為在function1中 讀到a[0]=1這一行時,它會去找function1中有沒有指定'a'為區域 變數,沒有的話就會去外面找最近的a來用囉 這個特性有時可以玩一些tricks 例如: counter=0 def function(): counter=counter+1 return counter function() 它會說 UnboundLocalError: local variable 'counter' referenced before assignment 因為沒有變數宣告的機制,所以它把counter當作是區域變數了 一個變通的方法就是使用global statement counter=0 def function(): global counter counter=counter+1 return counter function() function() function() 就會得到 1 2 3 ... 在這邊global counter這一行的意思就是告訴interpreter說在這邊的'counter' 要用的是"最外面"的counter 然而你也可以用前面所說的特性來達到同樣的效果,例如: counter=[0] def function(): counter[0]=counter[0]+1 return counter[0] function() function() function() 此外,global的使用還是有一些限制 例如: def geniter(): c=0 def iter(): global c c=c+1 return c return iter iter=geniter() iter() 它又會跟你說: NameError: global name 'c' is not defined 因為你使用global statement的時候 它會去「最外層」找全域變數來用 所以又會跟你說找不到… 但是使用前面的技巧,就還是可以達成目的: def geniter(): c=[0] def iter(): c[0]=c[0]+1 return c[0] return iter iter1=geniter() iter2=geniter() iter1() iter1() iter1() iter2() iter2() iter2() 就會得到 1 2 3 1 2 3 一個新聞是在python 3.0中多了 nonlocal statement可以用來表示 我要使用「上一層」的變數 所以應該就可以寫成 def generator(): c=0 def f(): nonlocal c c=c+1 return c return f 感覺上會變得比較直覺(沒有裝3.0所以沒試過) 總之沒有宣告變數的機制其實還是有一些不方便的地方啦 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.213.158 ※ 編輯: mantour 來自: 140.112.213.158 (01/22 13:31) ※ 編輯: mantour 來自: 140.112.213.158 (01/22 13:33)
aquarianboy:補充一下,第一個範例的結果應該是1 0 0 印了三次 :) 01/22 13:59
謝謝 已改^^ ※ 編輯: mantour 來自: 140.112.213.158 (01/22 14:01)
gardenest:感謝man大的解答,非常詳細,這個問題困惑我好久,終於 01/22 15:38
gardenest:決了^__^ 01/22 15:38
gardenest:解決了^__^ 01/22 15:39