常规函数可以在其定义中包含对自身的调用,这没问题。我不知道如何使用 lambda 函数来做这件事,但原因很简单,lambda 函数没有名称可以引用。有没有办法做到这一点?如何?
15 回答
我能想到的唯一方法就是给函数命名:
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)
更新:使用其他答案的想法,我能够将阶乘函数楔入一个未命名的 lambda:
>>> 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、命名 lambda 或 python 内部:
(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)
与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,它有助于 lambda 演算中的递归
Y = (lambda f: (lambda x: f(lambda v: x(x)(v)))(lambda x: f(lambda v: x(x)(v))))
第二部分是递归定义的阶乘函数fact
fact = (lambda f: (lambda i: 1 if (i == 0) else i * f(i - 1)))
Y应用于事实以形成另一个 lambda 表达式
F = Y(fact)
它应用于第三部分n,它评估到第 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
但是,如果您更喜欢事实而不是事实,您也可以使用相同的组合器来做到这一点
>>> (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
你不能直接做,因为它没有名字。但是使用像 Lemmy 指出的 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]
:
是的。我有两种方法可以做到这一点,其中一种已经涵盖了。这是我的首选方式。
(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)
这个答案很基本。它比 Hugo Walter 的回答简单一点:
>>> (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))
希望对某人有所帮助。
顺便说一句,斐波那契的计算不是很慢:
f = lambda x: 1 if x in (1,2) else f(x-1)+f(x-2)
我建议快速计算斐波那契:
fib = lambda n, pp=1, pn=1, c=1: pp if c > n else fib(n, pn, pn+pp, c+1)
它的工作速度非常快。
这里还有阶乘计算:
fact = lambda n, p=1, c=1: p if c > n else fact(n, p*c, c+1)
好吧,不完全是纯粹的 lambda 递归,但它适用于只能使用 lambda 的地方,例如 reduce、map 和列表推导或其他 lambda。诀窍是从列表理解和 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
lambda 重用其在列表理解表达式 (fn) 中定义的名称。这个例子相当复杂,但它显示了这个概念。
为此,我们可以使用定点组合器,特别是Z
组合器,因为它可以在严格的语言中工作,也称为渴望语言:
const Z = f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v)))
定义fact
函数并修改它:
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))
请注意:
事实 === Z(_fact)
并使用它:
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
我们现在可以使用新的 python 语法来使它更短更容易阅读:
斐波那契:
>>> (f:=lambda x: 1 if x <= 1 else f(x - 1) + f(x - 2))(5)
8
阶乘:
>>> (f:=lambda x: 1 if x == 0 else x*f(x - 1))(5)
120
我们:=
用来命名 lambda:直接在 lambda 本身中使用名称,并立即将其作为匿名函数调用。
我知道这是一个旧线程,但它在一些谷歌搜索结果中排名很高:)。随着 python 3.8 的到来,您可以使用 walrus 运算符来实现语法更少的 Y 组合器!
fib = (lambda f: (rec := lambda args: f(rec, args)))\
(lambda f, n: n if n <= 1 else f(n-2) + f(n-1))
很简单:
fac = lambda n: 1 if n <= 1 else n*fac(n-1)
Lambda 可以轻松替换 Python 中的递归函数:
例如,这个基本的 Compound_interest:
def interest(amount, rate, period):
if period == 0:
return amount
else:
return interest(amount * rate, rate, period - 1)
可以替换为:
lambda_interest = lambda a,r,p: a if p == 0 else lambda_interest(a * r, r, p - 1)
或更多可见性:
lambda_interest = lambda amount, rate, period: \
amount if period == 0 else \
lambda_interest(amount * rate, rate, period - 1)
用法:
print(interest(10000, 1.1, 3))
print(lambda_interest(10000, 1.1, 3))
输出:
13310.0
13310.0
如果您是真正的自虐狂,您也许可以使用 C 扩展来做到这一点,但这超出了 lambda(未命名、匿名)函数的能力。
No.(对于大多数 no 值)。