การใช้คำสั่ง python“ with” กับ try-except block


101

นี่เป็นวิธีที่ถูกต้องในการใช้คำสั่ง python "with" ร่วมกับ try-except block หรือไม่:

try:
    with open("file", "r") as f:
        line = f.readline()
except IOError:
    <whatever>

หากเป็นเช่นนั้นให้พิจารณาวิธีการทำสิ่งต่างๆแบบเก่า:

try:
    f = open("file", "r")
    line = f.readline()
except IOError:
    <whatever>
finally:
    f.close()

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

แก้ไข: การทำงานของโค้ดสองบล็อกข้างต้นเหมือนกันหรือไม่

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



สำหรับฉันการไม่ต้องจำปิด () สิ่งต่างๆในข้อความสุดท้ายเป็นเหตุผลที่ดีพอที่จะใช้ 'with' ฉันเห็นโค้ดจำนวนมากล้มเหลวในการปิดทรัพยากร และ 'ด้วย' ไม่มีข้อบกพร่องเท่าที่ฉันเห็น
Raúl Salinas-Monteagudo

คำตอบ:


145
  1. รหัสสองบล็อกที่คุณให้ ไม่เทียบเท่ากัน
  2. รหัสที่คุณอธิบายว่าเป็นวิธีการทำงานแบบเก่ามีข้อบกพร่องร้ายแรง: ในกรณีที่การเปิดไฟล์ล้มเหลวคุณจะได้รับข้อยกเว้นที่สองใน finallyประโยคเนื่องจากfไม่ถูกผูก

รหัสแบบเก่าที่เทียบเท่าจะเป็น:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

อย่างที่คุณเห็นwithคำสั่งสามารถทำให้ข้อผิดพลาดน้อยลง ใน Python เวอร์ชันใหม่กว่า (2.7, 3.1) คุณยังสามารถรวมหลายนิพจน์ไว้ในwithคำสั่งเดียวได้ ตัวอย่างเช่น:

with open("input", "r") as inp, open("output", "w") as out:
    out.write(inp.read())

นอกจากนั้นโดยส่วนตัวแล้วฉันถือว่าเป็นนิสัยที่ไม่ดีที่จะจับข้อยกเว้นใด ๆ ให้เร็วที่สุด นี่ไม่ใช่จุดประสงค์ของข้อยกเว้น หากฟังก์ชัน IO ที่สามารถล้มเหลวเป็นส่วนหนึ่งของการดำเนินการที่ซับซ้อนมากขึ้นในกรณีส่วนใหญ่ IOError ควรยกเลิกการดำเนินการทั้งหมดดังนั้นจึงต้องจัดการในระดับภายนอก การใช้withคำสั่งคุณสามารถกำจัดข้อความเหล่านี้ทั้งหมดtry...finallyได้ในระดับภายใน


7

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

และใช่วิธีที่คุณรวมเข้าด้วยกันwithและtry-exceptเป็นวิธีเดียวที่จะทำได้เนื่องจากข้อผิดพลาดพิเศษที่เกิดจากopenคำสั่งนั้นไม่สามารถจับได้ภายในwithบล็อก


1

ฉันคิดว่าคุณเข้าใจผิดเกี่ยวกับคำสั่ง "ด้วย" ที่ลดเฉพาะบรรทัด มันทำการเริ่มต้นและจัดการกับการฉีกขาด

ในกรณีของคุณ "ด้วย" ไม่

  • เปิดไฟล์
  • ประมวลผลเนื้อหาและ
  • อย่าลืมปิด

ลิงค์สำหรับทำความเข้าใจคำสั่ง "with": http://effbot.org/zone/python-with-statement.htm

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


-4

วิธี Pythonic เพิ่มเติมสำหรับรหัสต่อไปนี้คือ:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

try:
    f = open("file", "r")
except IOError:
    <whatever>
else:
    f.close()

1
ฉันได้เพิ่มการจัดรูปแบบโค้ดให้คุณแล้ว ทำให้อ่านง่ายขึ้น แต่คุณอาจต้องการตรวจสอบอีกครั้งเพื่อให้แน่ใจว่าฉันไม่ได้หักการเยื้อง
andrewsi

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