ทำไมไพ ธ อนจึงใช้ 'else' หลังจากและขณะลูป


480

ฉันเข้าใจว่าโครงสร้างนี้ทำงานอย่างไร:

for i in range(10):
    print(i)

    if i == 9:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

แต่ฉันไม่เข้าใจว่าเพราะเหตุใดจึงelseใช้เป็นคำหลักที่นี่เนื่องจากจะแนะนำรหัสที่เป็นปัญหาจะทำงานก็ต่อเมื่อforบล็อกนั้นไม่เสร็จซึ่งตรงข้ามกับที่ทำ! ไม่ว่าฉันจะคิดอย่างไรสมองของฉันก็ไม่สามารถก้าวหน้าได้อย่างราบรื่นจากforข้อความถึงelseบล็อก สำหรับฉันcontinueหรือcontinuewithจะทำให้รู้สึกมากกว่า (และฉันพยายามที่จะฝึกตัวเองให้อ่านมันเช่นนี้)

ฉันสงสัยว่า Python coders อ่านโครงสร้างนี้ในหัวของพวกเขาอย่างไร (หรือออกเสียงถ้าคุณชอบ) บางทีฉันขาดบางสิ่งบางอย่างที่จะทำให้บล็อกรหัสดังกล่าวถอดรหัสได้ง่ายขึ้น?


26
คุณอาจต้องการแปลเป็น "แล้ว" ในหัวของคุณ
Marcin

63
อย่าลืมกุญแจสำคัญใน Zen of Python: "... วิธีนั้นอาจไม่ชัดเจนในตอนแรกเว้นแต่ว่าคุณเป็นชาวดัตช์"
Daniel Roseman

50
ในหัวของฉันฉันแปลเป็น"หากไม่หยุด" และเนื่องจากbreakมีการใช้งานมากใน"ฉันพบว่า"ลูปคุณสามารถแปลเป็น"ถ้าไม่พบ"ซึ่งอยู่ไม่ไกลจากสิ่งที่elseอ่าน
MestreLion

29
ฉันคิดว่าคำถามจริง ๆ ที่หลายคนมีอยู่ที่นี่คือ "อะไรคือความแตกต่างระหว่างfor ... else foo()และfoo()หลังจากการวนซ้ำ? และคำตอบก็คือพวกมันจะทำงานต่างกันก็ต่อเมื่อลูปมี a break(ดังอธิบายในรายละเอียดด้านล่าง)
Sam Kauffman

10
อัฒภาคในงูหลาม ... ดวงตาของฉันเจ็บปวด .. ถึงแม้ว่ามันจะถูกต้อง syntactically มันไม่ได้เป็นวิธีที่ดีในการทำเช่นนั้น
DarkCygnus

คำตอบ:


278

มันเป็นโครงสร้างที่แปลกแม้แต่กับตัวเขียน Python ที่ปรุงรส เมื่อใช้ร่วมกับ for-loops โดยทั่วไปแล้วหมายถึง "ค้นหารายการบางอย่างใน iterable มิฉะนั้นถ้าไม่พบ do do ... " ในขณะที่:

found_obj = None
for obj in objects:
    if obj.key == search_key:
        found_obj = obj
        break
else:
    print('No object found.')

แต่เมื่อใดก็ตามที่คุณเห็นโครงสร้างนี้ทางเลือกที่ดีกว่าคือการห่อหุ้มการค้นหาในฟังก์ชัน:

def find_obj(search_key):
    for obj in objects:
        if obj.key == search_key:
            return obj

หรือใช้ความเข้าใจในรายการ:

matching_objs = [o for o in objects if o.key == search_key]
if matching_objs:
    print('Found {}'.format(matching_objs[0]))
else:
    print('No object found.')

มันไม่เทียบเท่ากับอีกสองรุ่น แต่ใช้งานได้ดีพอในรหัสที่ไม่มีประสิทธิภาพซึ่งไม่สำคัญว่าคุณจะวนซ้ำรายการทั้งหมดหรือไม่ คนอื่นอาจไม่เห็นด้วย แต่ส่วนตัวฉันจะหลีกเลี่ยงการใช้บล็อก for-else หรือ while-else ในรหัสการผลิต

ดูเพิ่มเติม[Python-ideas] บทสรุปของสำหรับ ... else threads


50
ความเข้าใจในรายการเป็นหนึ่งซับที่ไม่ถูกต้อง หากคุณกำลังมองหารายการเดียวในขณะที่forตัวอย่างห่วงและต้องการใช้การแสดงออกกำเนิด / รายการเข้าใจแล้วคุณต้องการnext((o for o in objects if o.key == search_key), None)หรือห่อไว้ในtry/ exceptและใช้ค่าเริ่มต้นไม่มีแทน/if else
agf

