ฉันจะทำให้ความรู้สึกของประโยค 'else' ของ Python loops ได้อย่างไร?


191

โปรแกรมเมอร์ Python หลายคนอาจไม่รู้ว่าไวยากรณ์ของwhileลูปและforลูปรวมถึงelse:ประโยคที่เป็นตัวเลือก:

for val in iterable:
    do_something(val)
else:
    clean_up()

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

เสมอ? เมื่อ "ล้มเหลว" ของลูปตามชื่อแนะนำ? เมื่อเลิกจ้างปกติ? แม้ว่าจะออกจากลูปด้วยreturnหรือไม่ ฉันไม่สามารถมั่นใจได้อย่างสมบูรณ์โดยไม่ต้องมองหามัน

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

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

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


23
"ถ้ามีอะไรเหลือให้ทำซ้ำ ... อื่น ๆ "
OneCricketeer

4
ฉันคิดว่าคุณสามารถจำได้ในขณะนี้หลังจากที่เขียนคำถามนี้ :)
แจสเปอร์

11
elseหมายโดยทั่วไป "ถ้าเงื่อนไขต่อเนื่องล้มเหลว" ในแบบดั้งเดิมสำหรับการวนซ้ำสภาพความต่อเนื่องเป็นปกติi < 42ซึ่งในกรณีนี้คุณสามารถดูส่วนที่เป็นif i < 42; execute the loop body; else; do that other thing
njzk2

1
ทั้งหมดนี้เป็นเรื่องจริงและฉันชอบคำตอบของ drawoc แต่สิ่งที่ต้องพิจารณาอีกประการหนึ่งคือคำอื่น ๆ ที่มีอยู่เป็นคำหลักที่มีอยู่ซึ่งก็ค่อนข้างสมเหตุสมผล คุณอาจรู้จักลอง / ยกเว้นและอาจลอง / ยกเว้น / สุดท้าย แต่ก็มีอย่างอื่น - รันรหัสนี้หากไม่มีข้อยกเว้นเกิดขึ้น btw ใดที่ไม่เหมือนกับการผลักรหัสนี้ภายใต้ข้อลองใช้ - การจัดการข้อยกเว้นจะใช้ดีที่สุดเมื่อกำหนดเป้าหมายแคบ ดังนั้นในขณะที่มันทำให้รู้สึกความคิด - ราคาตามจำนวนของคำตอบที่นี่ - ฉันคิดว่ามันนำมาใช้คำหลักที่เล่นด้วย - ทำงานนี้อยู่ภายใต้เงื่อนไขบางประการ
JL Peyret

1
@Falanwe, breakมีความแตกต่างเมื่อรหัสออกโดย กรณีการใช้งานที่ยอมรับได้คือเมื่อลูปค้นหาบางสิ่งและหยุดเมื่อพบ elseจะดำเนินการเฉพาะในกรณีที่ไม่พบ
alexis

คำตอบ:


212

(นี่คือแรงบันดาลใจจากคำตอบของ @Mark Tolonen)

ifคำสั่งทำงานของelseข้อถ้าเงื่อนไขของการประเมินผลเป็นเท็จ เหมือนกันwhileห่วงวิ่งประโยคอื่นถ้าสภาพของการประเมินผลเป็นเท็จ

กฎนี้ตรงกับพฤติกรรมที่คุณอธิบาย:

  • ในการดำเนินการปกติวนลูป while จะทำงานซ้ำ ๆ จนกว่าเงื่อนไขจะประเมินว่าเป็นเท็จและดังนั้นการออกจากลูปจะรันประโยคอื่นอย่างเป็นธรรมชาติ
  • เมื่อคุณรัน a breakคำสั่งคุณออกจากลูปโดยไม่ต้องประเมินเงื่อนไขดังนั้นเงื่อนไขไม่สามารถประเมินเป็นเท็จและคุณไม่เคยเรียกใช้ประโยคอื่น
  • เมื่อคุณรัน a continueคำสั่งคุณประเมินเงื่อนไขอีกครั้งและทำสิ่งที่คุณทำตามปกติที่จุดเริ่มต้นของการวนซ้ำวนซ้ำ ดังนั้นหากเงื่อนไขเป็นจริงคุณจะวนลูปต่อไป แต่ถ้าเป็นจริงคุณจะเรียกใช้ประโยคอื่นได้
  • วิธีอื่นในการออกจากลูปเช่นreturnไม่ประเมินเงื่อนไขและดังนั้นอย่ารันประโยคอื่น

