در دنیای برنامهنویسی، خطاها و استثناءها بخشی از روند طبیعی توسعه نرمافزار هستند. این استثناها در هنگام اجرای برنامه ممکن است رخ دهند و برنامه را از حالت اجرا متوقف کنند. برای مدیریت و کنترل این استثناها و جلوگیری از توقف برنامه، در زبانهای برنامهنویسی ابزارهایی به نام مدیریت استثنا (Exception Handling) وجود دارد. در این مقاله، با مدیریت استثنا در پایتون آشنا خواهیم شد. همچنین پیشنهاد میکنیم از دیگر آموزشهای ما نیز دیدن فرمایید:
- لیست و نحوه کار با آن
- دیکشنری در پایتون
- Tuple در پایتون
- if در پایتون
- حلقه for
- حلقه while
- تابع در پایتون
- تبدیل نوع داده
چرا باید استثناها را مدیریت کنیم؟
قبل از اینکه به جزئیات مدیریت استثنا در پایتون بپردازیم، باید بدانیم که چرا مدیریت استثناها مهم است. برنامهنویسان باید به برنامههای خود قابلیت مدیریت و کنترل استثناها را اضافه کنند زیرا:
- انعطافپذیری بیشتر: با مدیریت استثناها، میتوان برنامه را به گونهای طراحی کرد که به متوقف شدن نیاز نداشته باشد و به جای آن با خطاها برخورد(مدیریت) کند و به اجرای عادی برنامه ادامه دهد.
- رفع مشکلات: مدیریت استثناها به برنامهنویسان امکان رفع مشکلات را میدهد. با داشتن اطلاعات دقیق در مورد خطاها و استثناها، میتوان بهترین راه حل را پیدا کرد.
- حفاظت از اطلاعات: در برنامههای واقعی، ممکن است دادههای مهم و حساسی در خطر باشند. با مدیریت استثناها میتوان از انتشار نادرست دادهها جلوگیری کرد و از امنیت اطلاعات محافظت کرد.
انواع مدیریت استثنا در پایتون
پایتون دارای مجموعهای از استثناهای پیشفرض است که به طور خودکار در هنگام اجرا ایجاد میشوند. این استثناها به دستهبندیهای مختلفی تقسیم میشوند. برخی از مهمترین دستههای استثناها در پایتون عبارتند از:
SyntaxError
: این استثنا در هنگام وجود مشکلات در نحوه نوشتاری کد (مانند خطاهای نحوه نوشتاری) ایجاد میشود.IndentationError
: در هنگام وجود مشکلات در تورفتگی (Indentation) کد ایجاد میشود.NameError
: این استثنا در هنگام استفاده از یک متغیر یا نام تابعی که تعریف نشده باشد ایجاد میشود.TypeError
: هنگام اجرای عملیاتهای نامتناسب برای نوع دادهای که دارید ایجاد میشود.ValueError
: در هنگام وجود مشکلات در مقدار یک ورودی یا آرگومان ایجاد میشود.FileNotFoundError
: هنگام تلاش برای دسترسی به یک فایل که وجود ندارد ایجاد میشود.ZeroDivisionError
: این استثنا در هنگام تقسیم یک عدد به صفر ایجاد میشود.IndexError
: این استثنا در هنگام دسترسی به یک عنصر در یک لیست یا دنباله با استفاده از یک اندیس نامعتبر ایجاد میشود.KeyError
: این استثنا در هنگام دسترسی به یک کلید ناموجود در یک دیکشنری ایجاد میشود.AttributeError
: این استثنا در هنگام تلاش برای دسترسی به یک ویژگی یا متد روی یک شی که وجود ندارد ایجاد میشود.
مدیریت استثناها در پایتون
مدیریت استثنا در پایتون با استفاده از دستورات try
, except
, else
, و finally
انجام میشود. این دستورات به شما امکان میدهند کدی را که ممکن است استثنا ایجاد کند را اجرا کنید و در صورت بروز استثنا، با آن برخورد کنید و اقدامات مرتبط را انجام دهید. ساختار کلی استفاده از این دستورات به این صورت است:
try:
# کدی که ممکن است استثناء ایجاد کند
except استثناء_نوع_اول:
# برخورد با استثناء نوع اول
except استثناء_نوع_دوم:
# برخورد با استثناء نوع دوم
else:
# کدی که در صورت عدم بروز استثناء اجرا میشود
finally:
# کدی که همیشه اجرا میشود
حالا به تفصیل به هر قسمت از این ساختار میپردازیم:
بخش try
این قسمت کدی که ممکن است استثنا ایجاد کند قرار میگیرد. این قسمت اجباری است.
بخش except
با استفاده از دستور except
میتوانید برخورد با استثناها را مدیریت کنید. شما میتوانید یک یا چند except
برای برخورد با استثناهای مختلف ایجاد کنید. هر except
باید مشخص کننده نوع استثنا باشد. اگر استثنائی که ایجاد میشود با یکی از except
ها مطابقت داشته باشد، بلافاصله کد مرتبط با آن except
اجرا میشود.
بخش else
این بخش، کدی که در صورت عدم بروز استثنا اجرا میشود قرار میگیرد. این بخش اختیاری است.
بخش finally
در این بخش، کدی که همیشه باید اجرا شود (به صورت مستقل از وقوع یا عدم وقوع استثنا) قرار میگیرد. این بخش اختیاری است.
مثال اول: مدیریت استثناء ZeroDivisionError
مثال اول مدیریت استثنا در پایتون، یک دستور try
داریم که تقسیم یک عدد به صفر را انجام میدهد. اگر تقسیم به صفر امکانپذیر نباشد، یک استثناء ZeroDivisionError
ایجاد میشود و ما با استفاده از بخش except
این استثنا را مدیریت میکنیم.
try:
result = 10 / 0
except ZeroDivisionError:
print("تقسیم بر صفر امکانپذیر نیست.")
این مثال، کد درون بخش try
اجرا میشود. اما چون تقسیم بر صفر انجام میگردد، یک استثناء ZeroDivisionError
ایجاد و سپس بخش except
اجرا میشود و پیام “تقسیم بر صفر امکانپذیر نیست.” در کنسول چاپ خواهد شد.
مثال دوم: مدیریت استثناء ValueError
در این مثال، ما یک دستور try
داریم که سعی در تبدیل یک رشته به یک عدد انجام میدهد. اگر رشته قابل تبدیل به عدد نباشد، یک استثنا ValueError
ایجاد میشود و ما با استفاده از بخش except
این استثنا را مدیریت میکنیم.
try:
num = int("abc")
except ValueError:
print("رشته به عدد قابل تبدیل نیست.")
این مثال، تلاش برای تبدیل متن “abc” به عدد انجام گردیده که این کار ممکن نیست. بنابراین، یک استثنا ValueError
ایجاد و پیام “رشته به عدد قابل تبدیل نیست.” چاپ میشود.
مثال سوم: بخش else
در مدیریت استثنا
مثال بعدی، ما از بخش else
نیز استفاده میکنیم. در اینجا، کد درون بخش try
اجرا میشود و اگر هیچ استثنائی ایجاد نشود (یعنی کد بدون مشکل اجرا شود)، بخش else
اجرا میشود.
try:
num = int("42")
except ValueError:
print("رشته به عدد قابل تبدیل نیست.")
else:
print(f"عدد وارد شده: {num}")
همانطور که در کد بالا میبینید، متن “42” به عدد 42 تبدیل و هیچ استثنائی ایجاد نمیشود. بنابراین، بخش else
اجرا و پیام “عدد وارد شده: 42” چاپ میشود.
مثال چهارم: بخش finally
در مدیریت استثنا
مثال بعدی، ما از بخش finally
نیز استفاده میکنیم. بخش finally
برای اجرای کدی که همیشه باید اجرا شود (به صورت مستقل از وقوع یا عدم وقوع استثنا) مناسب است.
try:
result = 10 / 2
except ZeroDivisionError:
print("تقسیم بر صفر امکانپذیر نیست.")
else:
print(f"نتیجه تقسیم: {result}")
finally:
print("این بخش همیشه اجرا میشود.")
در این مثال، تقسیم عدد 10 به 2 انجام و هیچ استثنائی ایجاد نمیشود. بنابراین، بخش else
اجرا و پیام “نتیجه تقسیم: 5” چاپ میشود. سپس بخش finally
نیز اجرا و پیام “این بخش همیشه اجرا میشود.” چاپ میگردد.
مدیریت چند استثناء
شما میتوانید چند except
را برای مدیریت چند نوع مختلف استثنا ایجاد کنید. برای مثال:
try:
result = 10 / 0
except ZeroDivisionError:
print("تقسیم بر صفر امکانپذیر نیست.")
except ValueError:
print("رشته به عدد قابل تبدیل نیست.")
در این مثال، دو except
برای مدیریت دو نوع استثناء ZeroDivisionError
و ValueError
ایجاد گردیده است. اگر هر یک از این استثناها ایجاد شود، کد مربوط به آن استثناء اجرا خواهد شد.
استفاده از except
بدون مشخص کردن نوع استثنا
شما همچنین میتوانید از except
بدون مشخص کردن نوع استثنا استفاده کنید. در این صورت، این except
به همه استثناها پاسخ خواهد داد. این روش باید با احتیاط استفاده شود زیرا میتواند باعث ایجاد یک مدیریت استثنا نامناسب شود.
try:
result = 10 / 0
except:
print("یک استثناء ایجاد شد.")
استفاده از except
با ذکر نوع عمومی استثنا
در برخی موارد، شما میتوانید از except
با ذکر نوع عمومی استثنا مانند Exception
استفاده کنید. این به شما امکان میدهد تا به تمام نوعهای استثناها پاسخ دهید. این روش باید با احتیاط استفاده شود تا از ایجاد مدیریت استثنا نامناسب جلوگیری شود.
try:
result = 10 / 0
except Exception:
print("یک استثناء ایجاد شد.")
نکات مهم در مدیریت استثنا
- به دقت از نوع استثنا استفاده کنید: هنگام استفاده از
except
، بهتر است دقت کنید و نوع دقیق استثنا را مشخص کنید. این کمک میکند تا مدیریت استثناها دقیقتر شود. - استفاده از بخش
else
وfinally
: بخشelse
برای اجرای کد در صورت عدم وقوع استثنا و بخشfinally
برای اجرای کدی که همیشه باید اجرا شود بسیار مفیدند. - مدیریت استثناهای سفارشی: در برخی موارد، ممکن است نیاز به ایجاد و مدیریت استثناهای سفارشی داشته باشید. برای این کار، میتوانید یک کلاس استثنا خودتان ایجاد کنید.
ایجاد استثناهای سفارشی
علاوه بر مدیریت استثناهای پیشفرض پایتون، شما میتوانید استثناهای سفارشی خودتان را نیز ایجاد کنید. این استثناهای سفارشی برای مواقعی که بخواهید شرایط خاصی را برای بروز استثنا تعیین کنید مفید هستند.
برای ایجاد یک استثنا سفارشی، باید یک کلاس بسازید که از کلاس Exception
یا کلاسی که از آن ارثبری میکند ایجاد شود. سپس در داخل کلاس خود، یک متد به نام __init__
تعریف کنید که پیام استثنا را تنظیم کند. همچنین میتوانید سایر متدهای خود را به کلاس اضافه کنید.
مثال: ایجاد یک استثنا سفارشی
در این مثال، یک استثنا سفارشی به نام CustomError
ایجاد میشود. این استثنا دارای یک پیام خاص است که در زمان ایجاد آن تنظیم میشود.
class CustomError(Exception):
def __init__(self, message):
self.message = message
super().__init__(self.message)
# استفاده از استثناء سفارشی
try:
raise CustomError("این یک استثناء سفارشی است.")
except CustomError as e:
print(e.message)
در این مثال، یک کلاس به نام CustomError
تعریف گردیده است که از کلاس Exception
ارثبری میکند. در داخل این کلاس، متد __init__
تعریف کرده که پیام استثنا را تنظیم میکند. سپس یک استثنا از نوع CustomError
ایجاد و پیام آن چاپ میشود.
پیمایش استثناها
در برنامهنویسی، ممکن است نیاز داشته باشید تا استثناها را پیمایش کنید و اطلاعات بیشتری از آنها به دست آورید. در پایتون، شما میتوانید از دستورات try
و except
برای این کار استفاده کنید.
مثال: پیمایش استثناها
در این مثال، چندین استثنا با انواع مختلف ایجاد میشوند و اطلاعات آنها چاپ میشود.
try:
num = int("abc")
except ZeroDivisionError:
print("استثناء ZeroDivisionError ایجاد شد.")
except ValueError as ve:
print(f"استثناء ValueError ایجاد شد: {ve}")
except Exception as e:
print(f"استثناء ناشناخته ایجاد شد: {e}")
در این مثال، ابتدا تلاش برای تبدیل رشته “abc” به عدد انجام میشود که موجب ایجاد یک استثناء ValueError
میشود. سپس از دستورات except
برای پیمایش استثناها استفاده میشود. ابتدا بررسی میشود که آیا استثنا ZeroDivisionError
ایجاد گردیده است یا نه. در این مورد، استثنا ZeroDivisionError
ایجاد نشده است، بنابراین به بخش بعدی بررسی میرویم که آیا استثنا ValueError
ایجاد گردیده است یا نه. در این مورد، استثنا ValueError
ایجاد شده است و پیام مرتبط با آن چاپ میشود. در نهایت، برای استثناهای دیگر (همه استثناها که از نوع Exception
ارثبری میکنند) یک بخش except
دیگر وجود دارد که پیام استثنا ناشناخته چاپ میکند.
استفاده از finally
برای تنظیمکردن منابع
یکی از کاربردهای مهم بخش finally
در مدیریت استثناها، تنظیمکردن منابع (مانند فایلها یا اتصالات پایگاه داده) است. بخش finally
معمولاً برای انجام عملیاتی که باید همیشه انجام شود (مثل بستن یک فایل) استفاده میشود تا منابع به درستی آزاد شوند.
مثال: استفاده از finally
برای بستن فایل
try:
file = open("sample.txt", "r")
content = file.read()
print(content)
except FileNotFoundError:
print("فایل مورد نظر یافت نشد.")
finally:
file.close()
در این مثال، یک فایل به نام “sample.txt” باز میشود و محتوای آن خوانده میشود. اگر فایل یافت نشود (استثناء FileNotFoundError
)، پیام مناسب چاپ میشود. سپس بخش finally
اجرا و فایل بسته خواهد شد.