Python - 在递归函数中使用共享变量

时间:2014-05-20 14:18:05

标签: python recursion global-variables return-value

我使用递归函数对Python中的列表进行排序,并且我希望在函数继续时跟踪排序/合并的数量。但是,当我在函数内部声明/初始化变量时,它会在函数的每次连续调用中成为局部变量。如果我在函数外声明变量,函数认为它不存在(即无法访问它)。如何在函数的不同调用之间共享此值?

我尝试使用" global"函数内部和外部的变量标签如下:

global invcount  ## I tried here, with and without the global tag

def inv_sort (listIn):
    global invcount   ## and here, with and without the global tag

    if (invcount == undefined):  ## can't figure this part out
        invcount = 0

    #do stuff

但我无法弄清楚如何检查全局变量的未定义状态,并在第一次递归调用时给它一个值(因为在所有连续的递归中它应该有一个值并被定义)。

我的第一个想法是从函数的每次调用中返回变量,但我无法弄清楚如何将两个对象传递出函数,我已经必须将列表传递给递归排序工作。我第二次尝试解决此问题涉及到我将变量invcount添加到列表中,我将其作为带有标识符的最后一个元素传递,例如"i27"。然后我可以检查最后一个元素中是否存在标识符(本例中为字母i),如果存在pop(),则在函数调用开始时将其关闭,并在递归期间重新添加它。在实践中,这变得非常复杂,虽然它最终可能起作用,但我想知道是否有更实际或更简单的解决方案。

有没有办法在不直接传递/返回变量的情况下共享变量?

4 个答案:

答案 0 :(得分:6)

你可以做几件事。举个例子,你应该修改它:

invcount = 0

def inv_sort (listIn):
    global invcount

    invcount += 1

    # do stuff

但是这种方法意味着您应该在每次调用invcount之前将inv_sort归零。 因此,最好将invcount作为结果的一部分返回。例如,使用这样的元组:

def inv_sort(listIn):

    #somewhere in your code recursive call
    recursive_result, recursive_invcount = inv_sort(argument)

    # this_call_invcount includes recursive_invcount
    return this_call_result, this_call_invcount   

答案 1 :(得分:5)

替代方案可能是使用默认参数,例如:

def inv_sort(listIn, invcount=0):
    ...
    invcount += 1
    ...
    listIn, invcount = inv_sort(listIn, invcount)        
    ...
    return listIn, invcount

这样做的缺点是你的电话会变得不那么整洁:

l, _ = inv_sort(l) # i.e. ignore the second returned parameter

但这确实意味着每次使用单个参数调用函数时invcount会自动重置(如果需要测试,还提供注入invcount值的机会:{{1 }})。

答案 2 :(得分:3)

在Python中没有“undefined”变量,你不需要它。

在函数外部,将变量设置为0.在循环内部,使用global关键字,然后递增。

invcount = 0
def inv_sort (listIn):
    global invcount

    ... do stuff ...

    invcount += 1

答案 3 :(得分:1)

假设您不需要知道函数内部的计数,我会使用装饰器函数来处理它:

import functools

def count_calls(f):
    @functools.wraps(f)
    def func(*args):
        func.count += 1
        return f(*args)
    func.count = 0
    return func

您现在可以装饰递归函数:

@count_calls
def inv_sort(...):
    ...

在调用之前或之后检查或重置count

inv_sort.count = 0
l = inv_sort(l)
print(inv_sort.count)