forลูปทำงานในลักษณะเดียวกัน เพียงพิจารณาว่าเงื่อนไขเป็นจริงหากตัววนซ้ำมีองค์ประกอบเพิ่มเติมหรือเท็จอย่างอื่น


8
นี่คือคำตอบที่ยอดเยี่ยมที่สุด ปฏิบัติต่อลูปของคุณเหมือนชุดข้อความสั่งของ elif และพฤติกรรมอื่นจะเปิดเผยตรรกะตามธรรมชาติ
Nomenator

1
ฉันชอบคำตอบนี้ด้วย แต่มันไม่ได้เป็นการเปรียบเทียบกับชุดelifคำสั่ง มีคำตอบที่ทำและมีหนึ่ง upvote สุทธิ
alexis

2
ไม่ถูกต้องอย่างแน่นอนขณะที่ลูปอาจมีเงื่อนไขตรงกับเท็จก่อนหน้านี้breakซึ่งในกรณีนี้elseจะไม่เรียกใช้ แต่เงื่อนไขเป็นเท็จ ในทำนองเดียวกันกับforลูปก็สามารถbreakในองค์ประกอบสุดท้าย
Tadhg McDonald-Jensen

36

ดีกว่าที่จะคิดด้วยวิธีนี้: elseบล็อกจะถูกดำเนินการเสมอหากทุกอย่างถูกต้องในforบล็อกก่อนหน้านี้จนหมด

ขวาในบริบทนี้จะหมายถึงการไม่มีexceptionไม่มีไม่มีbreak returnคำสั่งใด ๆ ที่การควบคุม hijacks forจะทำให้เกิดการelseข้ามบล็อก


พบกรณีการใช้งานทั่วไปเมื่อค้นหารายการในiterableซึ่งการค้นหาจะถูกเรียกออกเมื่อพบรายการหรือ"not found"ยกธง / พิมพ์ผ่านelseบล็อกต่อไปนี้:

for items in basket:
    if isinstance(item, Egg):
        break
else:
    print("No eggs in basket")  

A continueไม่จี้ควบคุมจากforดังนั้นการควบคุมจะดำเนินต่อไปelseหลังจากที่forหมดแล้ว


20
ฟังดูดีมาก ... แต่แล้วคุณก็คาดหวังว่าelseประโยคจะต้องถูกประหารชีวิตเมื่อสิ่งต่าง ๆไม่ถูกต้องใช่ไหม ฉันแล้วการสับสนอีกครั้ง ...
อเล็กซิส

ฉันต้องเห็นด้วยกับคุณเรื่อง "เทคนิคมันไม่ได้ [ความหมายคล้ายกับอื่น ๆ ทุกคนelse]" ตั้งแต่elseมีการเรียกใช้เมื่อไม่มีเงื่อนไขในการห่วงประเมินทรูในฐานะที่ผมแสดงให้เห็นในคำตอบของฉัน
Tadhg McDonald- เซ่น

@ TadhgMcDonald Falseเซ่นนอกจากนี้คุณยังสามารถทำลายห่วงที่ ดังนั้นคำถามของวิธีการที่forจะเสียขึ้นอยู่กับกรณีการใช้งาน
Moses Koledoye

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

1
มันไม่มีอะไรเกี่ยวข้องกับ "สิ่งที่กำลังทำอยู่" จะดำเนินการอื่นอย่างหมดจดเมื่อif/ whileเงื่อนไขประเมินว่าเป็นเท็จหรือไม่forอยู่ในรายการ breakมีลูปที่มีอยู่ (หลังจากelse) continueย้อนกลับและประเมินสภาพลูปอีกครั้ง
Mark Tolonen

31

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

forจะคล้ายกันยกเว้นสภาพเท็จของมันจะหลบหนี iterator ของมัน

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


1
สิ่งที่คุณพูดฟังดูสมเหตุสมผลมาก แต่เมื่อรวมเงื่อนไขการเลิกจ้างทั้งสามเข้าด้วยกัน "จนกระทั่ง [เงื่อนไข] เป็นเท็จหรือหยุดพัก / ต่อ" ผิด: สำคัญelseประโยคจะถูกดำเนินการหากออกจากลูปด้วยcontinue(หรือปกติ) แต่ไม่ได้breakถ้าเราออกด้วย รายละเอียดปลีกย่อยเหล่านี้เป็นสาเหตุที่ฉันพยายามที่จะelseจับสิ่งที่จับและสิ่งที่ไม่
alexis

