Python: profundidade máxima de recursão excedida

85

Eu tenho o seguinte código de recursão, em cada nó eu chamo de consulta sql para fazer com que os nós pertençam ao nó pai.

aqui está o erro:

Exception RuntimeError: 'maximum recursion depth exceeded' in <bound method DictCursor.__del__ of <MySQLdb.cursors.DictCursor object at 0x879768c>> ignored

RuntimeError: maximum recursion depth exceeded while calling a Python object
Exception AttributeError: "'DictCursor' object has no attribute 'connection'" in <bound method DictCursor.__del__ of <MySQLdb.cursors.DictCursor object at 0x879776c>> ignored

Método que chamo para obter resultados sql:

def returnCategoryQuery(query, variables={}):
    cursor = db.cursor(cursors.DictCursor);
    catResults = [];
    try:
        cursor.execute(query, variables);
        for categoryRow in cursor.fetchall():
            catResults.append(categoryRow['cl_to']);
        return catResults;
    except Exception, e:
        traceback.print_exc();

Na verdade, não tenho nenhum problema com o método acima, mas coloquei-o de qualquer maneira para dar uma visão geral adequada da questão.

Código de recursão:

def leaves(first, path=[]):
    if first:
        for elem in first:
            if elem.lower() != 'someString'.lower():
                if elem not in path:
                    queryVariable = {'title': elem}
                    for sublist in leaves(returnCategoryQuery(categoryQuery, variables=queryVariable)):
                        path.append(sublist)
                        yield sublist
                    yield elem

Chamando a função recursiva

for key, value in idTitleDictionary.iteritems():
    for startCategory in value[0]:
        print startCategory + " ==== Start Category";
        categoryResults = [];
        try:
            categoryRow = "";
            baseCategoryTree[startCategory] = [];
            #print categoryQuery % {'title': startCategory};
            cursor.execute(categoryQuery, {'title': startCategory});
            done = False;
            while not done:
                categoryRow = cursor.fetchone();
                if not categoryRow:
                    done = True;
                    continue;
                rowValue = categoryRow['cl_to'];
                categoryResults.append(rowValue);
        except Exception, e:
            traceback.print_exc();
        try:
            print "Printing depth " + str(depth);
            baseCategoryTree[startCategory].append(leaves(categoryResults))
        except Exception, e:
            traceback.print_exc();

Código para imprimir o dicionário,

print "---Printing-------"
for key, value in baseCategoryTree.iteritems():
    print key,
    for elem in value[0]:
        print elem + ',';
    raw_input("Press Enter to continue...")
    print

Se a recursão for muito profunda, devo receber o erro ao chamar minha função de recursão, mas quando recebo esse erro ao imprimir o dicionário.

adicionar ponto e vírgula
fonte
8
Reescreva-o iterativamente em vez de recursivamente.
Seth Carnegie
1
A if first:verificação é redundante com for elem in first:. Se a consulta retornar uma lista de resultados vazia, iterar sobre ela simplesmente não fará nada corretamente, como você deseja. Além disso, você pode criar essa lista de forma mais simples com uma compreensão de lista (e esses pontos-e-vírgulas são desnecessários e geralmente considerados feios :))
Karl Knechtel
@KarlKnechtel, desculpe pelos pontos-e-vírgulas, você pode dizer que estou apenas começando na programação Python ... :)
add-ponto-e-vírgulas
Não há necessidade de se desculpar, eu não estou pagando para você escrever isso, afinal :) Espero que você ache o Python libertador;)
Karl Knechtel

Respostas:

162

Você pode incrementar a profundidade de pilha permitida - com isso, chamadas recursivas mais profundas serão possíveis, como este:

import sys
sys.setrecursionlimit(10000) # 10000 is an example, try with different values

... Mas eu aconselho você a primeiro tentar otimizar seu código, por exemplo, usando iteração em vez de recursão.

Óscar López
fonte
1
Eu adicionei a linha em vez de 10000, eu adicionei 30000, mas acabei com a falha de segmentação (core despejado) :(
add-ponto-e-vírgulas
16
Há uma razão pela qual está fixado em 1000 ... Eu acredito que Guido van Rossum disse algo sobre isso .
Lambda Fairy
3
Portanto, o argumento de Guido é que a chamada de cauda adequada (1) fornece rastreamentos de pilha piores - em oposição a nenhum quadro quando você escreve iterativamente? como isso é pior? (2) Se dermos a eles algo bom, eles podem começar a confiar nisso. (3) Não acredito nisso, cheira a Scheme. (4) Python é mal projetado, de forma que um compilador não pode descobrir com eficiência se algo é uma chamada final. Acho que podemos concordar com isso?
John Clements,
1
@hajef Terceiro, chamar de atalho certamente não é apenas para listas; qualquer estrutura de árvore ganha. Tente percorrer uma árvore sem chamadas recursivas em um loop; você acaba modelando a pilha manualmente. Finalmente, seu argumento de que Python nunca foi projetado dessa maneira é certamente verdadeiro, mas faz pouco para me convencer de que é um design divino.
John Clements
1
Só porque van Rossum tem uma abelha em seu chapéu sobre recursão não significa que recursão em vez de iteração não é "ideal": depende do que você está otimizando!
Gene Callahan