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

Ram*_*amy -1 python recursion python-3.x

更新:让我澄清一下这究竟是什么令人困惑.如果我添加这样的print语句:

    def recur(lis, json, target):
        if lis[0] == target:
            print(json[tagert])
            return json[target]
        else:
            recur(lis[1:], json[lis[0]], target)
Run Code Online (Sandbox Code Playgroud)

我的print语句将显示JSON的预期值.我不知道怎么说这个.鉴于return语句之前的行给出了我期望的结果(在else中没有return语句)为什么else中的return语句是必要的?

对于那些坚持对此进行贬低的人,我已经多次查看了关于丢失退货声明的问题.从来没有回答过任何一个问题的原因是为什么必须回归.向你倾倒所有你想要的东西,但至少要明白你是在贬低一个好问题.我认为这个社区正在成熟,但显然不是.


所以我看了几个与我同名的问题,我仍然不太明白为什么会这样.

如果我有这样的递归函数:

def recur(lis, json, target):
    if lis[0] == target:
        return json[target]
    else:
        return recur(lis[1:], json[lis[0]], target)
Run Code Online (Sandbox Code Playgroud)

我按预期获得了返回值.

但是如果我不在else语句中返回,我得到一个None:

def recur(lis, json, target):
    if lis[0] == target:
        return json[target]
    else:
        recur(lis[1:], json[lis[0]], target)
Run Code Online (Sandbox Code Playgroud)
>>> final_json = recur(my_list, my_json, 'ID')
>>> print(final_json)   
None
Run Code Online (Sandbox Code Playgroud)

这是特定于Python的吗?我有点生疏,但我似乎记得像Haskell这样的语言更优雅地处理它,我相信,我不需要返回递归调用的值.这对我来说更有意义 - 我不需要所有的中间值,因为我传递了我的函数在堆栈的每个级别所需的所有值.我在这里错过了什么?

Rob*_*ond 5

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

首先,在Python中:

def factorial(n):
    if (n == 0):
        return 1
    return n * factorial(n-1)
Run Code Online (Sandbox Code Playgroud)

所以在这里你有"返回的中间值",这似乎是你声称似乎是Python独有的.(当然你没有返回递归调用本身的结果,但是对它执行了一个简单的操作 - 但这并没有改变这种情况,除非我完全误解了.你仍然按顺序返回值用这个"中间结果"做点什么.)

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

function factorial(n) {
    if (n == 0) {
       return 1;
    }
    return n * factorial(n-1);
}
Run Code Online (Sandbox Code Playgroud)

我希望你会同意,抛开基本语法中的微不足道的差异,JS版本与上面的Python版本相同.特别是,两者都做"返回中间值"的事情.

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

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

factorial :: Integer -> Integer
factorial n
    | n==0 = 1
    | otherwise = n * factorial (n-1)
Run Code Online (Sandbox Code Playgroud)

是的,这里没有明确的退货声明.但这只是因为Haskell函数是必须始终产生值的"纯"函数,所以在一些更复杂的代码结束时,您只需定义其结果,而不是使用显式语句来告诉您该值是什么.在每个可能的输入上.

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

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

所以,如果我对一个非常简单的话题进行了太长时间的话,我深表歉意 - 我仍然不确定你的困惑在哪里.但我希望这有助于你克服它.