4
@alexis ใช่ฉันต้องการชี้แจงที่นั่น แก้ไข ดำเนินการต่อไม่ได้ดำเนินการอื่น แต่กลับไปที่ด้านบนของลูปซึ่งอาจประเมินเป็นเท็จ
Mark Tolonen

24

นี่คือสิ่งที่มันหมายถึง:

for/while ...:
    if ...:
        break
if there was a break:
    pass
else:
    ...

มันเป็นวิธีการเขียนรูปแบบทั่วไปที่ดีกว่านี้:

found = False
for/while ...:
    if ...:
        found = True
        break
if not found:
    ...

ส่วนelseคำสั่งจะไม่ถูกดำเนินการหากมีreturnเพราะเพราะreturnออกจากฟังก์ชั่นตามที่มีความหมาย ข้อยกเว้นเพียงข้อเดียวที่คุณอาจนึกถึงคือfinallyมีจุดประสงค์เพื่อให้แน่ใจว่ามีการดำเนินการอยู่เสมอ

continueไม่มีอะไรพิเศษเกี่ยวกับเรื่องนี้ breakมันทำให้เกิดการซ้ำปัจจุบันของวงไปยังจุดสิ้นสุดซึ่งอาจจะเกิดขึ้นจะจบวงทั้งหมดและอย่างชัดเจนในกรณีที่ว่าห่วงไม่ได้จบลงด้วย

try/else คล้ายกัน:

try:
    ...
except:
    ...
if there was an exception:
    pass
else:
    ...

20

หากคุณคิดว่าลูปของคุณเป็นโครงสร้างคล้ายกับนี้ (ค่อนข้างหลอกรหัส):

loop:
if condition then

   ... //execute body
   goto loop
else
   ...

มันอาจจะสมเหตุสมผลมากกว่า ห่วงเป็นหลักเพียงแค่คำว่าซ้ำจนกว่าเงื่อนไขเป็นif falseและนี่คือจุดสำคัญ ลูปตรวจสอบสภาพของมันและเห็นว่ามันเป็นfalseดังนั้นจึงดำเนินการelse(เช่นเดียวกับปกติif/else ) แล้วลูปจะทำ

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

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


ฉันชอบคำตอบนี้มาก แต่คุณสามารถทำให้มันง่ายขึ้น: งดendป้ายกำกับและใส่goto loopเข้าไปในifร่างกาย บางทีอาจจะล้าสมัยด้วยการใส่ifบรรทัดเดียวกับป้ายกำกับและทันใดนั้นมันก็ดูคล้ายกับต้นฉบับมาก
Bergi

@Bergi ใช่ฉันคิดว่ามันทำให้ชัดเจนขึ้นหน่อยขอบคุณ
Keiwan

15

ช่วงเวลาที่ gotcha ของฉันพร้อมelseประโยคของลูปคือเมื่อฉันดูการพูดคุยของRaymond Hettingerที่บอกเล่าเรื่องราวเกี่ยวกับวิธีที่เขาคิดว่าควรเรียกnobreakมันว่า ลองดูรหัสต่อไปนี้คุณคิดว่ามันจะทำอะไร?

for i in range(10):
    if test(i):
        break
    # ... work with i
nobreak:
    print('Loop completed')

คุณเดาว่าอะไร ส่วนที่บอกว่าnobreakจะถูกประหารชีวิตถ้าbreakคำสั่งไม่ได้ตีในวง


8

ฉันมักจะคิดว่าโครงสร้างวนรอบเช่นนี้

for item in my_sequence:
    if logic(item):
        do_something(item)
        break

เป็นจำนวนมากเช่นเดียวกับจำนวนตัวแปรif/elifงบ:

if logic(my_seq[0]):
    do_something(my_seq[0])
elif logic(my_seq[1]):
    do_something(my_seq[1])
elif logic(my_seq[2]):
    do_something(my_seq[2])
....
elif logic(my_seq[-1]):
    do_something(my_seq[-1])