4
และเช่นเดียวกับคำตอบของแลนซ์เฮลสเตนมีกรณีที่เกิดขึ้นจริงซึ่งควรใช้for/elseโครงสร้าง
andrean

5
ไชโย ฉันมีไฟล์เว้าแหว่งที่elseมีการจับคู่กับforและฉันก็ไม่รู้ว่ามันถูกกฎหมาย
maxywb

3
ฉันคิดว่า for for loop นั้นชัดเจนที่สุดของโครงสร้างที่นั่น
Miles Rout

14
เป็นมูลค่าการกล่าวขวัญว่าประโยคอื่นจะทำงานแม้ว่าห่วงสำหรับมีค่าเว้นแต่breakคำสั่งจะทำงานได้ชัดเจนในตัวอย่างนี้ จากเอกสารด้านบน: "ส่วนelseคำสั่งมีปัญหาการรับรู้อื่น: หากไม่มีbreakในการวนซ้ำส่วนelseคำสั่งจะซ้ำซ้อนตามหน้าที่" เช่นfor x in [1, 2, 3]:\n print x\n else:\n print 'this executes due to no break'
dhackner

586

โครงสร้างทั่วไปคือการเรียกใช้การวนซ้ำจนกว่าจะพบสิ่งที่ต้องการแล้วจึงแยกออกจากการวนซ้ำ ปัญหาคือว่าถ้าฉันแยกออกจากวงหรือปลายวงฉันต้องตรวจสอบกรณีที่เกิดขึ้น วิธีหนึ่งคือการสร้างตัวแปรธงหรือร้านค้าที่จะให้ฉันทำแบบทดสอบที่สองเพื่อดูว่าวงออกจาก

ตัวอย่างเช่นสมมติว่าฉันต้องค้นหารายการและประมวลผลแต่ละรายการจนกว่าจะพบรายการตั้งค่าสถานะแล้วหยุดการประมวลผล หากรายการแฟล็กหายไปจะต้องมีการยกข้อยกเว้น

ใช้ Python for... elseสร้างที่คุณมี

for i in mylist:
    if i == theflag:
        break
    process(i)
else:
    raise ValueError("List argument missing terminal flag.")

เปรียบเทียบสิ่งนี้กับวิธีที่ไม่ใช้น้ำตาลประโยคนี้:

flagfound = False
for i in mylist:
    if i == theflag:
        flagfound = True
        break
    process(i)

if not flagfound:
    raise ValueError("List argument missing terminal flag.")

ในกรณีแรกraiseจะถูกผูกไว้แน่นกับ for loop มันทำงานด้วย ในครั้งที่สองการผูกไม่รุนแรงและอาจมีข้อผิดพลาดเกิดขึ้นระหว่างการบำรุงรักษา


69
สิ่งนี้จะอธิบายได้ดีกว่าคำตอบที่เลือกซึ่งผู้เขียนไม่ได้รับสิ่งที่เป็นเรื่องเกี่ยวกับ!
erikbwork

17
ฉันต้องบอกว่าน้ำตาลซินแทคติคอาจทำให้ฟันของโปรเจ็กต์ของคุณพังทลาย นี่จะไม่ทำPython: the good partsหนังสือ
boatcoder

1
คุณสามารถยืนยันได้ว่าในตัวอย่างของคุณprocess(i)เกิดขึ้นสำหรับทุกรายการmylistอย่างเคร่งครัดก่อนtheflagและไม่ใช่theflagตัวเอง? มันเป็นสิ่งที่ตั้งใจหรือไม่
bli

4
processจะดำเนินการในแต่ละiที่มีอยู่ในรายการก่อนที่theflagจะมาถึงก็จะไม่ได้รับการดำเนินการในองค์ประกอบในรายการหลังจากที่และมันจะไม่ได้รับการดำเนินการในtheflag theflag
Lance Helsten

1
คำสั่งอื่นยังได้รับการดำเนินการหาก iterable ไม่มีองค์ประกอบ
Lost

173

มีการนำเสนอที่ยอดเยี่ยมโดย Raymond Hettinger ซึ่งมีชื่อว่าTransforming Code เป็น Beautiful, Idiomatic Pythonซึ่งเขากล่าวถึงประวัติของการfor ... elseสร้าง ส่วนที่เกี่ยวข้องคือ "แยกความแตกต่างของจุดออกหลายห่วง" เริ่มต้นที่ 15:50และดำเนินการต่อประมาณสามนาที นี่คือจุดที่สูง:

  • for ... elseสร้างถูกคิดค้นโดยโดนัลด์ Knuth แทนบางGOTOกรณีการใช้งาน;
  • การนำelseคำหลักกลับมาใช้ใหม่เพราะ "มันเป็นสิ่งที่ Knuth ใช้และผู้คนรู้ในเวลานั้น [ forคำสั่ง] ทั้งหมดได้ฝังifและGOTOข้างใต้และพวกเขาคาดหวังว่าelse"
  • ในการเข้าใจย้อนหลังมันควรจะถูกเรียกว่า "ไม่หยุด" (หรืออาจจะเป็น "nobreak") แล้วมันจะไม่สับสน *

