Python: Maximale Rekursionstiefe überschritten

85

Ich habe den folgenden Rekursionscode. An jedem Knoten rufe ich eine SQL-Abfrage auf, um festzustellen, ob die Knoten zum übergeordneten Knoten gehören.

Hier ist der Fehler:

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

Methode, die ich aufrufe, um SQL-Ergebnisse zu erhalten:

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();

Ich habe eigentlich kein Problem mit der obigen Methode, aber ich habe es trotzdem ausgedrückt, um einen angemessenen Überblick über die Frage zu geben.

Rekursionscode:

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

Aufruf der rekursiven Funktion

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();

Code zum Drucken des Wörterbuchs,

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

Wenn die Rekursion zu tief ist, sollte der Fehler angezeigt werden, wenn ich meine Rekursionsfunktion aufrufe, aber wenn ich diesen Fehler erhalte, wenn ich das Wörterbuch drucke.

Add-Semikolons
quelle
8
Schreiben Sie es iterativ statt rekursiv um.
Seth Carnegie
1
Die if first:Prüfung ist überflüssig mit for elem in first:. Wenn die Abfrage eine leere Ergebnisliste zurückgibt, führt das Durchlaufen der Abfrage einfach korrekt zu nichts, wie Sie es wünschen. Sie können diese Liste auch einfacher mit einem Listenverständnis erstellen (und diese Semikolons sind unnötig und werden allgemein als hässlich angesehen :))
Karl Knechtel
@KarlKnechtel Entschuldigung für die Semikolons, können Sie sagen, ich bin gerade in der Python-Programmierung .... :)
Add-Semi-Colons
Keine Notwendigkeit, sich zu entschuldigen, ich bezahle dich doch nicht dafür, es zu schreiben :) Ich hoffe, du findest Python befreiend;)
Karl Knechtel

Antworten:

160

Sie können die zulässige Stapeltiefe erhöhen. Auf diese Weise sind tiefere rekursive Aufrufe wie folgt möglich:

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

... Aber ich würde Ihnen raten, zuerst zu versuchen, Ihren Code zu optimieren, indem Sie beispielsweise Iteration anstelle von Rekursion verwenden.

Óscar López
quelle
1
Ich habe die Zeile anstelle von 10000 hinzugefügt. Ich habe 30000 hinzugefügt, aber am Ende habe ich einen Segmentierungsfehler (Core Dump) festgestellt :(
Add-Semi-Colons
15
Es gibt einen Grund, warum es auf 1000 eingestellt ist ... Ich glaube, Guido van Rossum hat etwas darüber gesagt .
Lambda Fairy
3
Guidos Argument ist also, dass der richtige Tail-Aufruf (1) schlechtere Stack-Traces liefert - im Gegensatz zu überhaupt keinen Frames, wenn Sie ihn iterativ schreiben? wie ist das schlimmer (2) Wenn wir ihnen etwas Nettes geben, können sie sich darauf verlassen. (3) Ich glaube nicht daran, es riecht nach Schema. (4) Python ist schlecht entworfen, so dass ein Compiler nicht effizient erkennen kann, ob es sich um einen Tail-Aufruf handelt. Ich denke, dass wir uns darauf einigen können?
John Clements
1
@hajef Drittens ist Tail-Calling sicherlich nicht nur für Listen; Jede Baumstruktur gewinnt. Versuchen Sie, einen Baum ohne rekursive Aufrufe in einer Schleife zu durchlaufen. Sie modellieren den Stapel von Hand. Schließlich ist Ihr Argument, dass Python nie so entworfen wurde, sicherlich richtig, aber es überzeugt mich wenig davon, dass es ein göttliches Design ist.
John Clements
1
Nur weil van Rossum eine Biene über Rekursion in seiner Haube hat, heißt das nicht, dass Rekursion statt Iteration nicht "optimal" ist: hängt davon ab, was Sie optimieren!
Gene Callahan