Python 中的 lambda 函数可以递归调用自身吗?

发布于 2024-07-12 22:46:53 字数 98 浏览 8 评论 0原文

常规函数可以在其定义中包含对自身的调用,没有问题。 我不知道如何使用 lambda 函数来做到这一点,但原因很简单,lambda 函数没有可引用的名称。 有办法做到吗? 如何?

A regular function can contain a call to itself in its definition, no problem. I can't figure out how to do it with a lambda function though for the simple reason that the lambda function has no name to refer back to. Is there a way to do it? How?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

镜花水月 2024-07-19 22:46:53

我能想到的唯一方法就是给函数命名:

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]

所以这是可能的,但并不真正推荐!

The only way I can think of to do this amounts to giving the function a name:

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

or alternately, for earlier versions of python:

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

Update: using the ideas from the other answers, I was able to wedge the factorial function into a single unnamed 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]

So it's possible, but not really recommended!

旧瑾黎汐 2024-07-19 22:46:53

没有reduce、map、命名lambdas或python内部:

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

without reduce, map, named lambdas or python internals:

(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)
累赘 2024-07-19 22:46:53

与所说相反,你可以直接这样做。

(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应用于fact以形成另一个

F = Y(fact)

应用于第三部分的lambda表达式, 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

但是,如果您更喜欢 fibs 而不是 facts,您也可以使用相同的组合器来做到这一点

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

Contrary to what sth said, you CAN directly do this.

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

The first part is the fixed-point combinator Y that facilitates recursion in lambda calculus

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

the second part is the factorial function fact defined recursively

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

Y is applied to fact to form another lambda expression

F = Y(fact)

which is applied to the third part, n, which evaulates to the nth factorial

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

or equivalently

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

If however you prefer fibs to facts you can do that too using the same combinator

>>> (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
述情 2024-07-19 22:46:53

你不能直接这样做,因为它没有名字。 但是,使用像 Y 组合器 Lemmy 指出的辅助函数,您可以通过将该函数作为参数传递给自身来创建递归(听起来很奇怪):

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

You can't directly do it, because it has no name. But with a helper function like the Y-combinator Lemmy pointed to, you can create recursion by passing the function as a parameter to itself (as strange as that sounds):

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

This prints the first ten Fibonacci numbers: [1, 1, 2, 3, 5, 8, 13, 21, 34, 55],

苏佲洛 2024-07-19 22:46:53

是的。 我有两种方法可以做到这一点,其中一种已经被涵盖了。 这是我的首选方式。

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

Yes. I have two ways to do it, and one was already covered. This is my preferred way.

(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)
淡笑忘祈一世凡恋 2024-07-19 22:46:53

这个答案非常基本。 它比雨果·沃尔特的回答简单一点:

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

This answer is pretty basic. It is a little simpler than Hugo Walter's answer:

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

Hugo Walter's answer:

(lambda a:lambda v:a(a,v))(lambda s,x:1 if x==0 else x*s(s,x-1))(10)
硪扪都還晓 2024-07-19 22:46:53
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))

希望这对某人有帮助。

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

Hope it would be helpful to someone.

耀眼的星火 2024-07-19 22:46:53

现在,我们可以使用新的 Python 语法来使其更短、更易于阅读:

Fibonacci:

>>> (f:=lambda x: 1 if x <= 1 else f(x - 1) + f(x - 2))(5)
8

Factorial:

>>> (f:=lambda x: 1 if x == 0 else x*f(x - 1))(5)
120

We use := 来命名 lambda:直接在 lambda 本身中使用名称并立即调用它作为匿名函数。

(参见https://www.python.org/dev/peps/pep-0572< /a>)

We can now use new python syntax to make it way shorter and easier to read:

Fibonacci:

>>> (f:=lambda x: 1 if x <= 1 else f(x - 1) + f(x - 2))(5)
8

Factorial:

>>> (f:=lambda x: 1 if x == 0 else x*f(x - 1))(5)
120

We use := to name the lambda: use the name directly in the lambda itself and call it right away as an anonymous function.

(see https://www.python.org/dev/peps/pep-0572)

油饼 2024-07-19 22:46:53

顺便说一句,我建议不要缓慢计算斐波那契:

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)

By the way, instead of slow calculation of Fibonacci:

f = lambda x: 1 if x in (1,2) else f(x-1)+f(x-2)

I suggest fast calculation of Fibonacci:

fib = lambda n, pp=1, pn=1, c=1: pp if c > n else fib(n, pn, pn+pp, c+1)

It works really fast.

Also here is factorial calculation:

fact = lambda n, p=1, c=1: p if c > n else fact(n, p*c, c+1)
剑心龙吟 2024-07-19 22:46:53

我喜欢莫托库尔的回答,因为它很简洁。 以下是我关于寻找解决方案的想法:

对于递归,我们需要调用相同的方法,但由于它是 lambda,我们无法获得对它的引用。 我们引用名称的一种方法是通过方法参数。 因此,我们要调用的方法应该作为参数传递。 (另一种方法是通过检查调用堆栈来获取当前方法的引用,如 habnabit 的答案)

接下来的事情是能够将不同的值传递给每个递归调用。 所以我们引入另一个参数来保存该值。

计算 6 的阶乘的示例:

(lambda f : f(f,6) )( lambda f, x : 1 if x <= 1 else x * f(f, x-1) )

或者

从一开始就定义参数而不是对其进行硬编码:

(lambda f,x : f(f,x) )( (lambda f, x : 1 if x <= 1 else x * f(f, x-1)), 6)

I liked motokur's answer as its succint. Here's my thinking about finding the solution :

For recursion, we need to call the same method but since its a lambda, we can't get a ref to it. One way we can reference a name is via method parameters. So, the method we want to call should be passed as a parameter. ( Another way is to get a ref to the current method by inspecting the call stack as in habnabit's answer)