ดังนั้นหากคำถามคือ "ทำไมพวกเขาไม่เปลี่ยนคำหลักนี้?" จากนั้นCat Plus Plus อาจให้คำตอบที่ถูกต้องที่สุด - ณ จุดนี้มันจะเป็นการทำลายรหัสที่มีอยู่มากเกินไปที่จะใช้งานได้จริง แต่ถ้าคำถามที่คุณถามจริงๆคือทำไมelseถูกนำกลับมาใช้ใหม่ในตอนแรกดูเหมือนว่ามันจะเป็นความคิดที่ดีในเวลานั้น

โดยส่วนตัวฉันชอบประนีประนอมของการแสดงความคิดเห็น# no breakในบรรทัดที่ใดก็ตามที่elseอาจถูกเข้าใจผิดได้อย่างรวดเร็วว่าเป็นของวง มันชัดเจนและรัดกุมพอสมควร ตัวเลือกนี้ได้รับการกล่าวถึงสั้น ๆ ในสรุปว่า Bjorn เชื่อมโยงในตอนท้ายของคำตอบของเขา:

เพื่อความสมบูรณ์ฉันควรพูดถึงว่าด้วยการเปลี่ยนแปลงเล็กน้อยในไวยากรณ์โปรแกรมเมอร์ที่ต้องการไวยากรณ์นี้สามารถมีได้ในขณะนี้:

for item in sequence:
    process(item)
else:  # no break
    suite

* การเสนอราคาโบนัสจากส่วนนั้นของวิดีโอ: "เหมือนกับว่าเราเรียกว่า lambda makefunctionไม่มีใครจะถามว่า 'lambda ทำอะไร' '


33

เพราะพวกเขาไม่ต้องการแนะนำคำหลักใหม่ให้กับภาษา แต่ละคนขโมยตัวระบุและทำให้เกิดปัญหาความเข้ากันได้ย้อนหลังดังนั้นจึงเป็นวิธีสุดท้าย


2
ดูเหมือนว่าfinallyจะเป็นทางเลือกที่ดีกว่าในกรณีนั้น เป็นคำหลักสุดท้ายที่ยังไม่ปรากฏในขณะที่โครงสร้างนี้ถูกนำมาใช้หรือไม่
Ponkadoodle

26
@ Walacoloo finallyนั้นไม่ค่อยดีนักเพราะมันบอกเป็นนัย ๆ ว่าบล็อกนั้นจะถูกเรียกใช้งานหลังจากวนรอบเสมอและมันก็ไม่ได้ (เพราะมันจะซ้ำซ้อนด้วยการใส่รหัสเพื่อเรียกใช้หลังจากวนรอบ)
Cat Plus Plus

มันไม่สามารถเป็นได้finallyเพราะประโยคอื่นถูกเรียกใช้งานเช่นกันเมื่อcontinueใช้ในลูป for - ซึ่งอาจเป็นไปได้หลายครั้งและไม่เพียงแค่ตอนจบ
pepr

6
@pepr elseการดำเนินการข้อไม่ได้รับผลกระทบจากcontinue( เอกสารและรหัสการทดสอบ )
อากาศ

@AirThomas: +1 คุณพูดถูก elseจะถูกดำเนินการเฉพาะเมื่อcontinueเป็นหนึ่งสำหรับการทำซ้ำที่ผ่านมา
pepr

33

เพื่อให้ง่ายคุณสามารถคิดแบบนั้น

  • หากพบbreakคำสั่งในforลูปelseส่วนหนึ่งจะไม่ถูกเรียกใช้
  • หากไม่พบbreakคำสั่งในforลูปelseส่วนหนึ่งจะถูกเรียกใช้

ในคำอื่น ๆ ถ้าห่วงซ้ำไม่ได้ "เสีย" กับbreakการelseเป็นส่วนหนึ่งจะถูกเรียกว่า


elseบล็อกจะยังไม่ได้รับการดำเนินการถ้าร่างกายของวงยกข้อยกเว้น
Amal K

17

