【问题标题】:Decoding a Cryptic Python statement解码一个神秘的 Python 语句
【发布时间】:2014-02-03 14:04:52
【问题描述】:

我在招聘广告上看到了这个(在 SO 上):

lambda f: (lambda a: a(a))(lambda b: f(lambda *args: b(b)(*args)))

所以我的理解是它是一个匿名(未命名)函数,它由两个进一步嵌套的匿名函数组成。最里面的函数接受一个变量列表(*args)。

我不知道它应该做什么。这是实际可行的事情,还是如果不查看实际的 args 列表就无法判断?

【问题讨论】:

  • 你确定它应该做什么?
  • 我会赞同@mhlester 的建议,即这是一个病态的玩笑。有可能导致无限递归?!
  • 可能不清楚代码的作用,但很清楚经理必须做什么:解雇程序员,找一个写可读代码的人。
  • 也许他们期待一个潜在的候选人说这是垃圾代码......

标签: python


【解决方案1】:

不只是 *args,如果不知道 abf *args 是什么,很难分辨它是什么。

当 b 作为参数传递给函数 b 时,兔子洞尤其深,结果是传递 args 的函数。

【讨论】:

    【解决方案2】:

    代码正在创建Y-combinator in Python。这只是一个练习,而不是真实世界的代码;不要试图解密它。

    要了解 Y-combinator 本身的作用,您可以参考这个 SO 问题:What is a y-combinator? 及其维基百科页面:Fixed-point combinator

    也许此广告正在寻找了解函数式编程和/或高级计算机科学主题的人,例如 Lambda calculusCombinatory logic,它们是函数式编程背后的主要理论基础。

    或者他们的公司可能是Y Combinator winner startup,他们只是在寻找具有CS背景的Python程序员。

    【讨论】:

      【解决方案3】:

      我撤消了 lambda,只是为了使其更易于阅读。下面是使用嵌套函数的代码:

      def f1(f):
          def f2(a):
              return a(a)
      
          def f3(b):
              def f4(*args):
                  return b(b)(*args)
      
              return f(f4)
      
          return f2(f3)
      

      这基本上相当于:

      f1 = lambda f: (lambda a: a(a))(lambda b: f(lambda *args: b(b)(*args)))
      

      现在让我们关注函数调用。首先,您将使用一些参数调用 f1。然后会发生以下情况:

      1. f2 被 f3 调用
      2. f2 返回以自身为参数调用的 f3
      3. 现在我们在 f3 里面,b 是 f3
      4. f3 以 f4 为参数返回 f(你调用 f1 的参数)
      5. f 是一个回调,它以函数作为其唯一参数调用
      6. 如果 f 调用此函数,则其调用将应用于 b 调用 b 的结果。 b 是 f3,所以 f 本质上是调用 f3(f3) 的结果,这就是 f 将要返回的结果

      因此 f1 可以简化为:

      def f1(f):
          def f3():
              def f4(*args):
                  return f3()(*args)
              return f(f4)
      
          return f3()
      

      现在我想出了一种调用 f1 的方法,它不会以无限递归结束:

      called = False
      
      def g1(func):
          def g2(*args):
              print args
              return None
      
          global called
      
          if not called:
              called = True
              func(5)
          else:
              return g2
      
      f1(g1) # prints "(5,)"
      

      如您所见,它使用全局来停止递归。

      这是另一个示例,它使用 10 的 lambda(lambda 是泊松分布的参数,而不是 lambda 算子)运行泊松分布试验:

      import random
      
      def g3(func):
          def g4(a):
              def g5(b):
                  print a
                  return a+b
              return g5
      
          if random.random() < 0.1:
              return g4(1)
          else:
              return g4(func(1))
      
      f1(g3)
      

      最后是确定性的,不依赖于全局,实际上有点有趣:

      def g6(func):
          def g7(n):
              if n > 0:
                  return n*func(n-1)
              else:
                  return 1
      
          return g7
      
      print f1(g6)(5) # 120
      print f1(g6)(6) # 720
      

      我相信每个人都可以猜到这个函数是什么,但很有趣的是,你实际上可以让这个奇怪的 lambda 表达式做一些有用的事情。

      【讨论】:

      • function 应替换为 def
      • 您应该在 f2 之外但在 f1 内部定义 f3
      【解决方案4】:

      这是相当等价的,没有太多嵌套:

      def f1(f):
          def f2(a): return a(a)
          def f3(b):
              def f4(*args): return b(b)(*args)
              return f(f4)
          return f2(f3)
      

      f2可以替换,所以我们得到

      def f1(f):
          def f3(b):
              def f4(*args): return b(b)(*args)
              return f(f4)
          return f3(f3) # was f2(f3)
      

      f3 总是被自己调用,所以我们将b 替换为f3

      def f1(f):
          def f3():
              def f4(*args): return f3()(*args)
              return f(f4)
          return f3()
      

      那么它有什么作用呢?

      我们看到f3() 返回任何f 返回的值,并且应该使用任意数量的参数调用它。

      f 应该采用一个函数,该函数采用另一个带有 *args 的函数并返回这样的函数。

      调用 f1(f) 返回 f(f4) 返回的任何内容。

      让我们测试一下:

      • 使用f=lambda ff: lambda *args: ff(*args)f1(f)() 为我们提供了无限递归。
      • f=lambda ff: lambda *args: (ff, args) 不会调用给定的函数,所以我们可以放心地使用它:
        • f1(f)(4) 给了我们一个元组 (f4, (4,))
        • 如果我们使用该元组的第 0 个元素:f1(f)(4)[0](1),我们会得到 (f4, (1,))

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-08
        • 1970-01-01
        • 1970-01-01
        • 2012-11-10
        • 1970-01-01
        • 1970-01-01
        • 2020-08-10
        相关资源
        最近更新 更多