Python递归函数错误:";超过最大递归深度;

Python递归函数错误:";超过最大递归深度;,python,recursion,Python,Recursion,我用以下代码解决了ProjectEuler的问题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):

我用以下代码解决了ProjectEuler的问题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)))
这三个功能的工作原理如下:

  • isPrime检查一个数字是否为素数
  • 素数列表返回一个列表,该列表包含特定范围内的一组素数,限制为“n”,并且
  • sumPrimes对列表中所有数字的值求和。(最后一个函数是不需要的,但我喜欢它的清晰性,特别是对于像我这样的初学者。)
  • 然后我编写了一个新函数,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给了我:

    运行时错误:超过最大递归深度


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

    我不是python专家,但我想你已经达到极限了。这就是递归的问题,当你不需要递归很多次的时候,它是很好的,但是当递归的数量变得相当大的时候,它就不好了

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


    编辑:实际上,仔细查看您的特定错误后,您可以通过更改来克服它。不过这只会让你走这么远。最终你会得到一个stackoverflow异常,这让我回到了我最初的观点。

    递归不是Python中最惯用的方法,因为它没有优化,因此使用递归代替迭代是不切实际的(即使在您的示例中,函数不是尾部递归的,这也不会有任何帮助)。基本上,这意味着您不应该将其用于复杂度大于线性的事情,如果您希望输入较大,(仍然可以做对数递归深度的事情,比如像快速排序的分治算法)

    如果您想尝试这种方法,请使用一种更适合于函数式编程的语言,如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第十个问题的python方法是:

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

    (好吧,也许把它分成几行会更像蟒蛇,但我喜欢一行)

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

    正如前面所说,在无法处理深堆栈的语言中,最好进行迭代e方法。特别是在您的情况下,最好更改使用的算法。我建议使用查找素数列表。它将比您当前的程序快得多。

    您可以用肮脏的方式执行:

    try: function() except: function()
    

    我不太明白。第一个算法,即“primeList”,不是已经基于迭代了吗?另外,问题使用了200万的值;这是一个不合理的限制吗?确实是。但是你问为什么你的第二个primeListRec不起作用。它是递归的,因此递归深度超过了错误。那么递归到底是不是一个viPython中的可行方法?大多数Python程序员都会避免吗?(例如,它是否非Python?)在这种情况下,尾部递归没有帮助,因为递归调用不是函数中的最后一个操作。当迭代版本无论如何都需要堆栈时(例如遍历树、生成置换等),这是一种可行的方法递归深度被限制在一个合理的范围内。在这种情况下,你试图以一种人工的方式使用递归,因为它显然是你所需要的循环。我不知道什么是“尾部递归”是的,所以我点击了谷歌,发现还有其他类型的递归。这对我来说是新的;我认为只有一种递归。谢谢!但我仍然必须问:如果有涉及大量数字的递归,什么样的Pythonic方法才能处理它?@user283169我想说的正是我所说的:递归不应该被滥用Python。如果您需要它,因为您的问题本质上是递归的,请使用它,但不要尝试用递归替换迭代,因为这不是它的使用方式。所以我必须始终坚持通过for/while循环手动迭代来处理大数目的问题吗?是的,我认为是这样……但不是完全确定。规则可能有例外,但我可以我一定会寻找你提到的例外情况。谢谢事实上,我的程序很慢。花了一分钟多的时间才完成,这打破了Project Euler的“一分钟规则”。我刚刚研究了埃拉托什尼方法的筛子,它很吸引人。我会尽我最大的努力学习它。谢谢你的建议。好的,我收回你的建议