Python递归函数错误:“超出最大递归深度”

时间:2010-03-08 13:10:13

标签: python recursion

我使用以下代码解决了项目Euler的问题10,该代码通过强力实施:

def isPrime(n):

    for x in range(2, int(n**0.5)+1):
        if n % x == 0:
            return False
    return True


def primeList(n):

    primes = []

    for i in range(2,n):
        if isPrime(i):
            primes.append(i)

    return primes


def sumPrimes(primelist):
    prime_sum = sum(primelist)
    return prime_sum


print (sumPrimes(primeList(2000000)))

这三个功能的工作原理如下:

  1. isPrime 检查数字是否为素数;
  2. primeList 返回一个列表,其中包含一组限制为“n”的特定范围的素数,并且;
  3. sumPrimes 总结列表中所有数字的值。 (不需要最后一个功能,但我喜欢它的清晰度,特别是像我这样的初学者。)
  4. 然后我编写了一个新函数 primeListRec ,它与 primeList 完全相同,以帮助我更好地理解递归:

    def primeListRec(i, n):
        primes = []
        #print i
    
    
        if (i != n):
            primes.extend(primeListRec(i+1,n))
    
        if (isPrime(i)):
            primes.append(i)
            return primes
    
    
        return primes
    

    上述递归函数有效,但仅适用于非常小的值,如'500'。当我输入'1000'时,该功能导致我的程序崩溃。当我输入类似'2000'的值时,Python给了我这个:

    RuntimeError:超出最大递归深度

    我的递归函数出了什么问题?或者是否有一些特定的方法来避免递归限制?

5 个答案:

答案 0 :(得分:28)

递归不是在Python中执行操作的最惯用的方式,因为它没有tail recursion优化,因此使用递归作为迭代的替代是不切实际的(即使在您的示例中函数不是尾递归,无论如何都无济于事。基本上,这意味着如果你希望你的输入很大,你就不应该把它用于复杂度大于线性的东西(对于那些具有对数递归深度的事情来说,这仍然是可以的,比如像QuickSort那样划分和征服算法)。

如果您想尝试这种方法,请使用更适合进行函数式编程的语言,如Lisp,Scheme,Haskell,OCaml等;或尝试使用Stackless Python,它在堆栈使用方面有更广泛的限制,并且还具有尾递归优化: - )

顺便说一下,函数的尾递归等价物可能是:

def primeList(n, i=2, acc=None):
    return i > n and (acc or []) or primeList(n, i+1, (acc or []) + (isPrime(i) and [i] or []))

另一个“顺便说一句”,你不应该构建一个列表,如果你只是为了将值加起来......解决Project Euler第10个问题的Pythonic方法是:

print sum(n for n in xrange(2, 2000001) if all(n % i for i in xrange(2, int(n**0.5)+1)))

(好吧,也许在不同的行中拆分它会更加Pythonic,但我喜欢一个衬里^ _ ^)

答案 1 :(得分:1)

嗯,我不是python专家,但我认为你已达到stack限制。这就是递归的问题,当你不必递归很多次但当递归次数达到相当大的时候没有好处时,这很好。

理想的替代方法是重写算法以改为使用迭代。

修改:实际上,通过更改sys.getrecursionlimit,您可以更仔细地查看特定错误。那只会带你到目前为止。最终你会得到一个stackoverflow异常,它让我回到原点。

答案 2 :(得分:1)

就像已经说过的那样,在无法处理深层堆栈的语言中,采用迭代方法会更好。特别是在您的情况下,最好更改使用的算法。我建议使用Sieve of Eratosthenes来查找素数列表。它会比你当前的程序快得多。

答案 3 :(得分:0)

您正在迭代n个数字并在每个步骤中递归。因此,Python的递归限制定义了您的最大输入数。这显然是不可取的。特别是因为欧拉问题通常涉及相当大的数字。

答案 4 :(得分:-2)

你可以用脏的方式做到这一点:

try: function() except: function()