Can a lambda function call itself recursively in Python?
常规函数可以在其定义中包含对自身的调用,没问题。 我无法弄清楚如何使用lambda函数来做这件事,原因很简单,因为lambda函数没有可以引用的名称。 有办法吗? 怎么样?
我能想到的唯一方法就是为函数命名:
1 | fact = lambda x: 1 if x == 0 else x * fact(x-1) |
或者,对于早期版本的python:
1 | fact = lambda x: x == 0 and 1 or x * fact(x-1) |
更新:使用其他答案中的想法,我能够将阶乘函数楔入一个未命名的lambda:
1 2 | >>> 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内部:
1 | (lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10) |
与某些人说的相反,你可以直接这样做。
1 | (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,它有助于lambda演算中的递归
1 | Y = (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v)))) |
第二部分是递归定义的阶乘函数事实
1 | fact = (lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1))) |
Y应用于事实以形成另一个lambda表达式
1 | F = Y(fact) |
它应用于第三部分n,它被推广到第n个阶乘
1 2 3 | >>> n = 5 >>> F(n) 120 |
或者等价的
1 2 | >>> (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 |
然而,如果你更喜欢纤维,你也可以使用相同的组合器
1 2 | >>> (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 |
你不能直接这样做,因为它没有名字。但是使用像Le-Lein指向的Y-combinator这样的辅助函数,你可以通过将函数作为参数传递给自身来创建递归(听起来很奇怪):
1 2 3 4 5 6 7 8 9 10 | # 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)) |
这将打印前十个Fibonacci数字:
是。我有两种方法可以做到,其中一种已经被覆盖了。这是我的首选方式。
1 2 3 4 | (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,但这可能就是你要找的东西。
这个答案很基本。这比Hugo Walter的回答简单一点:
1 2 3 | >>> (lambda f: f(f))(lambda f, i=0: (i < 10)and f(f, i + 1)or i) 10 >>> |
雨果沃尔特的回答:
1 | (lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10) |
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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)) |
希望它会对某人有所帮助。
Lambda可以轻松替换Python中的递归函数:
例如,这个基本的compound_interest:
1 2 3 4 5 | def interest(amount, rate, period): if period == 0: return amount else: return interest(amount * rate, rate, period - 1) |
可以替换为:
1 | lambda_interest = lambda a,r,p: a if p == 0 else lambda_interest(a * r, r, p - 1) |
或者提高可见度:
1 2 3 | lambda_interest = lambda amount, rate, period: \ amount if period == 0 else \ lambda_interest(amount * rate, rate, period - 1) |
用法:
1 2 | print(interest(10000, 1.1, 3)) print(lambda_interest(10000, 1.1, 3)) |
输出:
1 2 | 13310.0 13310.0 |
为此,我们可以使用定点组合器,特别是
1 | const Z = f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v))) |
定义
1 2 3 | 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)) |
请注意:
fact === Z(_fact)
并使用它:
1 2 3 4 5 6 | 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 |
也可以看看:
JavaScript中的定点组合器:记忆递归函数
好吧,不是完全纯粹的lambda递归,但它适用于只能使用lambdas的地方,例如:减少,映射和列出理解,或其他lambdas。诀窍是从列表理解和Python的名称范围中受益。以下示例按给定的键链遍历字典。
1 2 3 | >>> 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 |
lambda重用其在列表推导表达式(fn)中定义的名称。这个例子相当复杂,但它显示了这个概念。
如果你真的是受虐狂,你或许可以使用C扩展来做,但是为了回应Greg(嗨Greg!),这超出了lambda(未命名,匿名)功能的能力。
不。(大多数值为no)。