Python: se superó la profundidad máxima de recursividad

85

Tengo el siguiente código de recursividad, en cada nodo llamo a la consulta sql para que los nodos pertenezcan al nodo principal.

aquí está el error:

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 al que llamo para obtener resultados de 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();

En realidad, no tengo ningún problema con el método anterior, pero lo planteo de todos modos para brindar una descripción general adecuada de la pregunta.

Código de recursividad:

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

Llamar a la función 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 el diccionario,

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

Si la recursividad es demasiado profunda, debería recibir el error cuando llamo a mi función de recursividad, pero cuando obtengo este error cuando imprimo el diccionario.

añadir punto y coma
fuente
8
Vuelva a escribirlo de forma iterativa en lugar de recursiva.
Seth Carnegie
1
El if first:cheque es redundante con for elem in first:. Si la consulta devuelve una lista de resultados vacía, iterar sobre ella simplemente no hará nada correctamente, como desee. Además, puede crear esa lista de manera más simple con una lista de comprensión (y esos puntos y comas son innecesarios y generalmente se consideran feos :))
Karl Knechtel
@KarlKnechtel lo de los puntos y comas, se puede saber que estoy acaba de entrar en la programación Python .... :)
add-punto y coma
No hay necesidad de disculparse, no te pagaré por escribirlo después de todo :) Espero que encuentres Python liberador;)
Karl Knechtel

Respuestas:

162

Puede incrementar la profundidad de pila permitida; con esto, serán posibles llamadas recursivas más profundas, como esta:

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

... Pero le aconsejo que primero intente optimizar su código, por ejemplo, usando iteración en lugar de recursividad.

Óscar López
fuente
1
Agregué la línea en lugar de 10000, agregué 30000 pero terminé con una falla de segmentación (núcleo descargado) :(
agregar punto y coma
16
Hay una razón por la que está fijado en 1000 ... Creo que Guido van Rossum dijo algo sobre esto .
Lambda Fairy
3
Entonces, el argumento de Guido es que la llamada de cola adecuada (1) proporciona peores trazos de pila, en lugar de no tener ningún marco cuando lo escribe de forma iterativa. ¿cómo es eso peor? (2) Si les damos algo agradable, es posible que empiecen a confiar en ello. (3) No creo en eso, huele a Scheme. (4) Python está mal diseñado, por lo que un compilador no puede descubrir de manera eficiente si algo es una llamada de cola. ¿Supongo que podemos ponernos de acuerdo?
John Clements
1
@hajef En tercer lugar, el tail-call ciertamente no es solo para listas; cualquier estructura de árbol gana. Intente atravesar un árbol sin llamadas recursivas en un bucle; terminas modelando la pila a mano. Finalmente, su argumento de que Python nunca fue diseñado de esta manera es ciertamente cierto, pero hace poco para convencerme de que es un diseño divino.
John Clements
1
El hecho de que van Rossum tenga una abeja en su capó sobre la recursividad no significa que la recursividad en lugar de la iteración no sea "óptima": ¡depende de lo que esté optimizando!
Gene Callahan