Python: เกินความลึกของการเรียกซ้ำสูงสุด


86

ฉันมีรหัสการเรียกซ้ำต่อไปนี้ในแต่ละโหนดฉันเรียกแบบสอบถาม 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
เขียนซ้ำซ้ำ ๆ แทนที่จะเขียนซ้ำ
Seth Carnegie

1
กาซ้ำซ้อนกับif first: for elem in first:หากแบบสอบถามส่งคืนรายการผลลัพธ์ที่ว่างเปล่าการทำซ้ำอีกครั้งจะทำอะไรได้อย่างถูกต้องตามที่คุณต้องการ นอกจากนี้คุณสามารถสร้างรายการนั้นได้ง่ายขึ้นด้วยการทำความเข้าใจรายการ (และอัฒภาคเหล่านั้นไม่จำเป็นและโดยทั่วไปถือว่าน่าเกลียด :))
Karl Knechtel

@KarlKnechtel ขอโทษเกี่ยวกับอัฒภาคคุณบอกได้ไหมว่าฉันเพิ่งเข้าสู่การเขียนโปรแกรม Python .... :)
เพิ่มกึ่งโคลอน

ไม่ต้องขอโทษฉันไม่ได้จ่ายเงินให้คุณเพื่อเขียนมัน :) ฉันหวังว่าคุณจะพบ Python ปลดปล่อย;)
Karl Knechtel

คำตอบ:


167

คุณสามารถเพิ่มความลึกของสแต็กที่อนุญาต - ด้วยสิ่งนี้การเรียกซ้ำที่ลึกขึ้นจะเป็นไปได้เช่นนี้:

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

... แต่ฉันขอแนะนำให้คุณลองเพิ่มประสิทธิภาพโค้ดของคุณก่อนเช่นใช้การวนซ้ำแทนการเรียกซ้ำ


1
ฉันเพิ่มบรรทัดแทน 10,000 ฉันเพิ่ม 30000 แต่ฉันลงเอยด้วย Segmentation Fault (แกนถูกทิ้ง) :(
เพิ่มกึ่งโคลอน

16
มีเหตุผลที่ว่าทำไมมันตั้งอยู่ที่ 1000 คือ ... ผมเชื่อว่ากุยรถตู้ซัมพูดอะไรบางอย่างเกี่ยวกับเรื่องนี้
Lambda Fairy

3
ดังนั้นข้อโต้แย้งของ Guido คือการเรียกหางที่เหมาะสม (1) ให้การติดตามสแต็กที่แย่กว่า - เมื่อเทียบกับการไม่มีเฟรมเลยเมื่อคุณเขียนซ้ำ? มันแย่ลงอย่างไร? (2) หากเราให้สิ่งที่ดีแก่พวกเขาพวกเขาอาจเริ่มพึ่งพามัน (3) ฉันไม่เชื่อในเรื่องนี้มันมีกลิ่นเหมือน Scheme (4) Python ได้รับการออกแบบมาไม่ดีดังนั้นคอมไพเลอร์จึงไม่สามารถค้นพบได้อย่างมีประสิทธิภาพว่ามีบางสิ่งที่เรียกว่า tail call หรือไม่ ฉันเดาว่าเราสามารถเห็นด้วย?
John Clements

1
@hajef ประการที่สามการโทรหางไม่ได้มีไว้สำหรับรายการเท่านั้น โครงสร้างต้นไม้ใด ๆ ชนะ ลองสำรวจต้นไม้โดยไม่มีการเรียกซ้ำในวง คุณไขลานการสร้างแบบจำลองสแต็กด้วยมือ ในที่สุดข้อโต้แย้งของคุณที่ว่า Python ไม่เคยออกแบบด้วยวิธีนี้เป็นความจริงอย่างแน่นอน แต่มีเพียงเล็กน้อยที่จะทำให้ฉันเชื่อว่าเป็นการออกแบบของพระเจ้า
John Clements

1
เพียงเพราะ Van Rossum มีผึ้งอยู่ในฝากระโปรงของเขาเกี่ยวกับการเรียกซ้ำไม่ได้หมายความว่าการเรียกซ้ำแทนที่จะเป็นการทำซ้ำนั้นไม่ "เหมาะสมที่สุด": ขึ้นอยู่กับสิ่งที่คุณกำลังเพิ่มประสิทธิภาพ!
Gene Callahan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.