หลักการ EAFP ใน Python คืออะไร?


คำตอบ:


223

จากอภิธานศัพท์ :

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

ตัวอย่างเช่นการพยายามเข้าถึงคีย์พจนานุกรม

EAFP:

try:
    x = my_dict["key"]
except KeyError:
    # handle missing key

ปอนด์:

if "key" in my_dict:
    x = my_dict["key"]
else:
    # handle missing key

เวอร์ชัน LBYL ต้องค้นหาคีย์ภายในพจนานุกรมสองครั้งและอาจถือว่าอ่านได้น้อยกว่าเล็กน้อย


36
การเพิ่มประสิทธิภาพจะเป็นข้อดีอีกอย่างหนึ่งคือการหลีกเลี่ยงเงื่อนไขการแข่งขัน ... เช่นลองเปิดไฟล์และถ้าคุณได้รับคุณก็จะได้รับมัน แทนที่จะดูว่าคุณสามารถรับมันได้หรือไม่จากนั้นพยายามที่จะรับมันในภายหลังและตระหนักว่าในระยะเวลาสั้น ๆ ระหว่างการตรวจสอบและการเข้าถึงสัญญาณคุณสามารถรับได้นาน
Jon Clements

24
Python ยังมีวิธีหลีกเลี่ยงทั้งสองอย่างหากตัวจัดการเพียงแค่กำหนดค่าเริ่มต้นให้xเมื่อไม่มีคีย์: x = mydict.get('key')จะส่งคืนNoneหาก'key'ไม่ได้อยู่ในmy_dict; คุณสามารถทำได้.get('key', <something>)จากนั้น x จะถูกกำหนดให้บางอย่างถ้าคีย์ไม่ได้อยู่ในพจนานุกรม dict.setdefault()และcollections.defaultdictเป็นสิ่งที่ดีสำหรับการหลีกเลี่ยงโค้ดส่วนเกินเช่นกัน
JAB

1
ผมคิดว่าexcept KeyErrorเช่นเดียวกับการAttributeErrorที่เรียบง่าย แต่บางตัวอย่างที่เลวร้ายที่สุด หลายครั้งที่ฉันติดอยู่ในการดีบักบางสิ่งบางอย่างเพราะexcept AttributeErrorใส่ผิดตำแหน่งซึ่งท้ายที่สุดแล้วการจับข้อผิดพลาดของแอตทริบิวต์ที่ไม่ถูกต้องทำให้ลึกลงไปในห่วงโซ่ ตัวอย่างที่ดีกว่าที่ฉันคิดคือ: try: open() ... except: IOError. หรือtry: parseLine() ... except ParseError
Ski

4
@ski นั่นเป็นปัญหาที่แตกต่างกันเล็กน้อย คุณควรเสมอให้ลองบล็อกน้อยที่สุดเท่าที่จะหลีกเลี่ยงการจับข้อยกเว้นที่ไม่ถูกต้อง โปรดทราบว่าโดยทั่วไปฉันไม่ชอบสไตล์ EAFP ฉันแค่ตอบคำถามที่นี่และระบุว่าบางคนชอบ ฉันคิดเป็นกรณี ๆ ไปว่ารหัสใดที่ฉันอ่านได้มากที่สุด
Sven Marnach

1
ฉันคิดว่ามันคุ้มค่าที่จะกล่าวถึงว่าGrace Hopperน่าจะเป็นที่มาของวลีนี้โดยมีคำพูดของเธอ: "Dare and Do การขอการให้อภัยง่ายกว่าการขออนุญาต" (ไม่ จำกัด เฉพาะการเขียนโปรแกรม)
Fabien Snauwaert

11

ฉันจะพยายามอธิบายด้วยตัวอย่างอื่น

ที่นี่เรากำลังพยายามเข้าถึงไฟล์และพิมพ์เนื้อหาในคอนโซล

LBYL - ดูก่อนกระโดด:

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

import os

my_file = "/path/to/my/file.txt"

# Race condition
if os.access(my_file, os.R_OK):
    with open(my_file) as f:
        print(f.read())
else:
    print("File can't be accessed")

EAFP - ขอการให้อภัยได้ง่ายกว่าการอนุญาต:

ในตัวอย่างนี้เราแค่พยายามเปิดไฟล์และถ้าเปิดไม่ได้มันจะโยนIOErrorไฟล์. ถ้าทำได้เราจะเปิดไฟล์และพิมพ์เนื้อหา ดังนั้นแทนที่จะถามบางสิ่งที่เรากำลังพยายามทำอยู่ ถ้าได้ผลเยี่ยม! หากเราไม่จับข้อผิดพลาดและจัดการกับมัน

# # No race condition
try:
    f = open(my_file)
except IOError as e:
    print("File can't be accessed")
else:
    with f:
        print(f.read())

ฉันไม่แน่ใจว่าถูกต้องที่จะอธิบายว่านี่เป็นสภาพการแข่งขัน ไฟล์นั้นสามารถเข้าถึงได้หรือไม่
ds4940

3
@ ds4940 เป็นเงื่อนไขการแย่งชิงหากความสามารถในการเข้าถึงไฟล์เปลี่ยนไประหว่างบรรทัดที่ 6 และ 7 ซึ่งอยู่ระหว่างการตรวจสอบว่าไฟล์สามารถเข้าถึงได้และเปิดหรือไม่
Markus von Broady

@MarkusvonBroady เห็นด้วยแก้ไขคำตอบเพื่อเป็นตัวอย่างของผู้เข้าร่วมรายอื่นในสภาพการแข่งขัน
ds4940

7

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

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

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