Состав функции Python (ошибка максимальной глубины рекурсии, область действия?) - PullRequest
0 голосов
/ 01 августа 2011

Что не так с этой функцией?Это похоже на ошибку области видимости (хотя я думал, что исправил это, поместив каждый вызываемый объект в список вместо непосредственного использования).Ошибка: достигнута максимальная глубина рекурсии (при вызове comp (inv, dbl, inc)) ...

Примечание: вопрос в том, почему он повторяется, а не достигает максимальной глубины ...

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)

Traceback (если это поможет):

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

Ответы [ 2 ]

5 голосов
/ 01 августа 2011

Лямбда-функция, которую вы создаете, строит замыкание по переменной 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 голос
/ 01 августа 2011

Я не знаю, почему вы генерируете много функций для начала.Есть простая версия вашего кода:

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)
...