The next thing is to be able to pass different values to each recursive call. So we introduce another parameter to hold the value.

A example calculating the factorial of 6 :

(lambda f : f(f,6) )( lambda f, x : 1 if x <= 1 else x * f(f, x-1) )

OR

Defining the param from the start instead of hard-coding it :

(lambda f,x : f(f,x) )( (lambda f, x : 1 if x <= 1 else x * f(f, x-1)), 6)
温柔一刀 2024-07-19 22:46:53

嗯,不完全是纯粹的 lambda 递归,但它适用于只能使用 lambda 的地方,例如,reduce、映射和列表推导式或其他 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) 中定义的名称。 这个例子相当复杂,但它展示了这个概念。

Well, not exactly pure lambda recursion, but it's applicable in places, where you can only use lambdas, e.g. reduce, map and list comprehensions, or other lambdas. The trick is to benefit from list comprehension and Python's name scope. The following example traverses the dictionary by the given chain of keys.

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

The lambda reuses its name defined in the list comprehension expression (fn). The example is rather complicated, but it shows the concept.

分分钟 2024-07-19 22:46:53

我知道这是一个旧线程,但它在一些谷歌搜索结果中排名很高:)。 随着 python 3.8 的到来,您可以使用海象运算符以更少的语法实现 Y 组合器!

fib = (lambda f: (rec := lambda args: f(rec, args)))\
      (lambda f, n: n if n <= 1 else f(n-2) + f(n-1))

I know this is an old thread, but it ranks high on some google search results :). With the arrival of python 3.8 you can use the walrus operator to implement a Y-combinator with less syntax!

fib = (lambda f: (rec := lambda args: f(rec, args)))\
      (lambda f, n: n if n <= 1 else f(n-2) + f(n-1))
梦里梦着梦中梦 2024-07-19 22:46:53

简短回答

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

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

print(fact(5))

编辑:04/24/2022

解释

为此,我们可以使用定点组合器,特别是 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

也可以看看:
定点JavaScript 中的组合器:记忆递归函数

Short answer

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

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

print(fact(5))

Edited: 04/24/2022

Explanation

For this we can use Fixed-point combinators, specifically Z combinator, because it will work in strict languages, also called eager languages:

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

Define fact function and modify it:

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

Notice that:

fact === Z(_fact)

And use it:

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

See also:
Fixed-point combinators in JavaScript: Memoizing recursive functions

树深时见影 2024-07-19 22:46:53

我做了一些关于它的作业并弄清楚了一些事情,这是带有递归调用的 lambda 函数的示例:

sucesor = lambda n,f,x: (f)(x) if n == 0 else sucesor(n-1,f,(f)(x)) 

I got some homework about it and figured out something, heres an example of a lambda function with recursive calls:

sucesor = lambda n,f,x: (f)(x) if n == 0 else sucesor(n-1,f,(f)(x)) 
遗弃M 2024-07-19 22:46:53

很简单:

fac = lambda n: 1 if n <= 1 else n*fac(n-1)

As simple as:

fac = lambda n: 1 if n <= 1 else n*fac(n-1)
忘羡 2024-07-19 22:46:53

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

Lambda can easily replace recursive functions in Python:

For example, this basic compound_interest:

def interest(amount, rate, period):
    if period == 0: 
        return amount
    else:
        return interest(amount * rate, rate, period - 1)

can be replaced by:

lambda_interest = lambda a,r,p: a if p == 0 else lambda_interest(a * r, r, p - 1)

or for more visibility :

lambda_interest = lambda amount, rate, period: \
amount if period == 0 else \
lambda_interest(amount * rate, rate, period - 1)

USAGE:

print(interest(10000, 1.1, 3))
print(lambda_interest(10000, 1.1, 3))

Output:

13310.0
13310.0
空城之時有危險 2024-07-19 22:46:53

如果你真的是受虐狂,你也许可以使用 C 扩展来做到这一点,但这超出了 lambda(未命名、匿名)函数的能力。

否。(对于大多数否值)。

If you were truly masochistic, you might be able to do it using C extensions, but this exceeds the capability of a lambda (unnamed, anonymous) functon.

No. (for most values of no).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文