0

この関数で何が問題になっていますか?スコープエラーのように思えます(私はそれを直接使用するのではなく、リスト内に各呼び出し可能コードを置くことで修正したと考えましたが)。エラーが到達した最大再帰の深さである(呼び出し時にCOMP(INV、DBL、INC。))...Python関数の構成(最大再帰深度エラー、スコープ?)

注:質問です:なぜそれもないなぜそれが最大の深さに達しています、再帰れる...

def comp(*funcs): 
    if len(funcs) in (0,1): 
     raise ValueError('need at least two functions to compose') 
    # get most inner function 
    composed = [] 
    print("appending func 1") 
    composed.append(funcs[-1]) 
    # pop last and reverse 
    funcs = funcs[:-1][::-1] 
    i = 1 
    for func in funcs: 
     i += 1 
     print("appending func %s" % i) 
     composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs))) 
    return composed[-1] 

def inc(x): 
    print("inc called with %s" % x) 
    return x+1 
def dbl(x): 
    print("dbl called with %s" % x) 
    return x*2 
def inv(x): 
    print("inv called with %s" % x) 
    return x*(-1) 

if __name__ == '__main__': 
    comp(inv,dbl,inc)(2) 

トレースバック(それは場合に役立ちます):

appending func 1 
appending func 2 
appending func 3 
Traceback (most recent call last): 
    File "comp.py", line 31, in <module> 
    comp(inv,dbl,inc)(2) 
    File "comp.py", line 17, in <lambda> 
    composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs))) 
    File "comp.py", line 17, in <lambda> 
    composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs))) 
    File "comp.py", line 17, in <lambda> 
    composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs))) 
    (...) 
    File "comp.py", line 17, in <lambda> 
    composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs))) 
RuntimeError: maximum recursion depth exceeded while calling a Python object 
+0

はhttp://stackoverflow.com/questions/6035848/python-closure-not-working-as-expected/6035865と同様の質問を参照してください –

答えて

5

作成したラムダ関数がcomposed変数の上にクロージャを構築します。

composed.append(lambda *args, **kwargs: func(composed[-1](*args,**kwargs))) 

これは、ラムダ関数を作成するときにcomposed[-1]が評価されないことを意味しますが、を呼び出すと、となります。その効果は、composed[-1]が再帰的に繰り返し呼び出されるということです。

あなたは、ラムダ関数を作成するために、(独自のスコープ付き)ヘルパー関数を使用することによって、この問題を解決することができます。

def comp2(f1, f2): 
    return lambda *args, **kwargs: f1(f2(*args, **kwargs)) 

... 
for func in funcs: 
    composed.append(comp2(func, composed[-1])) 
+1

他の問題があることです'for funcs'ループのために、各ラムダの' func'は同じです。 –

+0

だから私は、明示的にcompos [i]を呼び出すことによってそれをやってみましたが、それでも同じ問題があります。それから、ちょうど合成[10](合成[9](合成[8](...))を呼ぶべきではありませんか?) – o1iver

+0

jochenが言ったことは、実際の問題かもしれないと思っています。 – o1iver

1

あなたが開始するために多くの機能を生成する理由を私は知りません。あなたのコードのシンプルなバージョンがあります:

def compose(*funcs): 
    if len(funcs) in (0,1): 
     raise ValueError('need at least two functions to compose') 

    # accepting *args, **kwargs in a composed function doesn't quite work 
    # because you can only pass them to the first function. 
    def composed(arg): 
     for func in reversed(funcs): 
      arg = func(arg) 
     return arg 

    return composed 

# what's with the lambdas? These are functions already ... 
def inc(x): 
    print("inc called with %s" % x) 
    return x+1 
def dbl(x): 
    print("dbl called with %s" % x) 
    return x*2 
def inv(x): 
    print("inv called with %s" % x) 
    return -x 

if __name__ == '__main__': 
    f = compose(inv,dbl,inc) 
    print f(2) 
    print f(3) 
+0

はい機能が間違っていました...コマンドラインからコピーしました – o1iver

+0

偉大な答えです。私はこのように複雑にしていました... argsについての良い点は、最初の関数のためだけです。ありがとう! – o1iver

+0

私は何か試してみましたが、sthのやり方で* argsと** kwargsを使うことができます。 – o1iver

関連する問題