这个lambda函数在Python3中是如何计算的?

5tmbdcev  于 2023-05-02  发布在  Python
关注(0)|答案(4)|浏览(207)

抱歉,我是一个学习Python 3编程的新手,我一直被这个问题卡住了。

f = lambda x, y: lambda z: (x)(y)(z)

result = (f)(lambda x: lambda y: x, lambda z: z * 2)(3)(4)

print(result)

结果:8
我试着把它分解:
f(lambda x: lambda y:x, lambda z:z*2)(3)(4)表示x是指(lambda x:lambda y: x),y是指(lambda z:z*2)
从那里,f接受x和y,并返回一个需要1个参数z的lambda函数。
lambda z: (x)(y)(z) (3)(4)
(3)应用于z,返回(x)(y)(3)(4) => (lambda x:lambda y:x)(lambda z: z*2)(3)(4)
因此,(lambda x: lambda y:z)应用于(lambda z:z*2)。这不就是(lambda z:z*2)吗?
为什么不输出(lambda z:z*2)(3)(4)与3应用到z返回6?
相反,输出是8。
我相信我的错误是在(3)应用于z的部分,但我似乎无法逻辑推理出来。
我没有其他人可以问,所以谢谢你的任何帮助。

4uqofj5v

4uqofj5v1#

将每个lambda转换为def

def f(x, y):
    def inner(z):
        return x(y)(z)
    return inner

def g(x):
    def inner(y):
        return x
    return inner

def h(z):
    return z * 2

result = f(g, h)(3)(4)

这至少让你有可能根据表达式的名称来推理表达式的每一个单独的部分:

# f(g, h)(z) -> g(h)(z)
# g(h)(z) -> h

# f(g, h)(z)    -> h
# f(g, h)(3)(4) -> h(4)
# f(g, h)(3)(4) -> 4 * 2 -> 8

print(result)  # 8
k0pti3hp

k0pti3hp2#

因此,(lambda x: lambda y:z)应用于(lambda z:z*2)。这不就是(lambda z:z*2)吗?
不。首先,(lambda x: lambda y:z)应该是(lambda x: lambda y: x),用x代替最后一个z。其次,用参数lambda z: z*2计算得到lambda y: lambda z: z*2,而不是lambda z: z*2。将lambda y: lambda z: z*2与单个参数3一起应用会产生lambda z: z*2,将其与单个参数4一起应用会产生4*2

u2nhd7ah

u2nhd7ah3#

如果你不想中断调试器,你可以用一个装饰器来检测你的函数,它会打印出发生了什么:

from functools import wraps

_level = 0

def wrap_func(f, *, name=None):
    name = name or f.__name__

    @wraps(f)
    def wrapped(*args):
        global _level
        print("  " * _level, f"Calling {name!r} with {args!r}")
        _level += 1
        res = f(*args)
        _level -= 1
        print("  " * _level, f" => returned {res!r}")
        return res

    return wrapped

f = wrap_func(lambda x, y: wrap_func(lambda z: (x)(y)(z), name="xyz"), name="xy")

result = f(
    wrap_func(lambda x: wrap_func(lambda y: x, name="y:x"), name="y:x-wrapper"),
    wrap_func(lambda z: z * 2, name="two-multiplier"),
)(3)(4)

print(result)

这将打印出来(当然,这仍然很神秘)

Calling 'xy' with (<function <lambda> at 0x10d2249a0>, <function <lambda> at 0x111dee660>)
  => returned <function <lambda>.<locals>.<lambda> at 0x11207c400>
 Calling 'xyz' with (3,)
   Calling 'y:x-wrapper' with (<function <lambda> at 0x111dee660>,)
    => returned <function <lambda>.<locals>.<lambda> at 0x11207c540>
   Calling 'y:x' with (3,)
    => returned <function <lambda> at 0x111dee660>
  => returned <function <lambda> at 0x111dee660>
 Calling 'two-multiplier' with (4,)
  => returned 8
8
sycxhyv7

sycxhyv74#

由于代码没有产生任何副作用,您可以使用SICP substitution method简化表达式。我会先远离数字:

f(lambda x: lambda y: x, lambda z: z * 2)
(lambda x, y: lambda z: (x)(y)(z))(lambda x: lambda y: x, lambda z: z * 2)
(lambda z: (lambda x: lambda y: x)(lambda z: z * 2)(z))
(lambda z: (lambda y: lambda z: z * 2)(z))
(lambda y: lambda z: z * 2)

这些都是一样的事实上,我只是通过在每一步都用应用程序进行测试来验证这一点,以防出错。例如(lambda z: (lambda x: lambda y: x)(lambda z: z * 2)(z))(3)(4) # => 8
然后我们可以继续应用程序:

(lambda y: lambda z: z * 2)(3)(4) # y is completely ignored
(lambda z: z * 2)(4)
4 * 2

相关问题