每次调用递归函数都会创建一个新框架吗?

时间:2017-07-31 23:05:39

标签: python function recursion

我试图解决一个问题,包括找到具有多个深度级别的列表的最大值。 我尝试了几个想法,但没有运气。 所以我在网上发现了这个。我自己实际上已经有了这个想法,但是我放弃了它而没有测试它,因为我之后会提到它。

def get_max(my_list):
    m = None
    for item in my_list:
        if isinstance(item, (list, tuple)):
            item = get_max(item)
        if not m or m < item:
            m = item
    return m

示例运行:

>>> get_max(((10, (1,2), [[1],[9]])))    
>>> 10

所以我放弃了这个想法,因为我认为如果在每个递归步骤中m的值被重置为None,它就不会找到我需要的最大值。 我在Python Tutor中运行它,但我仍然不明白m将如何记住值10,因为它已经多次重置为None。

有人可以向我解释一下吗?

每个递归步骤都会以某种方式创建一个新框架吗?

3 个答案:

答案 0 :(得分:2)

  

每个递归步骤都会以某种方式创建一个新框架吗?

是的,每次递归调用max都会创建一个新帧。这有实际的后果(如:如果递归深度非常大或可能无限,会发生什么?默认情况下,CPython将最大递归深度设置为1000.另请参阅:What is the maximum recursion depth in Python, and how to increase it?

m 是一个局部变量。因此,max的第一个父调用中的 m max的子调用中分配的 m 不同。 “记住”是因为孩子 m 作为返回给父母。

答案 1 :(得分:1)

正如其他人提到的,你的递归是正确的,因为get_max的每个调用都有自己的局部变量,my_listmitem

FWIW,这是您的代码的一个小变化。它应该更有效率,因为它使用内置的max而不是使用Python循环计算最大值(尽管我们仍然在循环生成该生成器表达式)。它还消除了m = None的需要,因此每次更新时都需要测试m是否已初始化。

def get_max(obj):
    is_seq = isinstance(obj, (list, tuple)) 
    return max(get_max(u) for u in obj) if is_seq else obj

data = (10, (1, 2), [[1], [9], [4, 7]])
print(get_max(data))

<强>输出

10

我们也可以使用map而不是max调用中的生成器表达式来编写它。

def get_max(obj):
    is_seq = isinstance(obj, (list, tuple)) 
    return max(map(get_max, obj)) if is_seq else obj

答案 2 :(得分:0)

递归调用似乎是针对当前列表中的列表。因此,此函数的基本案例是仅包含非列表项的列表。换句话说,当找到新列表时,只有一个新的函数调用,因此只有m变量的实例。

get_max()的每次调用都有自己的变量m,该变量将在该级别及下保持最大值