简体   繁体   English

试图理解Python中的递归

[英]Trying to understand recursion in Python

I've been trying to understand the following code, it's a recursion example from my Python book: 我一直试图理解下面的代码,这是我的Python书中的一个递归示例:

def mysum(L):
    if not L:
        return 0
    else:
        return L[0] + mysum(L[1:])


print(mysum([1, 2, 3, 4, 5]))

output: 15

I have a very hard time to understand how this works, and how it is returning 15 . 我很难理解它是如何工作的,以及它是如何返回的15

I've tried to rewrite the code as: 我试图将代码重写为:

def mysum(L):
    if not L:
        return 0
    else:
        temp = L[0] + mysum(L[1:])
        print(temp)
        return temp


mysum([1, 2, 3, 4, 5])

this outputs: 这个输出:

5
9
12
14
15

But i'm still not sure how this works, it's like it starts to sum backwards. 但我仍然不确定这是如何工作的,就像它开始倒退一样。 5 + 4 + 3 + 2 + 1

return L[0] + mysum(L[1:])
I know that functions on the right get executed before the function returns anything. 我知道右边的函数在函数返回任何内容之前执行。 In this case it's recursive, it calls itself until L has no elements in it. 在这种情况下,它是递归的,它会调用自身,直到L中没有元素。 But if it calls itself again, wouldn't that mean that it again doesn't return anything? 但如果它再次召唤自己,那是不是意味着它又不会返回任何东西? This is very confusing to me. 这对我来说非常困惑。

L[0] is the head of the list and L[1:] is the rest. L[0]是列表的头部, L[1:]是其余部分。 In each call the function adds the first element and the sum of the remaining list. 在每次调用中,函数都会添加第一个元素和剩余列表的总和。

So what is happening is: 所以发生的事情是:

mysum([1, 2, 3, 4, 5]) => 1 + mysum([2, 3, 4, 5])
mysum([1, 2, 3, 4, 5]) => 2 + mysum([3, 4, 5])
mysum([1, 2, 3, 4, 5]) => 3 + mysum([4, 5])
mysum([1, 2, 3, 4, 5]) => 4 + mysum([5])
mysum([1, 2, 3, 4, 5]) => 5 + mysum([])
mysum([]) => 0

After the last call everything everything returns. 在最后一次通话之后,一切都会回来

Maybe it would be helpful for you to print not only your temp but also L. 也许你不仅可以打印你的温度,还可以打印L.

it's like it starts to sum backwards. 就像它开始倒退一样。

Well that's because it kind of does, this is an example of tail recursion which is not optimized in python, imagine replacing the mysum(L[1:]) with the result in brackets, you would get something like this: 好吧那是因为它有点,这是一个尾递归的例子,没有在python中优化,想象用括号中的结果替换mysum(L[1:]) ,你会得到这样的东西:

#L[0] + mysum(L[1:])
mysum([1,2,3,4,5])
1 + mysum([2,3,4,5])
1 + (2 + mysum([3,4,5]))
1 + (2 + (3 + mysum([4,5])))
1 + (2 + (3 + (4 + mysum([5]))))
1 + (2 + (3 + (4 + (5 + mysum([])))))
1 + (2 + (3 + (4 + (5 + 0))))

The inner most level of recursion must finish evaluating before the above levels can, so it only actually starts adding the numbers together once the list has been exhausted and then starts will last recursive call. 内部最高级别的递归必须在上述级别之前完成评估,因此只有在列表耗尽后才开始将数字加在一起,然后启动将持续递归调用。 (the end of the list) (列表的末尾)

But if it calls itself again, wouldn't that mean that it again doesn't return anything? 但如果它再次召唤自己,那是不是意味着它又不会返回任何东西?

Well yes, but only until it can return something without requiring another recursive call, then it can return something, and then the level above can return, then the level above... 是的,但只有它可以返回一些东西而不需要另一个递归调用,然后它可以返回一些东西,然后上面的级别可以返回,然后上面的级别...

Let's follow your first part of code, we call it with the list [1,2,3,4,5] 让我们按照您的第一部分代码,我们将其称为列表[1,2,3,4,5]

The first call has L = [1,2,3,4,5] so gets into the second portion and does: 第一个调用有L = [1,2,3,4,5]所以进入第二部分并执行:

return 1 + mysum([2,3,4,5])

mysum is called again, now with a smaller list, which does: 再次调用mysum,现在使用较小的列表,其中:

return 2 + mysum([3,4,5])

Next up: 接下来:

return 3 + mysum([4,5])

Then: 然后:

return 4 + mysum([5])

One more time with the normal flow: 再一次正常流程:

return 5 + mysum([])

This time our passed list is empty and our function returns 0. This cascades back on the stack, which means mysum([5]) now evaluates to 5 (5+0=5), this leads to an evaluation of mysum([4,5]) etcetera all the way up to our first call which returns 15. 这次我们传递的列表是空的,我们的函数返回0.这个级联返回堆栈,这意味着mysum([5])现在的计算结果为5(5 + 0 = 5),这导致了对mysum的评估([4] ,5))etcetera一直到我们的第一次调用返回15。

Consider this code: 考虑以下代码:

def mysum0(L):
    return 0

def mysum1(L):
    return L[0] + mysum0(L[1:])

def mysum2(L):
    return L[0] + mysum1(L[1:])

def mysum3(L):
    return L[0] + mysum2(L[1:])

def mysum4(L):
    return L[0] + mysum3(L[1:])

print(mysum4([1, 2, 3, 4]))

Each function mysum[n] sums a list of length n and delegates to mysum[n-1] to help it out. 每个函数mysum[n]总结一个长度为n的列表,并委托给mysum[n-1]来帮助它。 Can you understand how that works? 你能理解它是如何工作的吗? The recursive mysum function is like all the mysum[n] functions combined into one. 递归的mysum函数就像所有mysum[n]函数合二为一。 It only needs to know how to handle a length of list 0 and how to take care of one layer. 它只需要知道如何处理列表0的长度以及如何处理一个层。

You can test the hypothetical question you raised: What happens when the recursion gets to the point that the list has only one element in it? 您可以测试您提出的假设问题:当递归到达列表中只有一个元素时会发生什么?

>>>print(mysum([5]))

returns: 收益:

5

Because it executes: 因为它执行:

return L[0] + mysum(L[1:])

L[0] returns 5, and mysum(L[1:]) (because L[1:] doesn't exist with a list of length 1) returns 0. L [0]返回5,并且mysum(L [1:])(因为L [1:]不存在,长度为1的列表)返回0。

So, now that the function has done that, it can compute the next mysum in the recursion, for L = [4, 5], which turns into: 所以,既然函数已经完成了,它可以计算递归中的下一个神秘,对于L = [4,5],它变成:

return L[0] + mysum[L[1:]

which is equivalent to: 这相当于:

return 4 + mysum[5]

which, since we calculated mysum[5] = 5, is equivalent to: 因为我们计算的mysum [5] = 5,相当于:

return 4 + 5

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM