2017-02-23 8 views
1

以下のコードで数値オブジェクトをエミュレートするメソッドを動的に設定しようとしています。しかし、代わりに、すべてのメソッドがループの最後のメソッドに設定されます。なぜこれが起こり、どうすればPythonをDWIMに納得させることができますか?数値オブジェクトをエミュレートするためにループ内でメソッドを動的に定義しますが、すべてのメソッドは最後の反復の値を受け取ります。なぜですか?

#!/usr/bin/env python3.5 
class Foo(float): 
    pass 

for tp in ("add", "sub", "mul", "truediv", "floordiv", "mod", "divmod", "pow"): 
    methname = "__{:s}__".format(tp) 
    print("defining", methname) 
    def func(self, other): 
     x = getattr(super(Foo, self), methname)(other) 
     print("I calculated x={:.3f}!".format(x)) 
     return x 
    func.__name__ = methname 
    setattr(Foo, methname, func) 

if __name__ == "__main__": # test 
    print("Addition", Foo(3) + Foo(3)) 
    print("Multiplication", Foo(3) * Foo(3)) 

$ ./dyn.py 
defining __add__ 
defining __sub__ 
defining __mul__ 
defining __truediv__ 
defining __floordiv__ 
defining __mod__ 
defining __divmod__ 
defining __pow__ 
I calculated x=27.000! 
Addition 27.0 
I calculated x=27.000! 
Multiplication 27.0 

答えて

1

結果27.0は3 ** 3で計算され、最後のループで変更されたmethnameを呼び出すときに実際に格納されている関数を呼び出しています。

funcで使用される変数は、グローバル変数を参照します。 funcを別のメソッドに入れ、ループ変数をパラメータとして渡すと、funcを含む関数のローカル変数は定数となり、ループによって変更されません。

#create function with the given name 
# \return the function 
def makeFunc(tp): 
    methname = "__{:s}__".format(tp) 
    print("defining", methname) 
    def func(self, other): 
     x = getattr(super(Foo, self), methname)(other) 
     print("I calculated x={:.3f}!".format(x)) 
     return x 
    func.__name__ = methname 
    return func 


for tp in ("add", "sub", "mul", "truediv", "floordiv", "mod", "divmod", "pow"): 
    func=makeFunc(tp) 
    setattr(Foo, func.__name__, func) 
+0

確か。私はリンクされた答えでそれを理解しました、たとえ私が関数を入れ子にしていないとしても。 'func'の署名に' methname = methname'を加えることは、そのトリックを行いました。 – gerrit

関連する問題