วิธีที่ง่ายที่สุดที่ฉันพบว่า 'ได้รับ' สิ่งที่ทำเพื่อ / อย่างอื่นและที่สำคัญกว่านั้นเมื่อใช้มันคือตั้งสมาธิที่ว่าคำสั่ง break จะข้ามไปที่ใด โครงสร้าง For / else เป็นบล็อกเดียว ตัวแบ่งกระโดดออกจากบล็อกและข้ามส่วนคำสั่งอื่นไป หากเนื้อหาของข้ออื่นเพียงแค่ทำตามสำหรับประโยคนั้นมันจะไม่ถูกกระโดดข้ามและดังนั้นตรรกะที่เทียบเท่าจะต้องถูกจัดเตรียมโดยการใส่ไว้ใน if สิ่งนี้ถูกพูดมาก่อน แต่ไม่มากนักในคำเหล่านี้ดังนั้นจึงอาจช่วยคนอื่นได้ ลองเรียกใช้ส่วนรหัสต่อไปนี้ ฉันสุดใจที่จะแสดงความคิดเห็น 'ไม่หยุด' เพื่อความชัดเจน

for a in range(3):
    print(a)
    if a==4: # change value to force break or not
        break
else: #no break  +10 for whoever thought of this decoration
    print('for completed OK')

print('statement after for loop')

"แบ่งกระโดดออกจากบล็อกและอื่น ๆ กระโดด 'มากกว่า' ประโยคอื่น" - ในขณะนี้อาจจะเป็นประโยชน์เป็นวิธีการ "รับ" a for:/ มันไม่ได้จริงๆให้เหตุผลสำหรับคำหลักที่เป็นอยู่else: elseให้กรอบที่นี่then:ดูเหมือนว่าจะเป็นธรรมชาติมากขึ้น (มีเป็นเหตุผลที่elseถูกเลือกให้อยู่ในคำตอบอื่น ๆ - พวกเขาเพียงแค่ไม่ได้ให้ที่นี่.)
มาร์ค Amery

16

ผมคิดว่าเอกสารที่มีคำอธิบายที่ดีของ คนอื่น , ดำเนินการต่อไป

[... ] มันจะถูกดำเนินการเมื่อลูปสิ้นสุดลงผ่านความเหนื่อยล้าของรายการ (ด้วยสำหรับ) หรือเมื่อเงื่อนไขนั้นกลายเป็นเท็จ (ด้วยในขณะที่) แต่ไม่ใช่เมื่อลูปถูกยกเลิกโดยคำสั่ง break "

ที่มา: เอกสาร Python 2: บทช่วยสอนเกี่ยวกับโฟลว์ควบคุม


13

ฉันอ่านมันเหมือน:

หากยังอยู่ในเงื่อนไขที่จะใช้การวนซ้ำให้ทำสิ่งอื่นทำอย่างอื่น


เงื่อนไขของคุณยังคงมีประโยชน์ (+1) แม้ว่ามันจะผิด - เป็นมนุษย์ ;-)
Wolf

-1; การออกเสียงfor:/ else:ทำให้ดูเหมือนว่าelse:จะทำงานหลังจากลูปเสมอซึ่งไม่ใช่กรณี
Mark Amery

11

เนื่องจากส่วนเทคนิคได้รับการตอบแล้วค่อนข้างมากความคิดเห็นของฉันเป็นเพียงความสัมพันธ์กับความสับสนที่ทำให้คำหลักที่นำกลับมาใช้ใหม่นี้

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

แทนที่จะใช้คำหลักนี้ด้วยwhileและforข้อความสร้างความสับสนแทน เหตุผลอาชีพของเราในฐานะโปรแกรมเมอร์ได้สอนเราว่าelseคำแถลงนั้นอยู่ในโครงสร้างการตัดสินใจ ของขอบเขตตรรกะ , เสื้อคลุมที่มีเงื่อนไขกลับเส้นทางที่จะปฏิบัติตาม ในขณะเดียวกันงบลูปมีเป้าหมายที่ชัดเจนเป็นรูปเป็นร่างเพื่อเข้าถึงบางสิ่ง เป้าหมายบรรลุตามการวนซ้ำอย่างต่อเนื่องของกระบวนการ

if / else บ่งบอกถึงเส้นทางที่จะปฏิบัติตาม ลูปตามเส้นทางจนกระทั่ง "เป้าหมาย" เป็นที่เรียบร้อยแล้ว

ปัญหาคือว่าelseเป็นคำที่กำหนดตัวเลือกสุดท้ายอย่างชัดเจนในเงื่อนไข ความหมายของคำว่ามีทั้งที่ใช้ร่วมกันโดยงูหลามและมนุษยภาษา แต่คำอื่น ๆ ในภาษามนุษย์ไม่เคยถูกใช้เพื่อบ่งบอกถึงการกระทำของใครบางคนหรือบางสิ่งที่จะเกิดขึ้นหลังจากที่บางสิ่งบางอย่างเสร็จสิ้น มันจะถูกนำมาใช้หากในระหว่างการดำเนินการให้เสร็จสิ้นปัญหาจะเพิ่มขึ้น (คล้ายกับคำสั่งbreak )

