【问题标题】:How can I apply a function to itself?如何将函数应用于自身?
【发布时间】:2018-03-06 18:37:16
【问题描述】:

假设我有一个函数f,它接受一些变量并返回一个相同类型的变量。为简单起见,假设

def f(x):
    return x/2+1

我有兴趣一遍又一遍地将f 应用于自身。类似f(f(f(...(f(x))...)))

我可以这样做

s = f(x)
for i in range(100):
    s = f(s)

但我想知道是否有一种更简单、更简洁的方法来做同样的事情。我不想避免for 循环(就像对自己的挑战)。是否有某种方法可以使用map 或类似功能来完成此操作?

【问题讨论】:

    标签: python


    【解决方案1】:

    有没有办法使用map 或类似的函数来完成这个?

    不是map,而是reduce。我不会为此使用它,但您可以在 n-item 序列上调用 reduce 以使 f 被调用 n 次。例如:

    >>> def f(x):
    ...   return x+1
    ... 
    >>> reduce(lambda n,_: f(n), range(100), 42)
    142
    

    解释:

    • n 分配f 的每个连续返回值。
    • _ 是来自 range(100) 的数字列表。这些数字都被忽略了。重要的是有多少。
    • 42 是起始值。

    100f(f(f...(f(42))...)) 的嵌套调用导致142

    【讨论】:

      【解决方案2】:

      在 Python 中,for 循环是最符合人体工程学和可读性的方法。所以我认为这主要是一个练习——这些在函数式语言中使用起来更自然。

      functools.reduce 通过重复调用两个参数的函数将值列表折叠为单个值。这是阶乘:

      >>> import functools, operator
      >>> operator.mul(2,3)
      6
      >>> functools.reduce(operator.mul, range(1, 10), 1)
      362880
      

      我们可以滥用这一点,仅使用值列表作为其长度而忽略实际内容。

      >>> def f(x):
      ...   return x/2+1
      ... 
      >>> functools.reduce(lambda x, y: f(x), range(10), 1)
      1.9990234375
      

      或者我们可以将(一元)函数的 n 个副本串在一起,并通过将每个副本应用于累积值来折叠它们。

      >>> import itertools
      >>> functools.reduce(lambda x, g: g(x), itertools.repeat(f, 10), 1)
      1.9990234375
      

      【讨论】:

        【解决方案3】:

        虽然从您的示例中不清楚您是尝试计算最终数值结果还是累积值列表,但您可以使用非常简单的递归方法和 lambda 函数:

        单值:

        f = lambda x, c = 1:x if c == 100 else f(x/2 + 1, c+1)
        >>f(200)
        2
        

        值列表:

        f = lambda x, c = 1:x if c == 100 else f(x+[x[-1]/2+1], c+1)
        >>f([200])
        [200, 101, 51, 26, 14, 8, 5, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
        

        【讨论】:

          【解决方案4】:

          构造将是递归。但是递归要求您的调用堆栈在某个时刻结束。这种情况可以使用以下算法:

          if(x == 0):
              return 1
          # this will make sure it ends at the preceding line in the next call
          return f(x - 1) 
          

          这通常是用于计算结果的方法,例如阶乘。

          举个例子,添加一个要求(仅当 x

          def f(x):
            if(x < 2):
              return 1
            return f(x/2+1)
          

          关键是调用栈有一个点开始返回(避免溢出)

          【讨论】:

            【解决方案5】:

            您可以在定义的返回行中添加函数本身。一个例子是这里的最佳答案How can I build a recursive function in python?

            【讨论】:

              【解决方案6】:

              你可以排除递归:

              from functools import partial
              recurse = partial(lambda g,f,x,n: g(g,f,x,n), # capture g
                                lambda g,f,x,n: n and g(g, f, f(x), n-1) or x)
              

              如果您对单行器更好的东西,可以取消递归:

              import itertools
              def recurse(f, x, n):
                for _ in itertools.repeat(None, n):
                  x = f(x)
                return x
              

              然后:

              >>> f = lambda x: x/2+1
              >>> recurse(f, 42, 5)
              7.0
              >>> f(f(f(42)))
              7.0
              

              【讨论】:

                【解决方案7】:

                我认为您要问的是称为递归的概念。您可以使用 lambda 函数之类的东西,但 for 循环中的递归调用本质上并不是坏事。我一般会阅读更多关于递归函数的信息,然后专门寻找 python 实现。

                【讨论】:

                • 不,for 循环还不错,但我想避免它们成为挑战。递归很好,我忘记了。
                猜你喜欢
                • 2012-02-28
                • 1970-01-01
                • 1970-01-01
                • 2023-04-05
                • 2016-01-13
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多