استثناها روشی قدرتمند و دلپذیر برای مدیریت خطاها در برنامه های پایتون شما هستند. استثناهای سفارشی این قدرت را به سطح جدیدی می برد.
کلاسهای استثنای داخلی پایتون به موقعیتهای خطای خاصی که ممکن است در کد شما ایجاد شود رسیدگی نمیکنند. در چنین مواردی، برای مدیریت موثر این خطاها باید استثناهای سفارشی ایجاد کنید.
در پایتون، میتوانید استثناهای سفارشی را تعریف کنید و در صورت بروز موقعیتهای خطای خاص، آنها را افزایش دهید. شما می توانید خطاهای خاص و اطلاعاتی را با استثناهای سفارشی مدیریت کنید و خوانایی و نگهداری کد خود را بهبود ببخشید.
چرا به استثناهای سفارشی نیاز دارید؟
در طول توسعه یک برنامه، سناریوهای خطای مختلفی ممکن است به دلیل تغییر در کد، ادغام با سایر بسته ها یا کتابخانه ها و تعامل با برنامه های خارجی ایجاد شود. رسیدگی به این خطاها برای بازیابی از آنها یا مدیریت با ظرافت شکست بسیار مهم است.
پایتون مجموعه ای از کلاس های استثنا داخلی را ارائه می دهد که خطاهایی مانند ValueError، TypeError، FileNotFoundError و غیره را پوشش می دهد. در حالی که این استثناهای داخلی به خوبی به هدف خود عمل می کنند، ممکن است فقط گاهی اوقات خطاهایی را که ممکن است در برنامه شما رخ دهد به دقت نشان دهند.
با ایجاد استثناهای سفارشی، می توانید آنها را به طور خاص متناسب با نیازهای برنامه خود تنظیم کنید و اطلاعاتی را برای توسعه دهندگانی که از کد شما استفاده می کنند ارائه دهید.
نحوه تعریف استثناهای سفارشی
برای ایجاد استثناهای سفارشی، یک کلاس پایتون تعریف کنید که از کلاس Exception به ارث می برد. کلاس Exception عملکرد پایه ای را ارائه می دهد که برای رسیدگی به استثناها به آن نیاز دارید، و می توانید آن را برای اضافه کردن ویژگی ها بر اساس نیازهای خاص خود سفارشی کنید.
هنگام ایجاد کلاسهای استثنای سفارشی، آنها را ساده نگه دارید و در عین حال ویژگیهای لازم برای ذخیره اطلاعات خطا را در نظر بگیرید. سپس کنترل کننده های استثنا می توانند به این ویژگی ها دسترسی داشته باشند تا خطاها را به درستی مدیریت کنند.
در اینجا یک کلاس استثنای سفارشی، MyCustomError وجود دارد:
class MyCustomError(Exception):
def __init__(self, message=None):
self.message = message
super().__init__(message)
این کلاس یک آرگومان پیام اختیاری را در طول مقداردهی اولیه می پذیرد. از متد super() برای فراخوانی سازنده کلاس Exception استفاده می کند که برای مدیریت استثنا ضروری است.
چگونه استثناهای سفارشی را افزایش دهیم
برای ایجاد یک خطا، از کلمه کلیدی raise و به دنبال آن یک نمونه از کلاس استثنای سفارشی خود استفاده کنید و یک پیام خطا به عنوان آرگومان ارسال کنید:
if True:
raise MyCustomError("A Custom Error Was Raised!!!.")
همچنین میتوانید خطا را بدون ارسال هیچ آرگومان مطرح کنید:
if True:
raise MyCustomError # shorthand
هر یک از فرمت ها برای بالا بردن خطاهای سفارشی مناسب است.
نحوه رسیدگی به استثناهای سفارشی
رسیدگی به استثناهای سفارشی از همان رویکردی پیروی می کند که مدیریت استثناهای داخلی. برای گرفتن استثناهای سفارشی و انجام اقدامات مناسب، از try، استثنا و در نهایت از بلوکها استفاده کنید.
try:
print("Hello, You're learning how to MakeUseOf Custom Errors")
raise MyCustomError("Opps, Something Went Wrong!!!.")
except MyCustomError as err:
print(f"Error: {err}")
finally:
print("Done Handling Custom Error")
به این ترتیب، شما می توانید تمام اشکال استثناهای سفارشی مطرح شده را مدیریت کنید.
اگر یک استثنا در طول اجرای یک بلوک try رخ دهد، یک بلوک غیر مربوطه می تواند آن را بگیرد و مدیریت کند. اگر بلوک غیر مناسبی برای مدیریت استثنا وجود نداشته باشد، هر بلوک نهایی اجرا میشود و به دنبال آن استثنا دوباره افزایش مییابد. از یک بلوک نهایی در درجه اول برای انجام کارهای پاکسازی استفاده کنید که باید در هر شرایطی اجرا شوند، چه استثنایی رخ دهد یا نه.
try:
raise KeyboardInterrupt
except MyCustomError as err:
print(f"Error: {err}")
finally:
print("Did not Handle the KeyboardInterrupt Error. \
Can Only Handle MyCustomError")
در این نمونه، یک استثنا KeyboardInterrupt رخ می دهد، اما بلوک استثنا فقط استثناهای MyCustomError را کنترل می کند. در این حالت، بلوک نهایی اجرا می شود و سپس استثنای unhandled دوباره بالا می رود.
ارث بردن کلاس های خطای سفارشی
بر اساس مفهوم برنامه نویسی شی گرا (OOP)، شما همچنین می توانید از کلاس های استثنای سفارشی مانند کلاس های معمولی ارث بری داشته باشید. با ارث بردن از یک کلاس استثنای سفارشی، می توانید کلاس های خطا ایجاد کنید که زمینه خاص تری را برای یک استثنا فراهم می کند. این رویکرد به شما اجازه می دهد تا خطاها را در سطوح مختلف در کد خود مدیریت کنید و درک بهتری از آنچه باعث خطا شده است را فراهم می کند.
فرض کنید در حال توسعه یک برنامه وب هستید که با یک API خارجی تعامل دارد. این 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}")
بند پایانی غیر از کلاس والد بررسی میشود و بهعنوان یک نشانهگیر برای سایر خطاهای مرتبط با API عمل میکند.
وقتی کلاسهای استثنای سفارشی را به ارث میبرید، میتوانید بهطور مؤثر خطاها را در API مدیریت کنید. این رویکرد به شما این امکان را میدهد تا مدیریت خطا را از جزئیات پیادهسازی API جدا کنید، و اضافه کردن استثناهای سفارشی یا ایجاد تغییرات را با تکامل API یا مواجهه با موارد خطای جدید آسانتر میکند.
بسته بندی استثناهای سفارشی
قرار دادن استثناها به معنای گرفتن یک استثنا، کپسوله کردن آن در یک استثنای سفارشی و سپس بالا بردن آن استثنای سفارشی در حالی است که به استثنای اصلی به عنوان علت آن اشاره می شود. این تکنیک به ارائه زمینه پیام های خطا کمک می کند و جزئیات پیاده سازی را از کد فراخوان پنهان نگه می دارد.
سناریویی را در نظر بگیرید که در آن برنامه وب شما با یک API تعامل دارد. اگر API یک LookupError را ایجاد کرد، می توانید آن را پیدا کنید، سپس یک استثنای سفارشی APINotFoundError را ایجاد کنید که به 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__}")
از یک عبارت from با عبارت raise برای ارجاع به استثنای اصلی در استثنای سفارشی خود استفاده کنید.
هنگامی که استثنای سفارشی رخ می دهد، استثنای اصلی را به عنوان یک ویژگی __cause__ شامل می شود که پیوندی بین استثنا سفارشی و اصلی ایجاد می کند. این به شما امکان می دهد منشا یک استثنا را ردیابی کنید.
با بسته بندی استثناها، می توانید زمینه معنادارتری ارائه دهید و پیام های خطای مناسب تری را برای کاربران ارسال کنید، بدون اینکه جزئیات پیاده سازی داخلی کد یا API خود را فاش کنید. همچنین به شما امکان می دهد انواع خطاها را به روشی ساختاریافته و یکسان مدیریت و رسیدگی کنید.
سفارشی کردن رفتار کلاس در پایتون
با به ارث بردن کلاس استثنای پایه ای که پایتون ارائه می کند، می توانید استثناهای ساده و مفیدی ایجاد کنید که می توانید در صورت بروز خطاهای خاص در کد خود، آن ها را مطرح کنید. شما همچنین می توانید رفتار سفارشی را برای کلاس های استثنای خود با کمک روش های magic یا dunder پیاده سازی کنید.