【问题标题】:How does this Python Lambda recursion expression work?这个 Python Lambda 递归表达式是如何工作的?
【发布时间】:2011-04-24 03:01:43
【问题描述】:
rec_fn = lambda: 10==11 or rec_fn()
rec_fn()

我是 Python 新手,并试图了解 lambda 表达式的工作原理。有人可以解释这个递归是如何工作的吗?我能够理解 10==11 将是“假”,这就是 rec_fn 将如何被一次又一次地递归调用。

但我无法得到的是这种看似新的编写 lambda 表达式的方式。

lambda x: x+y 在未命名函数中有参数“x”时发生了什么?

还有,为什么是

rec_fn() = lambda: .... // a syntax error
rec_fn = lambda: .... //syntactically correct - WHY?

什么是rec_fn?是函数还是变量?

【问题讨论】:

  • 谢谢大家!你的解释很棒:D 但在我接受答案之前,我需要知道 lambda 内部发生了什么。条件构造“或”如何工作?这有点像 if/else 语句。 “如果不是这个,那就执行那个”之类的事情

标签: python recursion lambda


【解决方案1】:

函数调用 -- x() -- 是一个表达式。它是赋值左侧的许多合法语法结构。应该发生什么? (和42 = lambda: ....说的差不多)

在第二种情况下,您只是将创建的新函数对象(使用 lambda 关键字)分配给一个变量(名为 rec_fn),而不是调用函数。

也许更清晰的方法是使用(首选)非 lambda 嵌套函数方法:

# just for example, not really useful as it is unless you like to eat CPU
def rec_fn():
  return 10 == 11 or rec_fn()

rec_fn()

lambda 关键字只是一个语法快捷方式,可用作表达式的一部分。

rec_fn 在上述情况下是一个局部变量(假设所述代码嵌套在函数/方法中)。 rec_fn 变量存储一个函数对象,稍后可以使用() 调用该函数对象。方法大致相同(可以调用的函数),但它们是属性而不是变量

【讨论】:

    【解决方案2】:
      rec_fn = lambda: 10==11 or rec_fn()
      rec_fn()
    

    和这个表达式类似,但是这个需要一个参数,

    rec_fn = lambda x: 10==11 or rec_fn(x)
    x = ...
    rec_fn(x)
    

    而你的 rec_fn() 你正在调用一个没有参数的函数,因此没有 x

    rec_fn() = lambda: .... // a syntax error
    

    这是试图将函数调用 rec_fn() (右侧表达式)的结果设置为一个值。那里没有变量可以分配 lambda 函数。

    rec_fn = lambda: .... //syntactically correct - WHY?
    

    这里是包含 lambda 的变量中的 rec_fn(本质上就像一个函数指针)

    【讨论】:

      【解决方案3】:
      rec_fn = lambda: 10==11 or rec_fn()
      rec_fn()
      

      函数体在执行之前不会被评估。一开始,rec_fn 没有任何价值。 lambda 的内容只是一些表达式,它对某个变量 rec_fn 进行了一些函数调用。它不会失败,因为该函数尚未执行。然后将新的 lambda 函数分配给变量 rec_fn,然后调用该函数。现在由于该函数正在执行,它将经历直到函数调用的动作。表达式为10==11 or rec_fn()。这是一个or 表达式,因此评估了左侧。 10==11 为 False,因此它必须评估右侧,这是对某个函数(或其他可调用对象)rec_fn 的函数调用。此时,rec_fn 被分配给我们刚刚创建的函数(本身),因此它被调用(递归)。等等。相当于:

      def rec_fn():
          return 10==11 or rec_fn()
      

      可以根据需要使用尽可能多的参数来编写 Lambda。在lambda: ... 的情况下,没有指定,所以它是一个“不带参数的函数”。

      请记住,函数(以及扩展的 lambda)是第一类对象。您可以像传递任何其他对象一样传递它们并将它们存储到其他变量中。

      rec_fn = lambda: ...
      

      很好,因为您已经定义了一个 lambda 函数并将其存储到变量 rec_fn 中。可以像使用任何其他函数一样使用该名称 rec_fn() 来调用它。

      rec_fn() = lambda: ...
      

      另一方面,失败是因为你不能为函数调用rec_fn()的结果分配任何东西。

      以这种方式定义函数与普通函数定义有很大不同:

      def rec_fn2(): # here you may use the parens with the name to indicate it takes no arguments
          ...        # unlike in the lambda assignment above
      

      试着记住不同之处。

      【讨论】:

        【解决方案4】:

        将函数调用视为运算符可能会有所帮助。因为它就是这样。当您执行rec_fn() 时,您正在做两件事。首先,您将获得对名为rec_fn 的对象的引用。这恰好是一个函数,但这并不重要(在 Python 中,除了函数之外的对象是可调用的)。然后是(),意思是“调用我刚刚命名的对象”。可以在不调用函数的情况下获得对函数的引用,只需去掉括号,然后您可以为其分配不同的名称,然后可以通过 添加 来调用它括号。

        def func1():
           print "func1"
        
        func2 = func1
        
        func2()       # prints "func1"
        

        现在您可以看到 lambda 是如何工作的。

        func3 = lambda x: x+1
        

        除了 lambda 表达式 函数之外,您正在执行与上面的 func2 = func1 行相同的操作。语法只是不同; lambda 函数可以在不给它命名的情况下定义。

        Lambda 可以有任意数量的参数,因此lambda: 3 是一个不带参数且始终返回 3 的函数,而 lambda x, y: x+y 是一个带两个参数并返回其和的函数。

        至于or的使用方式,它利用了短路。基本上,or知道如果它的第一个操作数是True,它就不需要评估第二个,因为无论第二个参数是什么,结果都将是True。因此,您可以将其读作if not 10==11: rec_fn()。顺便说一句,and 也会短路,尽管如果第一个参数是 False 它会这样做,因为无论第二个参数是什么,它都知道结果将是 False

        【讨论】:

          【解决方案5】:

          这可能是更容易理解的递归示例,阶乘 lambda 版本:

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

          输出:

          3628800
          

          不过,请注意 Python 的递归限制。

          使用 or as this if..else 的示例:

          print 1 or 'a'
          print 'a' or False
          print False or True or 0/9
          fact_or = lambda x: x == 0 and 1 or x * fact_or(x-1)
          print fact_or(10)
          

          【讨论】:

          • 对,这个肯定比较好理解。清除“if/else”语句。但是使用“或”要简洁得多。不知何故,它不是很直观。
          • 使用il作为变量名也很简洁,有时我有时会匆忙或出于旧习惯使用它们。事后我也常常后悔。
          猜你喜欢
          • 2016-03-19
          • 1970-01-01
          • 1970-01-01
          • 2013-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-03
          相关资源
          最近更新 更多