ทำไมตัววนซ้ำใน Python จึงทำให้เกิดข้อยกเว้น?


48

นี่คือไวยากรณ์สำหรับตัววนซ้ำใน Java (ค่อนข้างคล้ายไวยากรณ์ใน C #):

Iterator it = sequence.iterator();

while (it.hasNext()) {
    System.out.println(it.next());
}

ซึ่งทำให้รู้สึก นี่คือไวยากรณ์ที่เทียบเท่าใน Python:

it = iter(sequence)
while True:
    try:
        value = it.next() 
    except StopIteration:
        break
    print(value)

ฉันคิดว่ามีการใช้ข้อยกเว้นในกรณีพิเศษเท่านั้น

ทำไมไพ ธ อนใช้ข้อยกเว้นเพื่อหยุดย้ำ?


2

คำตอบ:


50

มีวิธี Pythonic มากในการเขียนนิพจน์นั้นโดยไม่ต้องเขียนบล็อกแบบลองยกเว้นสำหรับ a StopIteration:

# some_iterable is some collection that can be iterated over
# e.g., a list, sequence, dict, set, itertools.combination(...)

for value in some_iterable:
    print(value)

คุณสามารถอ่าน PEP ที่เกี่ยวข้อง234 255หากคุณต้องการทราบเพิ่มเติมว่าทำไมStopIterationถูกนำมาใช้และเหตุผลเบื้องหลังตัวทำซ้ำ

หลักการทั่วไปในภาษาไพ ธ อนคือการมีวิธีหนึ่งในการทำบางสิ่ง (ดูimport this) และโดยเฉพาะอย่างยิ่งความสวยงามชัดเจนอ่านง่ายและเรียบง่ายซึ่งวิธีการไพ ธ อนสอดคล้อง รหัสเทียบเท่าของคุณมีความจำเป็นเนื่องจากไพ ธ อนไม่ได้ให้hasNextฟังก์ชันตัววนซ้ำแก่สมาชิก เลือกให้คนอื่นวนซ้ำตัววนซ้ำโดยตรง (และถ้าคุณต้องการทำอย่างอื่นเพื่อลองอ่านและจับข้อยกเว้น)

การจับStopIterationข้อยกเว้นโดยอัตโนมัติในตอนท้ายของตัววนซ้ำนั้นเหมาะสมและเป็นอะนาล็อกของการEOFErrorยกหากคุณอ่านไฟล์ในตอนท้าย


6
วิธีการ "Pythonic" แน่นอนว่าดูเหมือนมากเช่น "สำหรับค่าตามลำดับ:" มากกว่า "สำหรับค่าใน iter (ลำดับ):" .. อัปเดตโพสต์?
Yam Marcovic

15
@Yam: ฉันเห็นด้วย ไม่ใช่ไพ ธ อนที่จะใช้ลำดับที่มีอยู่และแปลงเป็นตัววนซ้ำเพื่อใช้ลูปกับมัน ลำดับนั้นซ้ำแล้วซ้ำอีกดังนั้นการแปลงของ a listเป็น a listiteratorนั้นไม่มีจุดหมาย ผมเก็บไว้บรรทัดแรกเท่านั้นที่จะปฏิบัติตามจุดเริ่มต้น NullUserException ของอธิบายวิธีที่คุณควรจะห่วงมากกว่า iterator ซึ่งเป็นวิธีเดียวกับที่คุณควรจะห่วงมากกว่าใด ๆ iterable ( list, set, str, tuple, dict, file, generatorฯลฯ ) ฉันสามารถทำบางสิ่งบางอย่างit = itertools.combinations("ABCDE", 2)เพื่อให้ได้ตัวอย่างที่ดีขึ้นของตัววนซ้ำที่มีความหมาย
dr jimbob

1
it = iter(sequence)ไม่จำเป็น
Caridorc

2
@Caridorc - หากคุณอ่านความคิดเห็นแสดงว่าคุณมีข้อสงสัย ไม่จำเป็นและทำตามจุดเริ่มต้นของคำถาม (ที่พวกเขาถูกถามอย่างชัดเจนiterators) และคุณต้องiterสร้างiterator(ลองtype([])( list) vs type(iter([]))( listiterator) อย่างชัดเจน
dr jimbob

//, @drjimbob, คุณยกระดับยอดเยี่ยมในความคิดเห็นที่สองสำหรับคำถามนี้ ฉันค่อนข้างใหม่กับคุณสมบัติขั้นสูงของ iterables และฉันจะไม่ติดที่ถ้าฉันไม่ได้อ่านความคิดเห็น ฉันคิดว่ามันจะเป็นประโยชน์ต่อพวกเราหลายคนที่ยากจนการให้การศึกษาด้วยตนเองถ้าเราเห็นจุดนั้นว่าคำถามนั้นสามารถเปลี่ยนเป็น"The Python Way"เป็นส่วนแรกของคำตอบได้อย่างไร
Nathan Basanese

28

สาเหตุที่ไพ ธ อนใช้ข้อยกเว้นเพื่อหยุดการวนซ้ำที่บันทึกไว้ในPEP 234 :

มีการตั้งคำถามว่าข้อยกเว้นในการส่งสัญญาณการสิ้นสุดของการทำซ้ำนั้นไม่แพงเกินไปหรือไม่ มีตัวเลือกหลายตัวเลือกสำหรับข้อยกเว้น StopIteration: ค่าพิเศษ End to signal end, function end () เพื่อทดสอบว่าตัววนซ้ำเสร็จสิ้นหรือไม่แม้แต่นำข้อยกเว้น IndexError กลับมาใช้ใหม่

  • ค่าพิเศษมีปัญหาที่ถ้าลำดับมีค่าพิเศษนั้นการวนซ้ำของลำดับนั้นจะสิ้นสุดก่อนกำหนดโดยไม่มีการเตือนใด ๆ หากประสบการณ์กับสตริง C ที่ถูกยกเลิกค่า Null ไม่ได้สอนเราถึงปัญหาที่อาจเกิดขึ้นลองจินตนาการว่าเครื่องมือ Python Introspection มีปัญหาในการวนซ้ำรายการของชื่อในตัวทั้งหมดโดยสมมติว่าค่า End พิเศษเป็นค่าในตัว ในชื่อ!

  • การเรียกใช้ฟังก์ชัน end () จะต้องใช้สองสายต่อการวนซ้ำ การโทรสองสายนั้นมีราคาแพงกว่าการโทรหนึ่งครั้งบวกกับการทดสอบเพื่อรับข้อยกเว้น โดยเฉพาะอย่างยิ่งเวลาที่สำคัญสำหรับการวนซ้ำสามารถทดสอบได้อย่างถูกมากสำหรับข้อยกเว้น

  • การใช้ IndexError ซ้ำอาจทำให้เกิดความสับสนเนื่องจากอาจเป็นข้อผิดพลาดของแท้ซึ่งจะถูกพรางด้วยการสิ้นสุดการวนซ้ำก่อนกำหนด

หมายเหตุ: วิธีสำนวนที่ไพเราะกว่าลำดับเป็นดังนี้:

for value in sequence:
    print (value)

20

มันแตกต่างในปรัชญา ปรัชญาการออกแบบ Pythonic คือEAFP :

ง่ายต่อการขอการอภัยมากกว่าการอนุญาต รูปแบบการเขียนแบบ Python ทั่วไปนี้จะสมมติว่ามีคีย์หรือคุณสมบัติที่ถูกต้องและจับข้อยกเว้นหากสมมติฐานพิสูจน์ว่าเป็นเท็จ สไตล์ที่สะอาดและรวดเร็วนี้โดดเด่นด้วยการปรากฏตัวของหลายคนtryและexceptงบ เทคนิคนี้ขัดแย้งกับรูปแบบLBYLซึ่งใช้กับภาษาอื่น ๆ เช่น C ...


7

มันเป็นเพียงแค่ว่าการดำเนินงาน Java มีhasNext()วิธีการเพื่อให้คุณสามารถตรวจสอบการ iterator next()ว่างเปล่าก่อนที่จะดำเนินการ เมื่อคุณทำเช่นโทรnext()บน iterator Java มีองค์ประกอบไม่เหลือที่จะถูกโยนทิ้งNoSuchElementException

อย่างมีประสิทธิภาพคุณสามารถลอง.. จับจาวาในแบบลอง .. ยกเว้นใน Python และใช่ตามคำตอบก่อนหน้าปรัชญามีความสำคัญมากในโลก Pythonic

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.