در دنیای برنامهنویسی، خطاها و استثناءها بخشی از روند طبیعی توسعه نرمافزار هستند. این استثناها در هنگام اجرای برنامه ممکن است رخ دهند و برنامه را از حالت اجرا متوقف کنند. برای مدیریت و کنترل این استثناها و جلوگیری از توقف برنامه، در زبانهای برنامهنویسی ابزارهایی به نام مدیریت استثنا (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 اجرا و فایل بسته خواهد شد.