函数参数何时求值?

ash*_*shu 2 python lambda function higher-order-functions

在此代码片段中

def D(m, x):                                                                                                                                                                                                                                                                                                                                                                               
    print(m)                                                                                                                                                                                                                                                                                                                                                                               
    return x                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                                           
print((lambda x: D(1, D(2, D(4, x))))(5))                                                                                                                                                                                                                                                                                                                                                  
print("\n\n\n")                                                                                                                                                                                                                                                                                                                                                                            
print(D(1, lambda x: D(2, D(4, x)))(5))   
Run Code Online (Sandbox Code Playgroud)

我们看到以下输出

4
2
1
5




1
4
2
5
Run Code Online (Sandbox Code Playgroud)

为什么输出顺序不同?看起来当 D 的参数是 lambda 时,它会在稍后计算,而如果它是一个函数,它会先计算?我怎么理解这一点?

che*_*ner 5

所有参数均在函数实际调用时计算。

\n

在第一个中print,我们有一个由 lambda 表达式定义的函数,应用于 5。

\n

在第二个中print,我们D需要对它进行评估才能获得要应用的函数5

\n
\n

什么是D?它基本上是一个恒等函数,在返回另一个值之前打印一个值作为副作用。让我们稍微重写一下:

\n
def Dc(m):\n    def identity(x):\n        return x\n    print(m)\n    return identity\n
Run Code Online (Sandbox Code Playgroud)\n

花点时间说服自己这Dc(m)(x)相当于D(m, x)

\n

Dc现在让我们使用in 代替重写原始示例D

\n
print((lambda x: Dc(1)(Dc(2)(Dc(4)(x))))(5))\nprint(Dc(1)(lambda x: Dc(2)(Dc(4)(x)))(5))\n
Run Code Online (Sandbox Code Playgroud)\n

如果我们将 Python 假装成函数组合运算符,就会更容易看出。

\n
f \xe2\x88\x98 g = lambda x: f(g(x))\n
Run Code Online (Sandbox Code Playgroud)\n

(f \xe2\x88\x98 g)(x)只需调用g(x),然后将结果传递给f.

\n

重要提示:请记住, 的任何副作用g都会在 的副作用之前发生f

\n

现在让我们使用新的组合运算符重写我们的两个示例。

\n
print((Dc(1) \xe2\x88\x98  Dc(2) \xe2\x88\x98 Dc(4))(5)) # print(t(5)) where t = Dc(1) \xe2\x88\x98  Dc(2) \xe2\x88\x98 Dc(4)                                                                                                                                                                                                                                                                                                                   \nprint(Dc(1)((Dc(2) \xe2\x88\x98 Dc(4))(5))  # print(Dc(1)(t)(5)) where t = Dc(2) \xe2\x88\x98 Dc(4)\n
Run Code Online (Sandbox Code Playgroud)\n

由于组合本身不会产生副作用,并且函数组合具有结合性,因此我们可以分解出Dc(2) \xe2\x88\x98 Dc(4)使其更易于阅读。

\n
t = Dc(2) \xe2\x88\x98 Dc(4)\nprint((Dc(1) \xe2\x88\x98 t)(5)\nprint(Dc(1)(t)(5))\n
Run Code Online (Sandbox Code Playgroud)\n

现在很容易看到发生了什么

\n
    \n
  1. 在第一种情况下,我们创建一个函数,其副作用是在返回要打印的 5 之前打印 4, 2, 1。
  2. \n
  3. 在第二种情况下,我们调用 Dc(1)on t,在调用 之前立即输出 1 t(5),后者在返回 5 之前输出 4 和 2。
  4. \n
\n