Contents

วิธีสร้างข้อยกเว้นแบบกำหนดเองใน Python

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

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

ทำไมคุณถึงต้องการข้อยกเว้นแบบกำหนดเอง?

/th/images/own-you-error.jpg

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

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

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

วิธีกำหนดข้อยกเว้นแบบกำหนดเอง

หากต้องการสร้างข้อยกเว้นที่กำหนดเอง ให้กำหนดคลาส Python ที่สืบทอดมาจาก Exception class คลาส Exception นำเสนอฟังก์ชันการทำงานพื้นฐานที่คุณจะต้องจัดการกับข้อยกเว้น และคุณสามารถปรับแต่งเพื่อเพิ่มคุณสมบัติตามความต้องการเฉพาะของคุณได้

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

นี่คือคลาสข้อยกเว้นที่กำหนดเอง MyCustomError:

 class MyCustomError(Exception):
    def __init__(self, message=None):
        self.message = message
        super().__init__(message)

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

วิธีเพิ่มข้อยกเว้นแบบกำหนดเอง

อันที่จริง เพื่อล้วงเอาอุปสรรคและสร้างอินสแตนซ์ของหมวดหมู่ข้อยกเว้นที่ปรับแต่งโดยเฉพาะของเรา คุณอาจใช้คีย์เวิร์ด"เพิ่ม"ร่วมกับตัวอย่างประเภทข้อยกเว้นที่ตรงตามความต้องการของคุณ โดยระบุข้อความที่สรุปลักษณะของปัญหา:

 if True:
    raise MyCustomError("A Custom Error Was Raised!!!.")

เราอาจเลือกที่จะนำข้อยกเว้นมาโดยไม่มีข้อโต้แย้งใด ๆ

 if True:
    raise MyCustomError # shorthand

ทั้งสองรูปแบบมีความเหมาะสมเท่าเทียมกันสำหรับการสร้างข้อความแสดงข้อผิดพลาดแบบกำหนดเอง

/th/images/raised-custom-error.jpg

วิธีจัดการกับข้อยกเว้นที่กำหนดเอง

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

 try:
    print("Hello, You're learning how to All Things N Custom Errors")
    raise MyCustomError("Opps, Something Went Wrong!!!.")
except MyCustomError as err:
    print(f"Error: {err}")
finally:
    print("Done Handling Custom Error")

ในลักษณะนี้ เราพร้อมที่จะจัดการกับข้อยกเว้นพิเศษทุกประเภทเท่าที่จะเป็นไปได้ที่อาจเกิดขึ้น

/th/images/handling-custom-error.jpg

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

 try:
    raise KeyboardInterrupt
except MyCustomError as err:
    print(f"Error: {err}")
finally:
    print("Did not Handle the KeyboardInterrupt Error. \
Can Only Handle MyCustomError")

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

/th/images/re-raise-unhandled-exception.jpg

การสืบทอดคลาสข้อผิดพลาดแบบกำหนดเอง

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

เพื่อให้มั่นใจว่าการจัดการสถานการณ์ข้อผิดพลาดต่างๆ สอดคล้องกันในการผสานรวม API ภายนอกภายในเว็บแอปพลิเคชัน ขอแนะนำให้สร้างแนวทางที่เป็นมาตรฐานโดยการสร้างคลาสข้อยกเว้นเฉพาะที่เรียกว่า BaseAPIException

 class BaseAPIException(Exception):
    """Base class for API-related exceptions."""
    def __init__(self, message):
        super().__init__(message)
        self.message = message

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

 class APINotFoundError(BaseAPIException):
    """Raised when the requested resource is not found in the API."""
    pass

class APIAuthenticationError(BaseAPIException):
    """Raised when there's an issue with authentication to the API."""
    pass

class APIRateLimitExceeded(BaseAPIException):
    """Raised when the rate limit for API requests is exceeded."""
    pass

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

 def request_api():
    try:
        # Simulate an API error for demonstration purposes
        raise APINotFoundError("Requested resource not found.")
    except APINotFoundError as err:
        # Log or handle the 'Not Found' error case
        print(f"API Not Found Error: {err}")
    except APIAuthenticationError:
        # Take appropriate actions for authentication error
        print(f"API Authentication Error: {err}")
    except APIRateLimitExceeded:
        # Handle the rate limit exceeded scenario
        print(f"API Rate Limit Exceeded: {err}")
    except BaseAPIException:
        # Handle other unknown API exceptions
        print(f"Unknown API Exception: {err}") 

ส่วนคำสั่ง ยกเว้น สุดท้ายมีหน้าที่รับผิดชอบในการจับข้อยกเว้นใด ๆ ที่อาจเกิดขึ้นจากภายในคลาสพาเรนต์ โดยทำหน้าที่เป็นตัวจัดการข้อผิดพลาดที่ครอบคลุมทั้งหมดสำหรับปัญหาที่ไม่คาดคิดใด ๆ ที่เกี่ยวข้องกับ Application Programming Interface (API)

/th/images/inheriting-custom-exception.jpg

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

การตัดข้อยกเว้นที่กำหนดเอง

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

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

 def request_api():
    try:
        # Simulate an API error for demonstration purposes
        # Assuming the external API raised a LookupError
        raise LookupError("Sorry, You Encountered A LookUpError !!!")
    except LookupError as original_exception:
        try:
            # Wrap the original exception with a custom exception
            raise APINotFoundError \
                 ("Requested resource not found.") from original_exception
        except APINotFoundError as wrapped_exception:
            # Handle the wrapped exception here
             print(f"Caught wrapped API exception: {wrapped_exception}")

            # or re-raise it if necessary
            raise

try:
    request_api()
except APINotFoundError as err:
    print(f"Caught API exception: {err.__cause__}")

ใช้ประโยค “จาก” ร่วมกับคำสั่ง “raise” เพื่อกล่าวถึงข้อยกเว้นเริ่มต้นภายในข้อยกเว้นที่คุณปรับแต่งเอง

/th/images/wrapping-custom-exception.jpg

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

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

การปรับแต่งพฤติกรรมของคลาสใน Python

ด้วยการสืบทอดคลาสข้อยกเว้นพื้นฐานที่จัดทำโดย Python เราสามารถพัฒนาข้อยกเว้นขั้นพื้นฐานที่มีประสิทธิภาพซึ่งจะถูกหยิบยกขึ้นในระหว่างการเกิดข้อผิดพลาดเฉพาะภายในโค้ดของพวกเขา นอกจากนี้ ด้วยการใช้วิธีเวทย์มนตร์หรือ"ดันเดอร์"พฤติกรรมที่กำหนดเองอาจถูกสร้างขึ้นสำหรับคลาสข้อยกเว้นของตัวเอง