Python: перевищено максимальну глибину рекурсії


85

У мене є такий код рекурсії, на кожному вузлі я викликаю запит sql, щоб отримати вузли, що належать батьківському вузлу.

ось помилка:

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

Метод, який я викликаю для отримання результатів 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();

Я насправді не маю жодних проблем із вищезазначеним методом, але я все одно ставлю це, щоб дати належний огляд питання.

Код рекурсії:

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

Виклик рекурсивної функції

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

Код для друку словника,

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

Якщо рекурсія занадто глибока, я повинен отримувати помилку, коли викликаю свою функцію рекурсії, але коли я отримую цю помилку, коли друкую словник.


8
Перепишіть його ітеративно, а не рекурсивно.
Сет Карнегі,

1
if first:Перевірка дублює for elem in first:. Якщо запит повертає порожній список результатів, то ітерація над ним просто, правильно не зробить нічого, як вам заманеться. Крім того, ви можете створити цей список простіше із розумінням списку (а ці крапки з комою непотрібні і взагалі вважаються потворними :))
Карл Кнехтель,

@KarlKnechtel вибачте з крапкою з комою, чи можете ви сказати, що я тільки заходжу в програмування на Python .... :)
add-

Не потрібно вибачатися, я все-таки не плачу вам, щоб ви це написали :) Сподіваюся, ви знайдете Python визвольним;)
Karl Knechtel

Відповіді:


162

Ви можете збільшити дозволену глибину стека - завдяки цьому будуть можливі більш глибокі рекурсивні виклики, наприклад:

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

... Але я б порадив спочатку спробувати оптимізувати ваш код, наприклад, використовуючи ітерацію замість рекурсії.


1
Я додав рядок замість 10000, я додав 30000, але в підсумку виявився Помилка сегментації (ядро скинуто) :(
add-half-colons

16
Є причина, чому вона встановлена ​​на 1000 ... Я вважаю, що Гвідо ван Россум щось про це сказав .
Лямбда-фея

3
Отже, аргумент Гвідо полягає в тому, що правильний виклик хвоста (1) забезпечує гірші сліди стека - на відміну від жодних кадрів, коли ви пишете його ітеративно? як це гірше? (2) Якщо ми подаруємо їм щось приємне, вони можуть почати на це покладатися. (3) Я не вірю в це, це пахне схемою. (4) Python погано розроблений, тому компілятор не може ефективно виявити, чи є щось викликом хвоста. Я здогадуюсь, з яким ми можемо домовитись?
Джон Клементс

1
@hajef По-третє, виклик хвоста, звичайно, не лише для списків; будь-яка деревоподібна структура виграє. Спробуйте здійснити обхід дерева без рекурсивних викликів у циклі; ви змотуєте ручне моделювання стека. Нарешті, ваш аргумент про те, що Python ніколи не розроблявся таким чином, безумовно, правда, але мало що переконує мене, що це божий дизайн.
Джон Клементс,

1
Те, що у ван Россума є бджола в капоті про рекурсію, не означає, що рекурсія замість ітерації не є "оптимальною": залежить від того, що ви оптимізуєте!
Gene Callahan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.