Может ли лямбда-функция рекурсивно вызывать себя в Python?
регулярная функция может содержать вызов себе в своем определении, без проблем. Я не могу понять, как это сделать с лямбда-функцией, хотя по той простой причине, что лямбда-функция не имеет имени, на которое можно ссылаться. Есть ли способ сделать это? Как?
11 ответов:
единственный способ, который я могу придумать, чтобы сделать это, сводится к тому, чтобы дать функции имя:
fact = lambda x: 1 if x == 0 else x * fact(x-1)
или поочередно, для более ранних версий Python:
fact = lambda x: x == 0 and 1 or x * fact(x-1)
обновление: используя идеи из других ответов, я смог вклинить факториальную функцию в одну неназванную лямбду:
>>> map(lambda n: (lambda f, *a: f(f, *a))(lambda rec, n: 1 if n == 0 else n*rec(rec, n-1), n), range(10)) [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
Так что это возможно, но не очень рекомендуется!
без reduce, map, с именем lambdas или Python internals:
(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)
вы не можете сделать это напрямую, потому что у него нет имени. Но с помощью вспомогательной функции, такой как Y-комбинатор, на который указал Лемми, вы можете создать рекурсию, передав функцию в качестве параметра себе (как ни странно это звучит):
# helper function def recursive(f, *p, **kw): return f(f, *p, **kw) def fib(n): # The rec parameter will be the lambda function itself return recursive((lambda rec, n: rec(rec, n-1) + rec(rec, n-2) if n>1 else 1), n) # using map since we already started to do black functional programming magic print map(fib, range(10))
это печатает первые десять чисел Фибоначчи:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
,
вопреки тому, что сказал sth, вы можете напрямую сделать это.
(lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))(lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1)))(n)
первая часть комбинатор с фиксированной точкойY что облегчает рекурсию в лямбда-исчислении
Y = (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))
вторая часть-это факторная функция факт определена рекурсивно
fact = (lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1)))
Y применяется факт сформировать другое лямбда-выражение
F = Y(fact)
который наносится третья часть, n, который evaulates к N-му факториалу
>>> n = 5 >>> F(n) 120
или
>>> (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))(lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1)))(5) 120
если вы предпочитаете fibs до факты вы можете сделать это тоже с помощью того же комбинатора
>>> (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))(lambda f: (lambda i: f(i - 1) + f(i - 2) if i > 1 else 1))(5) 8
да. У меня есть два способа сделать это, и один уже был покрыт. Это мой предпочтительный способ.
(lambda v: (lambda n: n * __import__('types').FunctionType( __import__('inspect').stack()[0][0].f_code, dict(__import__=__import__, dict=dict) )(n - 1) if n > 1 else 1)(v))(5)
Я никогда не использовал Python, но этой - Это, наверное, то, что вы ищете.
этот ответ довольно простой. Это немного проще, чем ответ Хьюго Уолтера:
>>> (lambda f: f(f))(lambda f, i=0: (i < 10)and f(f, i + 1)or i) 10 >>>
ответ Хьюго Уолтера:
(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)
def recursive(def_fun): def wrapper(*p, **kw): fi = lambda *p, **kw: def_fun(fi, *p, **kw) return def_fun(fi, *p, **kw) return wrapper factorial = recursive(lambda f, n: 1 if n < 2 else n * f(n - 1)) print(factorial(10)) fibonaci = recursive(lambda f, n: f(n - 1) + f(n - 2) if n > 1 else 1) print(fibonaci(10))
надеюсь, что это будет полезно для кого-то.
Ну, не совсем чистая лямбда-рекурсия, но она применима в местах, где вы можете использовать только лямбды, например, сокращение, понимание карт и списков или другие лямбды. Хитрость заключается в том, чтобы извлечь выгоду из понимания списка и области имен Python. В следующем примере словарь проходит по заданной цепочке ключей.
>>> data = {'John': {'age': 33}, 'Kate': {'age': 32}} >>> [fn(data, ['John', 'age']) for fn in [lambda d, keys: None if d is None or type(d) is not dict or len(keys) < 1 or keys[0] not in d else (d[keys[0]] if len(keys) == 1 else fn(d[keys[0]], keys[1:]))]][0] 33
лямбда повторно использует свое имя, определенное в выражении понимания списка (fn). Пример довольно сложный, но он показывает концепцию.
для этого мы можем использовать комбинаторы с фиксированной точкой, в частности
Z
комбинатор, потому что он будет работать на строгих языках, также называемых нетерпеливыми языками:const Z = f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v)))
определение