涉及函数、递归和类的 Python 练习

Posted

技术标签:

【中文标题】涉及函数、递归和类的 Python 练习【英文标题】:Python Exercise involving functions, recursion and classes 【发布时间】:2017-11-12 13:28:44 【问题描述】:

我正在做一个练习,我要创建一个表示函数(写成 lambda 表达式)和涉及它们的几个方法的类。

目前我写的有:

class Func():
    def __init__(self, func, domain):
        self.func = func
        self.domain = domain

    def __call__(self, x):
        if self.domain(x):
            return self.func(x)
        return None

    def compose(self, other):
        comp_func= lambda x: self.func(other(x))
        comp_dom= lambda x: other.domain(x) and self.domain(other(x))
        return Func(comp_func, comp_dom)

    def exp(self, k):
        exp_func= self
        for i in range(k-1):
            exp_func = Func.compose(exp_func, self)
        return exp_func 

正如你在上面看到的,函数 exp 与自身组合了一个函数 k-1 次。现在我要编写上述函数的递归 版本,采用相同的参数“self”和“k”。 但是我很难弄清楚它是如何工作的。在我写的原始 exp 中,我可以在所有迭代中访问原始函数“self”,但是在创建递归函数时,我无法访问原始函数,并且每次迭代只能访问最近组合的函数。因此,例如,如果我尝试将 self 与 self 组合一定次数,我将得到:

f= x+3
f^2= x+6
(f^2)^2= x+12

所以我们跳过了函数 x+9。

我该如何解决这个问题?有没有办法仍然保留对原始功能的访问权限?

更新:

def exp_rec(self, k):
    if k==1:
        return self
    return Func.compose(Func.exp_rec(self, k-1), self)

【问题讨论】:

恕我直言,如果您必须将 lambda 分配给变量,那么最好从它进行闭包(即使用 def funcname(x): 而不是 funcname = lambda x: ... 说明我要使用 lambda 表达式。 好吧,请记住:***.com/questions/25010167/… 【参考方案1】:

这是一个练习,所以我不会提供答案。

在递归中,你想做两件事:

确定并检查告诉您何时停止的“警戒条件”;和

确定并计算告诉您下一个值的“递归关系”。

考虑一个简单的阶乘函数:

def fact(n):
    if n == 1:
        return 1

    return n * fact(n - 1)

在这个例子中,保护条件相当明显——它是唯一的条件语句!而递归关系在return语句中。

对于您的练习,事情不太明显,因为其目的是定义一个函数组合,而不是一个直接的整数计算。但请考虑:

f = Func(lambda x: x + 3)

(这是您的示例。)您希望 f.exp(1) 与 f 相同,并且 f.exp(2) 与 f(f(x)) 相同。那里告诉你守卫条件和递归关系:

保护条件是 exp() 仅适用于正数。这是因为 exp(0) 可能必须为不同的输入类型返回不同的东西(当 f = Func(lambda s: s + '!') 时 exp(0) 返回什么?)。

因此测试 exp(1),并将该条件设为原始 lambda。

然后,当递归定义 exp(n+1) 时,让它成为你的 original lambda 与 exp(n) 的组合。

您需要考虑几件事情:首先,您的类实例 有与之关联的数据。该数据将在您的递归中与您一起“旅行”,因此您不必递归传递这么多参数。其次,您需要决定 Func.exp() 是应该创建一个新的 Func(),还是应该修改现有的 Func 对象。最后,考虑如何编写一个硬编码函数Func.exp2(),它刚刚构建了我们称之为Func.exp(2) 的东西。这应该让您了解您的重复关系。

更新

基于一些 cmets,我觉得我应该展示这段代码。如果您要让递归函数修改 self 对象,而不是返回新对象,那么您需要在修改 self 之前“缓存”这些值,如下所示:

func = self.func
domain = self.domain

... recursive function modifies self.func and self.domain

【讨论】:

感谢您的回答。然而,这并没有真正让我知道如何前进,因为正如你所说,我应该让 exp(n+1) 成为原始 lambda 函数的组合,但是我如何访问那个“原始”函数? exp 可以采用的唯一参数是“self”和 k。 “k”显然没有给我关于原始函数的信息,因此递归必须采用原始函数的某个版本。所以在第一次迭代之后,exp 将不再记住原来的 lambda 函数,而只会记住直到某个 k 的合成。那么我该如何用它来组合 exp(n) 呢? self 里面的某个地方没有这个功能吗? 起初。但仅限于递归的第一步。第一步,你用自我组合自我,创造自我^2。然后你将它传递给递归的下一步,所以 self 现在是 self^2。如果你再次尝试用 self 组合它,你会得到 self^4 而不是 self^3。 假设你已经决定 exp() 修改 self (而不是返回一个单独的对象)。在这种情况下,在递归之前将 lambda 函数存储在局部变量中。 [edit]我添加了一个更新来演示 我不想修改原来的自己。但是我不能将同一个 self 传递给递归的下一步,否则我并没有真正做任何事情。当我在 exp 中调用 exp 时,我将不得不在 self 的组合版本上调用它。然后在下一步 exp 不知道原来的 self 是什么。

以上是关于涉及函数、递归和类的 Python 练习的主要内容,如果未能解决你的问题,请参考以下文章

Python基础 | 深浅拷贝问题递归函数练习

python小练习--函数调用函数,让对象具有能动性

python之路文章目录

Python基础-----函数内置函数递归等练习

Python基础-----while循环练习

python小练习--属性