为了账号安全,请及时绑定邮箱和手机立即绑定

在递归函数中返回中间值是 Python 的怪癖吗?

在递归函数中返回中间值是 Python 的怪癖吗?

ABOUTYOU 2021-08-17 11:01:12
更新:让我澄清一下究竟是什么如此令人困惑。如果我添加这样的打印语句:    def recur(lis, json, target):        if lis[0] == target:            print(json[tagert])            return json[target]        else:            recur(lis[1:], json[lis[0]], target)我的打印语句将显示 JSON 的预期值。我不知道如何表达这句话。鉴于 return 语句之前的行给出了我期望的结果(else 中没有 return 语句)为什么 else 中的 return 语句是必要的?对于那些坚持反对这一点的人,我已经多次查看了有关缺少 return 语句的问题。其中任何一个从未得到回答的是为什么需要返回。随心所欲地对我投反对票,但至少要明白你在投反对票一个好问题。我认为这个社区正在成熟,但显然没有。因此,我查看了几个与我的标题相同的问题,但我仍然不太明白为什么会这样。如果我有这样的递归函数:def recur(lis, json, target):    if lis[0] == target:        return json[target]    else:        return recur(lis[1:], json[lis[0]], target)我按预期获得了返回值。但是如果我不在 else 语句中返回 the,我会得到一个 None:def recur(lis, json, target):    if lis[0] == target:        return json[target]    else:        recur(lis[1:], json[lis[0]], target)>>> final_json = recur(my_list, my_json, 'ID')>>> print(final_json)   None这是特定于 Python 的吗?我有点生疏,但我似乎记得像 Haskell 这样的语言更优雅地处理这个问题,我相信,我不需要返回递归调用的值。这对我来说更有意义 - 我不需要所有中间值,因为我在堆栈的每个级别传递我的函数所需的所有值。我在这里缺少什么?
查看完整描述

3 回答

?
倚天杖

TA贡献1828条经验 获得超3个赞

我能想到的最好的证明方法是比较一个非常简单的递归递归函数,在几种不同的语言中。我选择的函数将计算整数的阶乘。(一个非负数,为了简单起见,如果出现负整数、浮点数或一些愚蠢的东西,我不会尝试执行任何验证来阻止函数爆炸。)


首先,在 Python 中:


def factorial(n):

    if (n == 0):

        return 1

    return n * factorial(n-1)

所以在这里你有“返回的中间值”,这似乎是你声称的似乎是 Python 独有的。(当然,您不是返回递归调用本身的结果,而是对其执行的简单操作 - 但这不会改变情况,除非我完全误解了。您仍在返回值,以便用这个“中间结果”做一些事情。)


那么让我们来看看如何在 Javascript 中做同样的事情。(是的,两种语言都有更优雅的方法来做到这一点,但我试图保持简单和严格的可比性。)


function factorial(n) {

    if (n == 0) {

       return 1;

    }

    return n * factorial(n-1);

}

我希望你会同意,撇开基本语法上的细微差别,JS 版本与上面的 Python 版本相同。特别是,两者都做“返回中间值”的事情。


我可以在 PHP 中编写完全相同的东西,或者(虽然我对这些语言不太熟悉)我认为在 C/C++/C#/Java 中,它会再次非常相同。


现在,如果我们最终来到 Haskell,它实际上是一种与上述所有语言完全不同的语言,让我们看看如何定义相同的函数:


factorial :: Integer -> Integer

factorial n

    | n==0 = 1

    | otherwise = n * factorial (n-1)

是的,这里没有明确的 return 语句。但这只是因为 Haskell 函数是必须始终产生一个值的“纯”函数,因此在一些更复杂的代码的末尾,您只需定义它的结果,而不是使用明确的语句来告诉您该值是什么在每个可能的输入上。


当然,您可以并且经常使用组合和其他高阶操作以“无点”风格更抽象地定义函数 - 这是函数式编程的好处之一。但归根结底,在 Haskell 中,函数最终是根据给定输入产生的输出来定义的——这实际上是基本的,这就是“函数”这个词在数学中的含义,以及它在数学中的含义纯函数式语言。(与单纯的“过程”相反,一个可重用的代码块可能会或可能不会产生一个值,就像在大多数过程语言(如 JS、Python 和其他语言)中一样。)


所以换句话说,上面仍然“返回中间值”。将=在本例中的最后一行标志是否工作return在其他语言的语句。


因此,如果我在一个非常简单的话题上讨论了太久,我深表歉意——我仍然不确定您的困惑在哪里。但我希望这能帮助你克服它。


查看完整回答
反对 回复 2021-08-17
  • 3 回答
  • 0 关注
  • 189 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信