ในกรณีนี้elseคำสั่ง on for for ทำงานเหมือนกับelseคำสั่งบน chain of elifs มันจะดำเนินการหากไม่มีเงื่อนไขใด ๆ ก่อนที่มันจะประเมินเป็น True (หรือหยุดการทำงานด้วยreturnหรือยกเว้น) หากลูปของฉันไม่ตรงกับข้อกำหนดนี้ฉันมักจะเลือกที่จะไม่ใช้for: elseด้วยเหตุผลที่แน่นอนที่คุณโพสต์คำถามนี้: มันไม่ง่าย


ขวา. แต่การวนซ้ำทำงานหลายครั้งดังนั้นจึงไม่มีความชัดเจนว่าคุณต้องการใช้สิ่งนี้กับ for-loop อย่างไร คุณช่วยอธิบายได้ไหม
อเล็กซิส

@alexis ฉันได้ทำซ้ำคำตอบของฉันฉันคิดว่ามันชัดเจนมากขึ้นในขณะนี้
Tadhg McDonald-Jensen

7

คนอื่น ๆ ได้อธิบายกลไกของwhile/for...elseแล้วและการอ้างอิงภาษา Python 3มีคำจำกัดความที่เชื่อถือได้ (ดูในขณะที่และสำหรับ ) แต่นี่คือตัวช่วยจำส่วนตัวของฉัน FWIW ฉันเดาว่ากุญแจสำหรับฉันคือการแยกมันออกเป็นสองส่วน: ส่วนหนึ่งสำหรับการทำความเข้าใจความหมายของelseความสัมพันธ์กับเงื่อนไขแบบวนรอบและอีกส่วนหนึ่งสำหรับการทำความเข้าใจการควบคุมแบบวนซ้ำ

ฉันพบว่ามันง่ายที่สุดในการเริ่มต้นด้วยความเข้าใจwhile...else:

whileคุณมีรายการเพิ่มเติมทำสิ่งต่าง ๆelseถ้าหมดทำสิ่งนี้

for...elseช่วยในการจำนั้นเป็นพื้นเดียวกัน:

forทุกรายการทำสิ่งต่าง ๆ แต่elseถ้าคุณหมดทำสิ่งนี้

ในทั้งสองกรณีชิ้นelseส่วนจะเข้าถึงก็ต่อเมื่อไม่มีรายการที่ต้องดำเนินการอีกต่อไปและรายการสุดท้ายได้รับการดำเนินการในลักษณะปกติ (เช่นไม่มีbreakหรือreturn) continueเพียงแค่ไปกลับและเห็นหากมีรายการใด ๆ เพิ่มเติม ตัวช่วยจำของฉันสำหรับกฎเหล่านี้ใช้กับทั้งสองwhileและfor:

เมื่อbreakไอเอ็นจีหรือreturnไอเอ็นจีไม่มีอะไรelseจะทำ
และเมื่อฉันพูดcontinueว่า "ย้อนกลับไปที่จุดเริ่มต้น" สำหรับคุณ

- ด้วยความหมาย "วนกลับไปเริ่มต้น" เห็นได้ชัดว่าเป็นจุดเริ่มต้นของการวนรอบที่เราตรวจสอบว่ามีรายการอื่น ๆ อีกมากใน iterable หรือไม่ตราบใดที่elseมีความเกี่ยวข้องcontinueไม่มีบทบาทเลย


4
ฉันขอแนะนำให้ปรับปรุงให้ดีขึ้นด้วยการบอกว่าจุดประสงค์ปกติของการวนลูปสำหรับ / else คือการตรวจสอบรายการจนกว่าคุณจะพบสิ่งที่คุณกำลังมองหาและต้องการหยุดหรือคุณหมดรายการ มี "else" เพื่อจัดการส่วน "ที่คุณใช้หมดแล้ว (โดยไม่ต้องพบสิ่งที่คุณค้นหา)"
supercat

@supercat: อาจเป็นไปได้ แต่ฉันไม่รู้ว่ามีการใช้งานที่พบบ่อยที่สุดอยู่ที่ใด elseยังสามารถนำมาใช้ในการทำบางสิ่งบางอย่างเมื่อคุณทำเสร็จแล้วก็มีรายการทั้งหมด ตัวอย่างรวมถึงการเขียนรายการบันทึกการปรับปรุงส่วนติดต่อผู้ใช้หรือส่งสัญญาณกระบวนการอื่น ๆ ที่คุณทำ อะไรก็ได้จริง ๆ นอกจากนี้บางส่วนของรหัสมีตัวพิมพ์เล็ก "สำเร็จ" ที่มีbreakการวนรอบด้านในและelseใช้เพื่อจัดการกรณี "ผิดพลาด" ที่คุณไม่พบรายการที่เหมาะสมในระหว่างการทำซ้ำ (อาจเป็นสิ่งที่คุณคิด ของ?).
Fabian Fagerholm

