2012-06-22 43 views
6

我很困惑這個範圍的行爲:奇怪的Python的功能範圍的行爲

class Bar: 
    def __init__(self): 
     for fn in ["open","openW","remove","mkdir","exists","isdir","listdir"]: 
      print "register", fn 
      def func_wrapper(filename): 
       print "called func wrapper", fn, filename 
      setattr(self, fn, func_wrapper) 

bar = Bar() 
bar.open("a") 
bar.remove("b") 
bar.listdir("c") 

這使輸出:

register open 
register openW 
register remove 
register mkdir 
register exists 
register isdir 
register listdir 
called func wrapper listdir a 
called func wrapper listdir b 
called func wrapper listdir c 

但我會預計func_wrapper將永遠是正確的功能。我知道func_wrapper的範圍是整個函數,但我在每次循環迭代中重新定義它,並且最後一個實例被保存在屬性中。我也試着在setattr下面添加func_wrapper = None,但這並沒有幫助(也想知道我......)。

我瞎了嗎?我甚至不知道如何解決這個問題。

+0

@heltonbiker:你能詳細點嗎?我應該如何在這裏使用字典?爲什麼? – Albert

+0

我已經讀得更徹底,並刪除了以前的評論。 – heltonbiker

回答

6

要麼與

class Bar: 
    def __init__(self): 
     for fn in ["open","openW","remove","mkdir","exists","isdir","listdir"]: 
      print "register", fn 
      def func_wrapper(filename, fn=fn): 
       print "called func wrapper", fn, filename 
      setattr(self, fn, func_wrapper) 

,或者更魯棒,與

def mkwrapper(fn): 
    def func_wrapper(filename): 
     print "called func wrapper", fn, filename 
    func_wrapper.__name__ = fn 
    return func_wrapper 

class Bar: 
    def __init__(self): 
     for fn in ["open","openW","remove","mkdir","exists","isdir","listdir"]: 
      print "register", fn 
      func_wrapper = mkwrapper(fn) 
      setattr(self, fn, func_wrapper) 

在原來的實例中,所有生成的函數訪問相同的外部變量fn,這改變了在每一個循環運行。在修正的例子中,這是被阻止的。

+0

啊是的,我認爲......這樣...... :) – Albert

+0

我一直認爲''lambda'有一些關於遲綁定的特殊*,但現在我明白常規函數真的有同樣的問題,它只是它們並不是像lambda函數那樣經常使用。 +1來提問和回答。 –

+0

我真的希望人們不要再推薦這個默認參數了。 –