Python: Đã vượt quá độ sâu đệ quy tối đa


85

Tôi có đoạn mã đệ quy sau, tại mỗi nút tôi gọi truy vấn sql để lấy các nút thuộc về nút cha.

đây là lỗi:

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

Phương pháp tôi gọi để nhận kết quả 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();

Tôi thực sự không có bất kỳ vấn đề nào với phương pháp trên nhưng tôi vẫn nói nó để cung cấp tổng quan thích hợp về câu hỏi.

Mã đệ quy:

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

Gọi hàm đệ quy

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

Mã để in từ điển,

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

Nếu đệ quy quá sâu, tôi sẽ gặp lỗi khi gọi hàm đệ quy, nhưng khi in từ điển tôi gặp lỗi này.


8
Viết lại nó lặp đi lặp lại thay vì đệ quy.
Seth Carnegie

1
Các if first:kiểm tra là không cần thiết với for elem in first:. Nếu truy vấn trả về một danh sách kết quả trống, thì việc lặp lại nó sẽ đơn giản, chính xác không làm gì cả, như bạn mong muốn. Ngoài ra, bạn có thể tạo danh sách đó đơn giản hơn với một sự hiểu biết danh sách (và những dấu chấm phẩy là không cần thiết và thường được coi xấu xí :))
Karl Knechtel

@KarlKnechtel xin lỗi về dấu chấm phẩy, bạn có thể nói tôi chỉ đi vào lập trình Python .... :)
add-phẩy

Không cần phải xin lỗi, tôi không trả tiền cho bạn để viết nó sau khi tất cả :) Tôi hy vọng bạn tìm thấy Python giải phóng;)
Karl Knechtel

Câu trả lời:


162

Bạn có thể tăng độ sâu ngăn xếp được phép - với điều này, sẽ có thể thực hiện các lệnh gọi đệ quy sâu hơn, như thế này:

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

... Nhưng tôi khuyên bạn trước tiên hãy thử tối ưu hóa mã của mình, chẳng hạn như sử dụng phép lặp thay vì đệ quy.


1
Tôi được thêm vào dòng thay vì 10000 i thêm 30000 nhưng tôi đã kết thúc Segmentation Fault (core dumped) :(
add-dấu chấm phẩy

16
Có một lý do tại sao nó được đặt ở mức 1000 ... Tôi tin rằng Guido van Rossum đã nói điều gì đó về điều này .
Lambda Fairy

3
Vì vậy, lập luận của Guido là việc gọi đuôi thích hợp (1) cung cấp dấu vết ngăn xếp tồi tệ hơn --- trái ngược với không có khung nào cả khi bạn viết nó lặp đi lặp lại? làm thế nào là tồi tệ hơn? (2) Nếu chúng tôi đưa cho họ thứ gì đó tốt đẹp, họ có thể bắt đầu dựa vào nó. (3) Tôi không tin vào nó, nó có mùi giống như Đề án. (4) Python được thiết kế kém, do đó trình biên dịch không thể phát hiện ra một thứ gì đó có phải là lệnh gọi đuôi một cách hiệu quả hay không. Tôi đoán rằng một trong những chúng ta có thể đồng ý?
John Clements

1
@hajef Thứ ba, gọi đuôi chắc chắn không chỉ dành cho danh sách; cấu trúc cây nào thắng. Hãy thử duyệt qua một cây mà không cần gọi đệ quy trong một vòng lặp; bạn tạo mô hình ngăn xếp bằng tay. Cuối cùng, lập luận của bạn rằng Python không bao giờ được thiết kế theo cách này chắc chắn đúng, nhưng không thuyết phục được tôi rằng đó là một thiết kế thần thánh.
John Clements

1
Chỉ vì van Rossum có một con ong trong nắp ca-pô của anh ấy về đệ quy không có nghĩa là đệ quy thay vì lặp lại không phải là "tối ưu": phụ thuộc vào những gì bạn đang tối ưu hóa!
Gene Callahan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.