¿Puede una función lambda llamarse a sí misma de forma recursiva en Python?

Una función normal puede contener una llamada a sí misma en su definición, no hay problema. No puedo averiguar cómo hacerlo con una función lambda, aunque por la sencilla razón de que la función lambda no tiene un nombre al que referirse. ¿Hay una manera de hacerlo? ¿Cómo?

La única forma en que puedo pensar para hacer esto es darle un nombre a la función:

fact = lambda x: 1 if x == 0 else x * fact(x-1) 

o alternativamente, para versiones anteriores de python:

 fact = lambda x: x == 0 and 1 or x * fact(x-1) 

Actualización : utilizando las ideas de las otras respuestas, pude combinar la función factorial en un único lambda sin nombre:

 >>> 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] 

Así que es posible, pero no es realmente recomendable!

sin reducción, mapa, lambdas internas o internas de python:

 (lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10) 

No puedes hacerlo directamente, porque no tiene nombre. Pero con una función auxiliar como el combinador en Y al que Lemmy apuntó, puede crear una recursión al pasar la función como un parámetro a sí mismo (por extraño que parezca):

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

Esto imprime los primeros diez números de Fibonacci: [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] ,

Al contrario de lo que dijo algo, PUEDES hacer esto directamente.

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

La primera parte es el combinador de punto fijo Y que facilita la recursión en el cálculo lambda

 Y = (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v)))) 

La segunda parte es el hecho de la función factorial definida recursivamente.

 fact = (lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1))) 

Y se aplica a los hechos para formar otra expresión lambda

 F = Y(fact) 

que se aplica a la tercera parte, n , que se evalúa al noveno factorial

 >>> n = 5 >>> F(n) 120 

o equivalente

 >>> (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 

Sin embargo, si usted prefiere los datos a los hechos, también puede hacerlo utilizando el mismo combinador.

 >>> (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 

Sí. Tengo dos formas de hacerlo, y una ya estaba cubierta. Esta es mi forma preferida.

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

Nunca he usado Python, pero esto es probablemente lo que estás buscando.

Esta respuesta es bastante básica. Es un poco más simple que la respuesta de Hugo Walter:

 >>> (lambda f: f(f))(lambda f, i=0: (i < 10)and f(f, i + 1)or i) 10 >>> 

La respuesta de Hugo Walter:

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

Espero que sea de ayuda para alguien.

Bueno, no exactamente la recursión lambda pura, pero es aplicable en lugares donde solo se pueden usar lambdas, por ejemplo, reducir, mapear y enumerar las comprensiones, u otras lambdas. El truco es beneficiarse de la comprensión de la lista y el scope del nombre de Python. El siguiente ejemplo atraviesa el diccionario por la cadena de claves dada.

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

La lambda reutiliza su nombre definido en la expresión de comprensión de lista (fn). El ejemplo es bastante complicado, pero muestra el concepto.

Para esto podemos usar combinadores de punto fijo , específicamente el combinador Z , porque funcionará en lenguajes estrictos, también llamados lenguajes ansiosos:

 const Z = f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v))) 

Definir la función de fact y modificarla:

 1. const fact n = n === 0 ? 1 : n * fact(n - 1) 2. const fact = n => n === 0 ? 1 : n * fact(n - 1) 3. const _fact = (fact => n => n === 0 ? 1 : n * fact(n - 1)) 

Darse cuenta de:

hecho === Z (_fact)

Y úsalo:

 const Z = f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v))); const _fact = f => n => n === 0 ? 1 : n * f(n - 1); const fact = Z(_fact); console.log(fact(5)); //120 

Si fuera verdaderamente masoquista, podría hacerlo usando extensiones C, pero para hacerse eco de Greg (¡hola Greg!), Esto excede la capacidad de una función lambda (sin nombre, anónima).

No. (para la mayoría de los valores de no).