1
กรณีที่ผมคิดว่าเป็นอย่างแม่นยำกรณีที่ประสบความสำเร็จในกรณีที่จบลงด้วยการ "หยุด" และ "อื่น" จับการขาดของความสำเร็จ หากไม่มีการ "หยุด" ภายในลูปรหัส "else" ก็อาจตามลูปเป็นส่วนหนึ่งของบล็อกล้อมรอบ
supercat

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

7

ในการทดสอบที่ขับเคลื่อนด้วยการพัฒนา (TDD) เมื่อใช้Premise Priority Premiseกระบวนทัศน์เป็นอันดับแรกคุณถือว่าลูปเป็นลักษณะทั่วไปของคำสั่งแบบมีเงื่อนไข

วิธีการนี้รวมเข้ากับไวยากรณ์นี้ได้ดีหากคุณพิจารณาคำสั่งที่เรียบง่ายif/else(ไม่elif) เท่านั้น:

if cond:
    # 1
else:
    # 2

พูดคุยกับ:

while cond:  # <-- generalization
    # 1
else:
    # 2

อย่างดี

ในภาษาอื่น ๆ ขั้นตอน TDD จากกรณีเดียวไปจนถึงกรณีที่มีการรวบรวมต้องการการปรับโครงสร้างเพิ่มเติม


นี่คือตัวอย่างจากบล็อก 8thlight :

ในบทความที่เชื่อมโยงที่บล็อก 8thlight จะมีการพิจารณากะตะ Word Wrap: การเพิ่มตัวแบ่งบรรทัดในสตริง ( sตัวแปรในตัวอย่างด้านล่าง) เพื่อให้พอดีกับความกว้างที่กำหนด ( lengthตัวแปรในตัวอย่างด้านล่าง) ณ จุดหนึ่งการใช้งานมีลักษณะดังต่อไปนี้ (Java):

String result = "";
if (s.length() > length) {
    result = s.substring(0, length) + "\n" + s.substring(length);
} else {
    result = s;
}
return result;

และการทดสอบครั้งต่อไปที่ล้มเหลวในปัจจุบันคือ:

@Test
public void WordLongerThanTwiceLengthShouldBreakTwice() throws Exception {
    assertThat(wrap("verylongword", 4), is("very\nlong\nword"));
    }

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

ในขณะที่ลูปไม่สามารถมีelseคำสั่งดังนั้นเราจึงจำเป็นที่จะกำจัดelseเส้นทางโดยการทำน้อยกว่าในifเส้นทาง นี่เป็นการปรับโครงสร้างอีกครั้ง

ซึ่งบังคับให้ทำการเปลี่ยนแปลงรหัสเพิ่มเติมในบริบทของการทดสอบที่ล้มเหลวหนึ่งรายการ:

String result = "";
while (s.length() > length) {
    result += s.substring(0, length) + "\n";
    s = s.substring(length);
}
result += s;

ใน TDD เราต้องการเขียนโค้ดให้น้อยที่สุดเท่าที่จะทำได้เพื่อทำการทดสอบ ด้วยไวยากรณ์ของ Python การเปลี่ยนแปลงต่อไปนี้เป็นไปได้:

จาก:

result = ""
if len(s) > length:
    result = s[0:length] + "\n"
    s = s[length:]
else:
    result += s

ถึง:

result = ""
while len(s) > length:
    result += s[0:length] + "\n"
    s = s[length:]
else:
    result += s

6

วิธีที่ฉันเห็นมันelse:ยิงเมื่อคุณย้ำผ่านจุดสิ้นสุดของลูป

หากคุณbreakหรือreturnหรือraiseคุณทำไม่ได้ย้ำที่ผ่านมาในตอนท้ายของวงที่คุณหยุด immeadiately และทำให้else:บล็อกจะไม่ทำงาน หากคุณcontinueยังคงวนซ้ำในตอนท้ายของลูปนับตั้งแต่ทำต่อไปให้ข้ามไปที่การวนซ้ำครั้งถัดไป มันไม่ได้หยุดลูป