ในตอนท้ายคำหลักจะยังคงอยู่ใน Python เห็นได้ชัดว่ามันเป็นความผิดพลาดชัดเจนขึ้นเมื่อโปรแกรมเมอร์ทุกคนพยายามคิดเรื่องที่จะเข้าใจการใช้งานเหมือนอุปกรณ์ช่วยในการจำ thenฉันมีความรักถ้าพวกเขาได้รับการแต่งตั้งแทนคำหลัก ฉันเชื่อว่าคำหลักนี้เหมาะสมอย่างสมบูรณ์ในการไหลวนซ้ำ, ผลตอบแทนหลังจากวนซ้ำ

มันคล้ายกับสถานการณ์ที่เด็กบางคนมีหลังจากทำตามทุกขั้นตอนในการประกอบของเล่น: แล้วพ่อล่ะ?


ฉันคิดว่าคำตอบนี้ตอบปัญหาความสับสนที่ฉันคิดว่า OP กำลังพูดถึง คำหลักอื่นจะตรงข้ามกับสิ่งที่คุณคาดหวังจากความหมายภาษาอังกฤษของสิ่งอื่น ๆ เมื่อแนบกับการกระทำของสำหรับ ในทางทฤษฎีสำหรับ ... คนอื่นอาจทำงานแตกต่างกันในกรณีที่คุณลงเอยในส่วนอื่นเมื่อวงแตกออก แต่ปัญหาคือการใช้เพื่อค้นหาองค์ประกอบ x และจัดการกรณีที่ x เป็น ไม่พบคุณอาจต้องใช้ธงหรือการทดสอบอื่นหลังจากทั้งหมดสำหรับ .. สร้างอย่างอื่น
Spacen Jasset

7

ฉันอ่านมันเหมือน "เมื่อiterableหมดแล้วและการดำเนินการกำลังจะดำเนินการต่อไปยังคำสั่งถัดไปหลังจากเสร็จสิ้นforประโยคอื่นจะถูกดำเนินการ" ดังนั้นเมื่อการทำซ้ำถูกทำลายโดยbreakสิ่งนี้จะไม่ถูกดำเนินการ


6

ฉันเห็นด้วยมันเหมือน 'elif ไม่ใช่ [เงื่อนไข (การเพิ่มการหยุดพักชั่วคราว)'

ฉันรู้ว่านี่เป็นหัวข้อเก่า แต่ฉันกำลังดูคำถามเดียวกันตอนนี้และฉันไม่แน่ใจว่ามีใครได้รับคำตอบของคำถามนี้ในแบบที่ฉันเข้าใจ

สำหรับฉันมีสามวิธีในการ "อ่าน" elseในFor... elseหรือWhile... elseข้อความซึ่งทั้งหมดจะเทียบเท่าคือ:

  1. else == if the loop completes normally (without a break or error)
  2. else == if the loop does not encounter a break
  3. else == else not (condition raising break) (สมมุติว่ามีเงื่อนไขดังกล่าวหรือคุณไม่มีห่วง)

ดังนั้นโดยพื้นฐานแล้ว "else" ในลูปคือ "elif ... " โดยที่ '... ' คือ (1) ไม่มีการหยุดพักซึ่งเทียบเท่ากับ (2) ไม่ใช่ [เงื่อนไข (s) การเพิ่มการแบ่ง]

ฉันคิดว่ากุญแจสำคัญคือelseไม่มีจุดหมายโดยไม่ต้อง 'หยุด' ดังนั้นfor...elseรวมถึง:

for:
    do stuff
    conditional break # implied by else
else not break:
    do more stuff

ดังนั้นองค์ประกอบที่สำคัญของการfor...elseวนรอบมีดังนี้และคุณจะอ่านพวกเขาในภาษาอังกฤษที่ชัดเจนกว่า:

for:
    do stuff
    condition:
        break
else: # read as "else not break" or "else not condition"
    do more stuff

ดังที่ผู้โพสต์คนอื่น ๆ บอกไว้โดยทั่วไปการหยุดพักจะเกิดขึ้นเมื่อคุณสามารถค้นหาว่าวงของคุณกำลังมองหาอะไรอยู่ดังนั้นการelse:กลายเป็น "สิ่งที่ต้องทำถ้ารายการเป้าหมายไม่ได้อยู่"

ตัวอย่าง

นอกจากนี้คุณยังสามารถใช้การจัดการข้อยกเว้นตัวแบ่งและลูปทั้งหมดเข้าด้วยกัน

