Python 如何在不靠近计算机的情况下理解函数的功能?

Python 如何在不靠近计算机的情况下理解函数的功能?,python,recursion,Python,Recursion,我在准备考试,遇到了这个问题 def子集(lst): 如果len(lst)==0: 收益率[] 其他: 对于尾随子集(lst[1:]): 屈服尾 收益率[lst[0]]+尾部 打印(列表(子集([1,5,3]))我认为当你完全能够自己编写代码时,你就可以通过考试了。试着自己编写代码,在函数中输入“prints”,看看到底发生了什么 我认为当你完全能够自己编写代码时,你就可以通过考试了。试着自己编写代码,在函数中输入“prints”,看看到底发生了什么 程序生成所有子集。这是因为在for循环中,

我在准备考试,遇到了这个问题

def子集(lst):
如果len(lst)==0:
收益率[]
其他:
对于尾随子集(lst[1:]):
屈服尾
收益率[lst[0]]+尾部

打印(列表(子集([1,5,3]))
我认为当你完全能够自己编写代码时,你就可以通过考试了。试着自己编写代码,在函数中输入“prints”,看看到底发生了什么

我认为当你完全能够自己编写代码时,你就可以通过考试了。试着自己编写代码,在函数中输入“prints”,看看到底发生了什么

程序生成所有子集。这是因为在
for
循环中,它“发射”尾部的所有
子集,并且有一个版本带有“head”而没有“head”

为了分析它的功能性,我会进行反向分析。很明显,对于每个递归调用,我们都会删除一个元素:可以说是“head”。当没有head时,递归就会结束:在这种情况下,我们会发出空列表

现在我们向上移动一个级别:如果我们向它提供一个包含一个元素的列表呢?递归调用显然会发出空列表(正如我们刚才演示的),这里我们发出两个版本:一个有头,一个没有头。因此,如果我们向它提供
[a]
,我们将得到两个版本:
[]
[a]

现在我们可以归纳地说,当我们得到一个列表
L=[x2,x3,x4,…,xn]
的所有子集
S
的列表时,那么
L'=[x1,x2,x3,…,xn]
的子集列表是
L
的子集
S
的列表,以及我们添加
x1
的子集列表

关于事物的顺序,因为在每个递归的
for
循环中,我们首先
产生一个没有“head”的版本“,显然将首先生成空列表。下一步,因为我们在头脑中,是有真实头脑的版本。下一个元素是第二个头部所在的元素,没有其他元素。因此,它就像二进制计数。对于列表
[x1,x2,x3,x4]

binary  result
0000    []
0001    [x1]
0010    [x2]
0011    [x1,x2]
0100    [x3]
0101    [x1,x3]
0110    [x2,x3]
0111    [x1,x2,x3]
1000    [x4]
1001    [x1,x4]
1010    [x2,x4]
1011    [x1,x2,x4]
1100    [x3,x4]
1101    [x1,x3,x4]
1110    [x2,x3,x4]
1111    [x1,x2,x3,x4]
如果您想要相反的方式,您应该在一个单独的
for
循环中不使用和使用:

def subsets(lst):
   if len(lst)==0:
       yield []
   else:
       for tail in subsets(lst[1:]):
           yield tail
       for tail in subsets(lst[1:]):
           yield [lst[0]]+tail
def子集(lst):
如果len(lst)==0:
收益率[]
其他:
对于尾随子集(lst[1:]):
屈服尾
对于尾随子集(lst[1:]):

yield[lst[0]]+tail
程序生成所有子集。这是因为在
for
循环中,它“发射”尾部的所有
子集,并且有一个版本带有“head”而没有“head”

为了分析它的功能性,我会进行反向分析。很明显,对于每个递归调用,我们都会删除一个元素:可以说是“head”。当没有head时,递归就会结束:在这种情况下,我们会发出空列表

现在我们向上移动一个级别:如果我们向它提供一个包含一个元素的列表呢?递归调用显然会发出空列表(正如我们刚才演示的),这里我们发出两个版本:一个有头,一个没有头。因此,如果我们向它提供
[a]
,我们将得到两个版本:
[]
[a]

现在我们可以归纳地说,当我们得到一个列表
L=[x2,x3,x4,…,xn]
的所有子集
S
的列表时,那么
L'=[x1,x2,x3,…,xn]
的子集列表是
L
的子集
S
的列表,以及我们添加
x1
的子集列表

关于事物的顺序,因为在每个递归的
for
循环中,我们首先
产生一个没有“head”的版本“,显然将首先生成空列表。下一步,因为我们在头脑中,是有真实头脑的版本。下一个元素是第二个头部所在的元素,没有其他元素。因此,它就像二进制计数。对于列表
[x1,x2,x3,x4]

binary  result
0000    []
0001    [x1]
0010    [x2]
0011    [x1,x2]
0100    [x3]
0101    [x1,x3]
0110    [x2,x3]
0111    [x1,x2,x3]
1000    [x4]
1001    [x1,x4]
1010    [x2,x4]
1011    [x1,x2,x4]
1100    [x3,x4]
1101    [x1,x3,x4]
1110    [x2,x3,x4]
1111    [x1,x2,x3,x4]
如果您想要相反的方式,您应该在一个单独的
for
循环中不使用和使用:

def subsets(lst):
   if len(lst)==0:
       yield []
   else:
       for tail in subsets(lst[1:]):
           yield tail
       for tail in subsets(lst[1:]):
           yield [lst[0]]+tail
def子集(lst):
如果len(lst)==0:
收益率[]
其他:
对于尾随子集(lst[1:]):
屈服尾
对于尾随子集(lst[1:]):

yield[lst[0]]+tail
首先,我确定函数在每次迭代中需要的所有局部变量。这包括参数、本地创建的变量,以及(偶尔)递归调用中出现的临时值

对于这个函数,我得到

return bookmark
lst
tail
temp for subsets(lst[1:])
您的两个返回点是第9行(主)和第5行(递归)

现在开始用铅笔和纸手动模拟最初的呼叫。您所做的大部分工作是维护调用堆栈存储和值。我们从主程序开始:

list(subsets([1,5,3]))
每次调用例程时,都会将这四个变量“推”到堆栈上(值或保留存储;只需将其设置为一个漂亮的框)。每次你回来,“砰”的一声把它们放回去(用你的橡皮擦)

现在打电话。堆栈现在如下所示:

return: line 9
lst:    [1, 5, 3]
tail:   None
temp:   None
--------------------
list(subsets([1,5,3]))
这将使您处于函数的顶部。一行一行地工作。len(lst)不是0,因此跳转到其他。您立即点击表达式子集(lst[1:]),它将在返回时为当前堆栈块上的tail提供一系列值。现在,将下一个调用推送到堆栈上:

return: line 9
lst:    [5, 3]
tail:   None
temp:   None
--------------------
return: line 9
lst:    [1, 5, 3]
tail:   None
temp:   None
--------------------
list(subsets([1,5,3]))
同样,len(lst)不是0,我们点击else。将该调用推到堆栈上。事实上,当我们这样做的时候,让我们先跳过一个电话,然后再推一个:

return: line 9
lst:    []
tail:   None
temp:   None
--------------------
return: line 9
lst:    [3]
tail:   None
temp:   None
--------------------
return: line 9
lst:    [5, 3]
tail:   None
temp:   None
--------------------
return: line 9
lst:    [1, 5, 3]
tail:   None
temp:   None
--------------------
list(subsets([1,5,3]))
注意:在下面的处理过程中,我选择了一条捷径,将生成器视为返回列表,而不是生成单个结果。这是为了让答案足够简短,以便理解。事实上,运行时系统一直在以一个新的速度反弹
[]
[5]
[3]
[5, 3]
return: line 9
lst:    [1, 5, 3]
tail:   None
temp:   [[], [5], [3], [5, 3]]
--------------------
list(subsets([1,5,3]))
[[], [1], [5], [1, 5], [3], [1, 3], [5, 3], [1, 5, 3]]