该函数查找列表中各项的总和,并且工作正常。它将列表中的第一项与列表的其余部分相加。 递归调用函数 mysum ,直到它为空。 当列表为空时,它返回0。但是为什么不覆盖该函数的先前返回值?
>>> def mysum(L):
if not L:
return 0
else:
return L[0] + mysum(L[1:])
>>> mysum([1, 2, 3, 4, 5])
15
答案 0 :(得分:2)
因为该函数的第一个调用是返回的最后一个。假设您有列表[1,2,3]
。您的代码将最终以
return 1 + sum([2, 3])
其中1 + sum([2,3])
是表达式。在此表达式变为值之前,代码将在那里等待。因此,它使此功能保持打开状态并等待sum(2,3])
的结果。本质上,您的代码变为
return 1 + (return 2 + sum([3]))
同样,2 + sum([3])
需要等待sum([3])
,您最终会得到类似
return 1 + (return 2 + (return 3 + sum([])))
现在,sum([])
不必等待任何人,它变成了0
,所以
return 1 + (return 2 + (return 3 + 0))
return 1 + (return 2 + 3)
return 1 + 5
return 6
答案 1 :(得分:0)
递归调用的结果不仅会沿调用堆栈传递(例如return mysum(L[1:])
),而且还会在每个中间步骤进行处理:
def mysum(L):
if not L:
return 0 # -------+
else: # |
return L[0] + mysum(L[1:])
# ^^^^^^^^^^^^ == 0 for the innermost call
# ^^^^^ != 0 in the general case
# ^^^^^^^^^^^^^^^^^^^ != 0 hence
答案 2 :(得分:0)
1. mysum([1, 2, 3, 4, 5])
L
不为空,所以我们转到else:
2. return 1 + mysum([2, 3, 4, 5])
L
不为空,所以我们转到else:
3. return 2 + mysum([3, 4, 5])
L
不为空,所以我们转到else:
4. return 3 + mysum([4, 5])
L
不为空,所以我们转到else:
5. return 4 + mysum([5])
L
不为空,所以我们转到else:
6. return 5 + mysum([])
L
为空,因此我们不进行其他操作:
7. return 0
现在我们知道mysum([])
的值了,让我们看看6的值是什么:
6'. return 5 + 0
这是5。现在我们知道mysum([5])
的值了,让我们看看5的值是什么:
5'. return 4 + 5
这是9。现在我们知道mysum([4, 5])
的值了,让我们看看4的值是:
4'. return 3 + 9
这是12。现在我们知道mysum([3, 4, 5])
的值了,让我们看看3的值是:
3'. return 2 + 12
这是14。现在我们知道mysum([2, 3, 4, 5])
的值了,让我们看看2的值是:
2'. return 1 + 14
现在我们知道mysum([1, 2, 3, 4, 5])
的值:15。
答案 3 :(得分:0)
递归没有什么特别的。您将返回L[0]
的结果以及某些函数调用的结果。图像“某些函数调用”是对其他任何函数的调用:
else:
return L[0] + sum(L[1:])
您希望以某种方式覆盖收益吗?当然不是。在这里是mysum
而不是sum
没什么不同。
答案 4 :(得分:0)
递归功能的行为可以表示为调用树。并在“返回”之前完成呼叫。
因此,在您的示例中:
调用mysum([1、2、3、4、5])可以做到:
步骤1-返回1 +调用mysum([2,3,4,5])
步骤2-后面的调用返回2 +调用mysum([3,4,5])
第3步-后一个调用返回3个调用mysum([4,5])
步骤4-后面的调用返回4 +调用mysum([5])
第5步-后一个调用返回5个调用mysum([])
第6步-后一个调用返回0
第7步-进入通话树并进行添加。