for x in range(0,3):
    print("x: {}".format(x))
    if x == 2:
        try:
            raise AssertionError("ASSERTION ERROR: x is {}".format(x))
        except:
            print(AssertionError("ASSERTION ERROR: x is {}".format(x)))
            break
else:
    print("X loop complete without error")

ผลลัพธ์

x: 0
x: 1
x: 2
ASSERTION ERROR: x is 2
----------
# loop not completed (hit break), so else didn't run

ตัวอย่าง

ตัวอย่างง่ายๆกับการหยุดพักการตี

for y in range(0,3):
    print("y: {}".format(y))
    if y == 2: # will be executed
        print("BREAK: y is {}\n----------".format(y))
        break
else: # not executed because break is hit
    print("y_loop completed without break----------\n")

ผลลัพธ์

y: 0
y: 1
y: 2
BREAK: y is 2
----------
# loop not completed (hit break), so else didn't run

ตัวอย่าง

ตัวอย่างง่ายๆที่ไม่มีการแบ่งไม่มีเงื่อนไขในการเพิ่มตัวแบ่งและไม่พบข้อผิดพลาด

for z in range(0,3):
     print("z: {}".format(z))
     if z == 4: # will not be executed
         print("BREAK: z is {}\n".format(y))
         break
     if z == 4: # will not be executed
         raise AssertionError("ASSERTION ERROR: x is {}".format(x))
else:
     print("z_loop complete without break or error\n----------\n")

ผลลัพธ์

z: 0
z: 1
z: 2
z_loop complete without break or error
----------

6

elseคำหลักที่สามารถทำให้เกิดความสับสนที่นี่และเป็นคนจำนวนมากได้ออกมาชี้สิ่งที่ชอบnobreak, notbreakมีความเหมาะสมมากขึ้น

เพื่อให้เข้าใจถึงfor ... else ...เหตุผลให้เปรียบเทียบกับtry...except...elseไม่ใช่if...else...โปรแกรมเมอร์ไพ ธ อนส่วนใหญ่คุ้นเคยกับโค้ดต่อไปนี้:

try:
    do_something()
except:
    print("Error happened.") # The try block threw an exception
else:
    print("Everything is find.") # The try block does things just find.

ในทำนองเดียวกันคิดว่าbreakเป็นชนิดพิเศษException:

for x in iterable:
    do_something(x)
except break:
    pass # Implied by Python's loop semantics
else:
    print('no break encountered')  # No break statement was encountered

ความแตกต่างpythonหมายถึงexcept breakและคุณไม่สามารถเขียนมันออกมาดังนั้นมันจะกลายเป็น:

for x in iterable:
    do_something(x)
else:
    print('no break encountered')  # No break statement was encountered

ใช่ฉันรู้ว่าการเปรียบเทียบนี้อาจยากและน่าเบื่อ แต่ก็ช่วยชี้แจงความสับสน


คุณควรจะเชื่อมโยงไปยังทรัพยากรเมื่อคุณคัดลอกจาก: นิค Coghlan ของงูหลามหมายเหตุ
godaygo

@ godaygo ขอบคุณสำหรับลิงค์ ฉันอ่านและยอมรับแนวคิดเมื่อเรียนรู้หลามครั้งแรกไม่ได้จดจำแหล่งที่มาเมื่อเขียนคำตอบ
cizixs

@cizixs คุณ"ไม่ได้จดจำแหล่งที่มา"แต่เพิ่งเกิดขึ้นเพื่อรวมประโยคความคิดเห็นทั้งหมดที่เหมือนต้นฉบับหรือไม่ Ooookaaaay
Mark Amery

5

รหัสในelseบล็อกคำสั่งจะถูกดำเนินการเมื่อforไม่วนซ้ำ

for x in xrange(1,5):
    if x == 5:
        print 'find 5'
        break
else:
    print 'can not find 5!'
#can not find 5!

จากเอกสาร: แยกและดำเนินการข้อความต่อและข้อความอื่น ๆ บน Loops

คำสั่งวนรอบอาจมีประโยคอื่น; มันจะถูกดำเนินการเมื่อลูปสิ้นสุดลงผ่านความเหนื่อยล้าของรายการ (กับสำหรับ) หรือเมื่อเงื่อนไขกลายเป็นเท็จ (ด้วยในขณะ) แต่ไม่เมื่อลูปถูกยกเลิกโดยคำสั่ง break นี่คือสุดขั้วโดยวงต่อไปนี้ซึ่งค้นหาหมายเลขเฉพาะ:

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, 'equals', x, '*', n//x)
...             break
...     else:
...         # loop fell through without finding a factor
...         print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

(ใช่นี่เป็นรหัสที่ถูกต้องดูอย่างใกล้ชิด: ประโยคอื่นเป็นของลูป for ไม่ใช่คำสั่ง if)

