2012-06-22 5 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の範囲が関数全体にあることを知っていますが、私はすべてのループの繰り返しでそれを再定義し、最後のインスタンスはattribに保存されました。私もsetattrの下にfunc_wrapper = Noneを追加しようとしましたが、それは助けになりません(私も疑問に思っていました...)。

私は盲目ですか?私は実際にどのように回避/修正するのか見ていない。あなたの元の例で

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) 

でより堅牢

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) 

か、と

+0

@heltonbiker:詳しいことはできますか?ここでは代わりに辞書を使うべきですか?なぜ? – Albert

+0

私はより完全に読んだことがあり、前のコメントを削除しました。 – heltonbiker

答えて

6

のいずれかが、生成されたすべての機能は、すべてのループの実行中に変更する同一の外の変数fnに、アクセスします。訂正された例では、これは防止される。

+0

ああ、私はこのようなsthだと思った... :) – Albert

+0

私はいつも、lateバインディングに関して「ラムダ」について何か特別なものがあると思っていたが、今は普通の機能に本当に同じ問題があることを理解している。ラムダ関数がそうであるのと同じように頻繁に使用されることはありません。質問と回答に+1してください。 –

+0

私は本当に人々がそのデフォルトパラメータのハックを推奨しなくてもいいと思っています。 –