1
ฉันชอบที่ฉันคิดว่าคุณกำลังจะทำอะไรบางอย่าง มันเชื่อมโยงกันเล็กน้อยกับวิธีการวนซ้ำที่ใช้ในวันเก่าก่อนคำหลักวนซ้ำ (กล่าวคือ: เช็คถูกวางไว้ที่ด้านล่างของลูปโดยมีgotoความสำเร็จสูงสุด) แต่เป็นคำตอบที่ได้รับการโหวตให้สั้นลง ...
alexis

@alexis ส่วนตัว แต่ฉันคิดว่าวิธีการแสดงมันง่ายกว่าที่จะคิด
Winston Ewert

ที่จริงฉันเห็นด้วย ถ้าเพียงเพราะมันเปี่ยมไปด้วยพลัง
alexis

4

คิดว่าelseประโยคเป็นส่วนหนึ่งของการสร้างห่วง breakแยกออกจากวงสร้างทั้งหมดและข้ามelseประโยค

แต่จริงๆแล้วการทำแผนที่จิตของฉันเป็นเพียงว่าเป็นรูปแบบ 'โครงสร้าง' ของรูปแบบ C / C ++:

  for (...) {
    ...
    if (test) { goto done; }
    ...
  }
  ...
done:
  ...

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

(ฉันใส่ 'โครงสร้าง' ในราคาที่ทำให้ตกใจเพราะความแตกต่างไม่ใช่ว่ารหัสนั้นมีโครงสร้างหรือไม่มีโครงสร้าง แต่เพียงว่ามีคำหลักและไวยากรณ์ที่อุทิศให้กับโครงสร้างนั้นหรือไม่)


1
ในกรณีที่เป็นelse? หากคุณหมายถึงdone:ฉลากที่จะยืน proxy หรือelse:ฉันเชื่อว่าคุณมีมันย้อนหลัง
alexis

@alexis รหัส 'อื่น ๆ' จะเติมใน '...' ทันทีก่อนdone:ฉลาก จดหมายโดยรวมอาจจะดีที่สุดกล่าวดังนี้: งูหลามมีelseโครงสร้าง -ON gotoวงเพื่อให้คุณสามารถแสดงรูปแบบการไหลการควบคุมนี้ได้โดยไม่ต้อง
zwol

มีวิธีอื่น ๆ ในการดำเนินการรูปแบบการไหลของการควบคุมนี้เช่นโดยการตั้งค่าสถานะ นั่นคือสิ่งที่elseหลีกเลี่ยง
alexis

2

หากคุณจับคู่elseกับforมันอาจสร้างความสับสน ฉันไม่คิดว่าคำหลักelseเป็นตัวเลือกที่ยอดเยี่ยมสำหรับไวยากรณ์นี้ แต่ถ้าคุณจับคู่elseกับifที่มีอยู่breakคุณจะเห็นว่ามันสมเหตุสมผลดี elseมีประโยชน์น้อยมากหากไม่มีifคำสั่งก่อนหน้านี้และฉันเชื่อว่านี่เป็นสาเหตุที่ผู้ออกแบบไวยากรณ์เลือกคำหลัก

ขอผมสาธิตมันเป็นภาษามนุษย์

forบุคคลในกลุ่มผู้ต้องสงสัยifทุกคนเป็นอาชญากร breakในการสอบสวน elseรายงานความล้มเหลว


1

วิธีที่ฉันคิดเกี่ยวกับมันที่สำคัญคือการพิจารณาความหมายของมากกว่าcontinueelse

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

จากนั้นคุณก็ต้องจำไว้ว่าelseประโยคนั้นจะถูกดำเนินการหลังจากการยกเลิกลูปปกติ


0
# tested in Python 3.6.4
def buy_fruit(fruits):
    '''I translate the 'else' below into 'if no break' from for loop '''
    for fruit in fruits:
        if 'rotten' in fruit:
            print(f'do not want to buy {fruit}')
            break
    else:  #if no break
        print(f'ready to buy {fruits}')


if __name__ == '__main__':
    a_bag_of_apples = ['golden delicious', 'honeycrisp', 'rotten mcintosh']
    b_bag_of_apples = ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
    buy_fruit(a_bag_of_apples)
    buy_fruit(b_bag_of_apples)

'''
do not want to buy rotten mcintosh
ready to buy ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
'''
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.