เมื่อใช้กับ loop ประโยคอื่น ๆ จะเหมือนกันกับประโยคอื่นของคำสั่ง try มากกว่าที่จะเป็นถ้า if statement: ประโยคอื่นของประโยค try จะทำงานเมื่อไม่มีข้อยกเว้นเกิดขึ้นและประโยคอื่นของ loop จะทำงานเมื่อไม่มีการแบ่งเกิดขึ้น . สำหรับข้อมูลเพิ่มเติมเกี่ยวกับคำสั่งลองและข้อยกเว้นดูการจัดการข้อยกเว้น

คำสั่ง continue ที่ยืมมาจาก C ดำเนินการต่อด้วยการวนซ้ำครั้งถัดไป:

>>> for num in range(2, 10):
...     if num % 2 == 0:
...         print("Found an even number", num)
...         continue
...     print("Found a number", num)
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9

1
นี้จะเพิ่มอะไรและไม่ได้ตอบคำถามซึ่งไม่ว่าแต่ทำไม
อากาศ

5

นี่คือวิธีคิดเกี่ยวกับมันที่ฉันไม่ได้เห็นใครพูดถึงข้างต้น:

ก่อนอื่นให้จำไว้ว่า for-loops นั้นเป็นเพียงน้ำตาลประโยครอบ ๆ ตัวอย่างเช่นการวนรอบ

for item in sequence:
    do_something(item)

สามารถเขียนใหม่ได้ (โดยประมาณ) เป็น

item = None
while sequence.hasnext():
    item = sequence.next()
    do_something(item)

ประการที่สองโปรดจำไว้ว่าในขณะที่ลูปนั้นทำซ้ำถ้าบล็อกนั้นซ้ำไปซ้ำมา! คุณสามารถอ่านสักครู่ห่วงว่า "ถ้าเงื่อนไขนี้เป็นจริงดำเนินการร่างกายแล้วกลับมาตรวจสอบอีกครั้ง"

ดังนั้นในขณะที่ / else ใช้งานได้ดี: มันเป็นโครงสร้างที่เหมือนกันกับ if / else โดยมีฟังก์ชั่นเพิ่มเติมของการวนลูปจนกว่าเงื่อนไขจะกลายเป็นเท็จแทนที่จะตรวจสอบเงื่อนไขเพียงครั้งเดียว

และสำหรับ / else ก็สมเหตุสมผลเช่นกัน: เนื่องจาก for-loops ทั้งหมดเป็นเพียงน้ำตาล syntactic ที่อยู่ด้านบนของ while-loops คุณแค่ต้องคิดออกว่าเงื่อนไขโดยนัยของ while-loop โดยนัยคืออะไรและอย่างอื่นนั้นสอดคล้องกับเมื่อนั้น สภาพกลายเป็นเท็จ


4

คำตอบที่ดีคือ:

  • สิ่งนี้ซึ่งอธิบายประวัติศาสตร์และ
  • สิ่งนี้ให้การอ้างอิงที่ถูกต้องเพื่อทำให้การแปล / ความเข้าใจของคุณง่ายขึ้น

บันทึกของฉันที่นี่มาจากสิ่งที่ Donald Knuth เคยกล่าวไว้ (ขออภัยไม่สามารถหาข้อมูลอ้างอิงได้) ว่ามีสิ่งก่อสร้างที่ while-else แยกไม่ออกจาก if-else คือ (ใน Python):

x = 2
while x > 3:
    print("foo")
    break
else:
    print("boo")

มีการไหลเดียวกัน (ไม่รวมความแตกต่างในระดับต่ำ) เป็น:

x = 2
if x > 3:
    print("foo")
else:
    print("boo")

ประเด็นคือถ้าอื่น ๆ ถือได้ว่าเป็นน้ำตาลเชิงซ้อนสำหรับในขณะที่คนอื่นซึ่งมีนัยbreakในตอนท้ายของifบล็อก ความหมายตรงข้ามที่whileห่วงคือส่วนขยายไปifเป็นเรื่องธรรมดามากขึ้น (มันซ้ำแล้วซ้ำอีกเพียง / คล้องตรวจสอบเงื่อนไข) เพราะมักจะสอนก่อนif whileอย่างไรก็ตามนั่นไม่เป็นความจริงเพราะนั่นหมายถึงการelseบล็อกในขณะที่ - อื่นจะถูกดำเนินการในแต่ละครั้งเมื่อเงื่อนไขเป็นเท็จ

เพื่อความเข้าใจที่ง่ายขึ้นให้คิดดังนี้:

