เพิ่มข้อยกเว้นกับผลตอบแทนไม่มีในฟังก์ชัน?


87

สิ่งที่ดีกว่าในฟังก์ชันที่ผู้ใช้กำหนดเองใน Python: raiseข้อยกเว้นหรือreturn None? ตัวอย่างเช่นฉันมีฟังก์ชันที่ค้นหาไฟล์ล่าสุดในโฟลเดอร์

def latestpdf(folder):
    # list the files and sort them
    try:
        latest = files[-1]
    except IndexError:
        # Folder is empty.
        return None  # One possibility
        raise FileNotFoundError()  # Alternative
    else:
        return somefunc(latest)  # In my case, somefunc parses the filename

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



3
ฉันเอนเอียงไปที่การเพิ่มข้อยกเว้นดังนั้นฉันจึงถูกบังคับให้จัดการกับข้อยกเว้นในฟังก์ชันการโทร หากฉันลืมตรวจสอบว่าเอาต์พุตไม่มีในฟังก์ชันการโทรหรือไม่ฉันอาจมีบั๊กแฝงอยู่ หากคุณส่งคืน None หวังว่าบรรทัดถัดไปในฟังก์ชันการโทรจะเพิ่ม AttributeError อย่างไรก็ตามหากค่าที่ส่งคืนถูกเพิ่มลงในพจนานุกรมแล้วเรียกใช้ฟังก์ชัน 100 รายการในไฟล์ต้นฉบับที่แตกต่างกัน AttributeError จะเพิ่มขึ้นคุณจะสนุกกับการค้นหาว่าเหตุใดค่านั้นจึงเป็นไม่มี
IceArdor

โดยทั่วไปฉันยังหลีกเลี่ยงค่าที่มีความหมายพิเศษหรือมีหลายลายเซ็นสำหรับฟังก์ชันเดียว (อาจส่งคืนสตริงหรือไม่มีก็ได้)
IceArdor

คำตอบ:


92

มันเป็นเรื่องของความหมายจริงๆ อะไรfoo = latestpdf(d) หมายถึง ?

สมเหตุสมผลหรือไม่ที่ไม่มีไฟล์ล่าสุด? จากนั้นให้แน่ใจว่ากลับไม่มี

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

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


3
อีกจุดหนึ่งที่จะต้องพิจารณา: ถ้าเพิ่มข้อยกเว้นข้อความสามารถแนบ Noneแต่เราไม่สามารถทำเช่นนั้นเมื่อกลับ
kawing-chiu

10

ฉันจะให้คำแนะนำสองสามข้อก่อนที่จะตอบคำถามของคุณเนื่องจากอาจตอบคำถามของคุณได้

  • ตั้งชื่อฟังก์ชันของคุณให้สื่อความหมายเสมอ latestpdfมีความหมายน้อยมากสำหรับทุกคน แต่เมื่อมองข้ามฟังก์ชันของคุณlatestpdf()จะได้รับ pdf ล่าสุด getLatestPdfFromFolder(folder)ผมขอแนะนำว่าคุณชื่อมัน

ทันทีที่ฉันทำสิ่งนี้ก็ชัดเจนว่าควรจะคืนอะไร .. หากไม่มี pdf จะเพิ่มข้อยกเว้น แต่เดี๋ยวก่อน ..

  • กำหนดฟังก์ชันให้ชัดเจน เนื่องจากไม่ชัดเจนว่า somefuc ควรจะทำอย่างไรและไม่ชัดเจนว่าเกี่ยวข้องกับการรับ pdf ล่าสุดอย่างไรฉันขอแนะนำให้คุณย้ายออก ทำให้โค้ดอ่านง่ายขึ้นมาก

for folder in folders:
   try:
       latest = getLatestPdfFromFolder(folder)
       results = somefuc(latest)
   except IOError: pass

หวังว่านี่จะช่วยได้!


1
หรือget_latest_pdf_from_folder. อันที่จริง Pep8: "ชื่อฟังก์ชันควรเป็นตัวพิมพ์เล็กโดยมีคำคั่นด้วยเครื่องหมายขีดล่างเท่าที่จำเป็นเพื่อปรับปรุงความสามารถในการอ่าน"
PatrickT

7

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

  1. ใครก็ตามที่เรียกใช้ฟังก์ชันของคุณจะไม่ได้รับแจ้งถึงข้อยกเว้นที่สามารถโยนทิ้งได้ มันกลายเป็นรูปแบบศิลปะเล็กน้อยที่จะรู้ว่าคุณกำลังตามล่าหาข้อยกเว้นประเภทใด (และทั่วไปยกเว้นบล็อกควรหลีกเลี่ยง)
  2. if val is Noneง่ายกว่าexcept ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpaceเล็กน้อย อย่างจริงจังฉันเกลียดที่ต้องจำไว้ว่าให้พิมพ์from django.core.exceptions import ObjectDoesNotExistที่ด้านบนของไฟล์ django ทั้งหมดของฉันเพื่อจัดการกับกรณีการใช้งานทั่วไปจริงๆ ในโลกที่มีการพิมพ์แบบคงที่ให้ตัวแก้ไขจัดการแทนคุณ

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

AttributeError: 'NoneType' object has no attribute 'foo'

ซึ่งเก้าครั้งในสิบครั้งคือสิ่งที่ผู้โทรจะเห็นว่าคุณส่งคืนโดยไม่ได้รับการจัดการใด ๆ ไม่ต้องกังวล

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


อาร์กิวเมนต์ที่ไม่ได้กำหนดข้อยกเว้นที่เป็นไปได้และยากที่จะตรวจจับได้คืออาร์กิวเมนต์ที่ถูกต้องสำหรับ Python
snorberhuis

4

ด้วยการพิมพ์ของ python 3.5 :

ฟังก์ชันตัวอย่างเมื่อส่งคืนไม่มีจะเป็น:

def latestpdf(folder: str) -> Union[str, None]

และเมื่อเพิ่มข้อยกเว้นจะเป็น:

def latestpdf(folder: str) -> str 

ตัวเลือกที่ 2 ดูเหมือนอ่านได้ง่ายกว่าและเป็น pythonic

(+ ตัวเลือกเพื่อเพิ่มความคิดเห็นในข้อยกเว้นตามที่ระบุไว้ก่อนหน้านี้)


5
Union[str, None]ควรจะเป็นOptional[str]
Georgy

2
ชวเลข แต่คุณพูดถูกมันอ่านง่ายกว่า ไม่ได้แก้ไขดังนั้นทั้งสองตัวเลือกจึงอยู่ที่นี่
Asaf

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

2

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

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