فایلها و مدیریت خطا
مدیریت خطا در پایتون با try و except
یادتان هست که int(input(...)) اگر کاربر بهجای عدد salam تایپ کند، برنامه را با ValueError متوقف میکند؟ در دنیای واقعی کاربرها همیشه چیزهای غیرمنتظره وارد میکنند. برنامهٔ خوب نباید با هر ورودی اشتباهی بترکد.
به خطاهایی که هنگام اجرا رخ میدهند استثنا (exception) میگویند. پایتون اجازه میدهد آنها را بگیریم و خودمان تصمیم بگیریم چه کنیم.
ساختار try/except
a = "salam"
try:
b = int(a)
print(b)
except ValueError:
print("it's not a numeric string")
- کدی که ممکن است خطا بدهد داخل
tryمیرود. - اگر خطا رخ داد، اجرای
tryهمانجا متوقف میشود و پایتون سراغ بلوکexceptمیرود. - اگر خطایی رخ نداد،
exceptکلاً نادیده گرفته میشود.
a را به "42" تغییر دهید و دوباره اجرا کنید.
مقایسه کنید با روش حلقه روی کاراکترها که قبلاً برای تشخیص عدد نوشتیم: try/except کوتاهتر است و اعداد منفی را هم درست تشخیص میدهد (int("-5") کار میکند).
💡 به این سبک در پایتون میگویند EAFP («بخشش خواستن راحتتر از اجازه گرفتن است»): بهجای اینکه اول همهچیز را چک کنید، کار را انجام دهید و اگر خطا داد، مدیریتش کنید.
نوع خطا را مشخص کنید
میشود نوشت except: (بدون نوع)، ولی این کار خطرناک است. همهٔ خطاها را میگیرد، حتی باگهای واقعی خودتان (مثل غلط املایی در اسم متغیر)، و آنها را بیصدا پنهان میکند:
try:
b = int(aa) # غلط املایی! aa تعریف نشده
except:
print("it's not a numeric string") # پیام گمراهکننده
پیام میگوید «عدد نیست»، در حالی که مشکل واقعی NameError است. همیشه دقیقاً خطایی را بگیرید که انتظارش را دارید:
try:
x = int(input("عدد: "))
print(100 / x)
except ValueError:
print("این عدد نیست!")
except ZeroDivisionError:
print("تقسیم بر صفر ممکن نیست!")
با ورودیهای 5، abc و 0 امتحان کنید.
الگوی «تا درست نگفتی، دوباره بپرس»
ترکیب while با try/except یکی از پرکاربردترین الگوهاست:
while True:
try:
age = int(input("سن خود را وارد کنید: "))
break # ورودی درست بود؛ از حلقه خارج شو
except ValueError:
print("لطفاً یک عدد صحیح وارد کنید.")
print(f"سن شما: {age}")
(در ویرایشگر این سایت، چند ورودی را با | جدا کنید، مثلاً abc|bist|25، تا رفتار حلقه را ببینید.)
while True یک حلقهٔ بینهایت عمدی است که فقط با break تمام میشود، یعنی وقتی int() بدون خطا اجرا شد.
else و finally
try:
with open("data.txt", encoding="utf-8") as f:
content = f.read()
except FileNotFoundError:
print("فایل پیدا نشد!")
else:
print("خوانده شد:", len(content), "کاراکتر") # فقط اگر خطایی رخ نداد
finally:
print("این خط در هر صورت اجرا میشود")
| بلوک | کِی اجرا میشود؟ |
|---|---|
try |
همیشه (تا جایی که خطا رخ دهد) |
except |
فقط اگر همان نوع خطا رخ داد |
else |
فقط اگر هیچ خطایی رخ نداد |
finally |
در هر صورت، چه خطا رخ بدهد چه نه؛ برای کارهای پاکسازی |
💡 دستور
withدر واقع یکtry/finallyآماده است که بستن فایل را درfinallyانجام میدهد.
پیام خطا را هم بگیرید
با as میشود خود شیء خطا را گرفت و پیامش را نمایش داد:
try:
int("salam")
except ValueError as e:
print("خطا:", e)
نکتهٔ مهم: try/except جای کد درست را نمیگیرد
try/except برای خطاهایی است که خارج از کنترل شما هستند: ورودی کاربر، فایلی که شاید وجود نداشته باشد، قطع اینترنت. باگهای خودتان را با try/except پنهان نکنید؛ درستشان کنید.
تمرین
تابعی به اسم safe_divide(a, b) بنویسید که a / b را برگرداند، ولی اگر b صفر بود بهجای کرش کردن None برگرداند.
جواب
def safe_divide(a, b):
try:
return a / b
except ZeroDivisionError:
return None
print(safe_divide(10, 2))
print(safe_divide(10, 0))