如何将一个函数应用于其自身?

9
假设我有一个名为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或类似函数来实现这个目的的方法吗?

7个回答

8
也许可以使用map或类似的函数来完成这个任务吗?
不是map,而是reduce。我不会用它来做这个,但你可以在n项序列上调用reduce,使f被调用n次。例如:
>>> def f(x):
...   return x+1
... 
>>> reduce(lambda n,_: f(n), range(100), 42)
142

解释:

  • n 被赋值为 f 的每个连续返回值。
  • _ 是一个由 range(100) 中的数字组成的列表。这些数字都被忽略。唯一重要的是它们的数量。
  • 42 是起始值。

100 层嵌套调用 f(f(f...(f(42))...)) 的结果是 142


5
在Python中,for循环是最符合人体工程学和易读性的方式。因此,我认为这主要是一种练习——在函数式语言中更自然地使用它们。
functools.reduce通过重复调用具有两个参数的函数将值列表折叠为单个值。下面是阶乘的示例: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

2

虽然从你的例子中不清楚你是想计算最终数字结果还是累积值列表,但你可以使用一个非常简单的带有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]

1
构造将是递归。但是递归需要在某个点结束调用堆栈。这种情况可以使用诸如以下算法的算法:
if(x == 0):
    return 1
# this will make sure it ends at the preceding line in the next call
return f(x - 1) 

这通常是计算阶乘等结果的方法。
举个例子,增加一个要求(仅在 x < 2 时计算,只是举例):
def f(x):
  if(x < 2):
    return 1
  return f(x/2+1)

关键是要有一个点开始回溯调用栈(以避免溢出)。

0
你可以将递归分解出来:
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

0

-1
我认为你所询问的是递归的概念。你可以使用类似于lambda函数的东西,但在for循环中进行递归调用并不是本质上的坏事。我建议你先了解一下递归函数的基本概念,然后再寻找特别针对Python的实现方法。

不,for循环并不是不好的,但我想避免使用它们来挑战自己。递归是一个好选择,我已经忘记了这一点。 - Demetri Pananos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接