โดยไม่ต้องbreak, returnฯลฯ วงปลายเฉพาะเมื่อสภาพไม่เป็นความจริงและในกรณีเช่นelseบล็อกยังจะดำเนินการครั้งเดียว ในกรณีของงูใหญ่forที่คุณต้องพิจารณาแบบ C forลูป (โดยมีเงื่อนไข) whileหรือแปลให้พวกเขา

หมายเหตุอื่น:

ก่อนวัยอันควรbreak, returnฯลฯ ภายในห่วงทำให้ไปไม่ได้สำหรับเงื่อนไขที่จะกลายเป็นเท็จเพราะการดำเนินการกระโดดออกมาจากวงในขณะที่สภาพเป็นความจริงและมันจะไม่กลับมาตรวจสอบอีกครั้ง


3

คุณอาจคิดว่ามันเหมือน elseในส่วนที่เหลือของหรือสิ่งอื่น ๆ ที่ไม่ได้ทำในวง


3
for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

"อื่น ๆ " ที่นี่เรียบง่ายอย่างบ้าคลั่งเพียงหมายถึง

1 "ถ้าfor clauseเสร็จสมบูรณ์"

for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
if "for clause is completed":
    print("Completed successfully")

มันเป็นการเขียนข้อความยาว ๆ อย่าง "สำหรับประโยคเสร็จสมบูรณ์" ดังนั้นพวกเขาจึงแนะนำ "อื่น ๆ "

else นี่คือถ้าในธรรมชาติของมัน

2 อย่างไรก็ตามยังไงกัน for clause is not run at all

In [331]: for i in range(0):
     ...:     print(i)
     ...: 
     ...:     if i == 9:
     ...:         print("Too big - I'm giving up!")
     ...:         break
     ...: else:
     ...:     print("Completed successfully")
     ...:     
Completed successfully

ดังนั้นจึงเป็นคำสั่งที่สมบูรณ์คือการรวมตรรกะ:

if "for clause is completed" or "not run at all":
     do else stuff

หรือใช้วิธีนี้:

if "for clause is not partially run":
    do else stuff

หรือด้วยวิธีนี้:

if "for clause not encounter a break":
    do else stuff

มิฉะนั้นจะทำหน้าที่เป็น "ธุรกรรม" ใน SQL
แคลคูลัส

2

นี่คืออีกกรณีการใช้สำนวนที่นอกเหนือจากการค้นหา สมมติว่าคุณต้องการรอให้เงื่อนไขเป็นจริงเช่นพอร์ตที่จะเปิดบนเซิร์ฟเวอร์ระยะไกลพร้อมกับการหยุดพักชั่วคราว จากนั้นคุณสามารถใช้while...elseโครงสร้างได้ดังนี้:

import socket
import time

sock = socket.socket()
timeout = time.time() + 15
while time.time() < timeout:
    if sock.connect_ex(('127.0.0.1', 80)) is 0:
        print('Port is open now!')
        break
    print('Still waiting...')
else:
    raise TimeoutError()

1

ฉันแค่พยายามทำความเข้าใจกับมันอีกครั้งเอง ฉันพบว่าสิ่งต่อไปนี้ช่วยได้!

•คิดว่าelseการจับคู่กับifภายในลูป (แทนที่จะเป็นกับfor) - หากตรงตามเงื่อนไขแล้วแบ่งลูปให้ทำเช่นนี้ - ยกเว้นว่าเป็นelseคู่ที่มีหลายifs!
•หากไม่มีifs elseมีความพึงพอใจที่ทุกคนแล้วทำ
•หลายifs สามารถถูกคิดว่าเป็นif- elif!


-2

ฉันพิจารณาโครงสร้างสำหรับ (ถ้ามี) คำอื่น B และสำหรับ (ถ้ามี) -else เป็นพิเศษถ้า-อื่น , ประมาณ มันอาจช่วยให้เข้าใจอื่น

A และ B ถูกดำเนินการมากที่สุดหนึ่งครั้งซึ่งเป็นโครงสร้างเดียวกันกับ if-else

สำหรับ (ถ้า) ถือได้ว่าเป็นพิเศษถ้าซึ่งจะวนไปลองเงื่อนไขถ้า เมื่อถ้าสภาพจะพบและแบ่ง ; อื่น ๆ B.


-2

Python ใช้สิ่งอื่นหลังจากนั้นและในขณะที่ลูปดังนั้นหากไม่มีสิ่งใดที่นำไปใช้กับการวนซ้ำจะมีสิ่งอื่นเกิดขึ้น ตัวอย่างเช่น:

test = 3
while test == 4:
     print("Hello")
else:
     print("Hi")

ผลลัพธ์จะเป็น 'สวัสดี' ซ้ำแล้วซ้ำอีก (ถ้าฉันถูกต้อง)

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