我最近研究了Python递归。我发现有些事情很难理解。
看起来像在python中通过递归计数和添加列表的元素几乎以类似的方式完成。有人可以解释一下为什么这些调用只是在下面的返回调用中加上“ 1”和“ num [0]”而导致其行为有所不同的原因:
return "*1*"+sum(num[1:])
和return "*num[0]*"+sum(num[1:])
列表中数字计数的代码:
def count(num):
if len(num) == 0:
return 0
return 1+count(num[1:])
print(count([1,2,3,4,5,6,11]))
输出:7
在列表中添加元素的代码:
def sum(num):
if len(num) == 0:
return 0
return num[0]+sum(num[1:])
print(sum([1,2,3,4,5,6,11]))
输出:32
有人可以在上述两个递归程序中解释返回声明吗?
任何对我有意义的信息都会有很大的帮助。非常感谢。
答案 0 :(得分:2)
首先,让我们用一个循环来编写它,它更具Python风格,对于新手来说也可能更容易理解:
def count(nums):
res = 0
for num in nums:
res = 1 + res
return res
def sum(nums):
res = 0
for num in nums:
res = num + res
return res
+
操作中相同的一个单词。但是现在,希望您能理解为什么会有所不同。第一个从0开始,然后向每个元素加1。第二个元素以0开头,并将元素添加到该元素,每个元素添加一次。
除了稍微复杂一点之外,递归代码基本上在做同样的事情。
实际上,将每个元素压入堆栈,然后从0开始,然后将堆栈弹出直到其为空,然后为每个元素分别添加1或元素(从堆栈弹出)。 1
但是将一堆元素压入堆栈并弹出它们会得到相同的元素,只是相反。将每个元素加1或将所有元素加起来,就可以实现向后计数与向前计数相同的功能。
如果您仍然不明白,则应尝试逐步完成通话。通常,我建议使用交互式可视化工具,例如Python Tutor,但是由于此问题似乎是专门为使您从功能上进行思考而设计的,因此我们就可以这样做。
想象一下,Python中的函数调用只是用参数替换参数的问题。 2
所以:
count([1,2,3])
= 0 if len([1,2,3]) == 0 else 1 + count([2,3])
= 1 + count([2,3])
= 1 + (0 if len([2,3]) == 0 else 1 + count([3]))
= 1 + (1 + count([3]))
= 1 + (1 + (0 if len([3]) == 0 else 1 + count([])))
= 1 + (1 + (1 + count([])))
= 1 + (1 + (1 + (0 if len([]) == 0 else 1 + count([])))))
= 1 + (1 + (1 + (0)))
= 1 + (1 + (1))
= 1 + (2)
= 3
sum([5,10,1])
= 0 if len([5,10,1]) == 0 else 5 + count([10,1])
= 5 + count([10,1])
= 5 + (0 if len([10,1]) == 0 else 10 + count([1]))
= 5 + (10 + count([3]))
= 5 + (10 + (0 if len([3]) == 0 else 1 + count([])))
= 5 + (10 + (1 + count([])))
= 5 + (10 + (1 + (0 if len([]) == 0 else ??? + count([])))))
= 5 + (10 + (1 + (0)))
= 5 + (10 + (1))
= 5 + (11)
= 16
此外,请注意上面的???
。 num[0]
为空时num
是什么?那会引发一个异常,但是,因为我们从不使用该分支,所以执行该操作并不重要。
1。它也无缘无故地制作了很多无用的列表副本,只是让作者假装他是使用Scheme而不是Python进行编程,但我们忽略了这一点。
2。他们不是,但是只要您不做作业或其他任何形式的变异,您实际上就无法分辨出区别。这就是为什么喜欢纯函数式语言(在其中您无法执行任务等)的人喜欢它们的原因。