مدیریت خطا (Error Handling) در پایتون

در هنگام اجرای برنامه، ممکن است کاربر ورودی نامناسبی وارد کند یا برنامه با مشکلی غیرمنتظره روبه‌رو شود. برای مثال، اگر از کاربر بخواهیم یک عدد وارد کند اما او به‌جای عدد یک متن وارد کند، برنامه ممکن است متوقف شود و یک پیام خطا نمایش دهد. در پایتون می‌توان با استفاده از مدیریت خطا (Exception Handling) این شرایط را کنترل کرد تا برنامه به‌صورت ناگهانی متوقف نشود و بتوانیم پیام مناسبی به کاربر نمایش دهیم. در این بخش با روش‌های مختلف مدیریت خطا در پایتون، از جمله try، except، else، finally و raise آشنا می‌شویم.

فهرست مطالب

خطا در برنامه‌نویسی چیست؟

در برنامه‌نویسی ممکن است برنامه‌ای که نوشته‌ایم به دلایل مختلف نتواند به درستی اجرا شود. پایتون در چنین شرایطی خطا (Error) ایجاد می‌کند و معمولاً اجرای برنامه را متوقف می‌کند. برای مثال، کد زیر را در نظر بگیرید:

number = int(input("یک عدد وارد کنید: "))
print(number)

اگر کاربر مقدار 25 را وارد کند، برنامه به‌درستی اجرا می‌شود:

یک عدد وارد کنید: 25
25

اما اگر کاربر به‌جای عدد، عبارت hello را وارد کند، پایتون نمی‌تواند آن را به عدد صحیح تبدیل کند و خطایی از نوع ValueError ایجاد می‌شود.

یک عدد وارد کنید: hello
ValueError: invalid literal for int()

در چنین شرایطی بهتر است به‌جای متوقف شدن برنامه، خطا را مدیریت کنیم و پیام مناسبی به کاربر نشان دهیم.

تفاوت خطای Syntax و خطای زمان اجرا

خطاها انواع مختلفی دارند. یکی از تفاوت‌های مهم، تفاوت بین خطای نحوی (Syntax Error) و خطای زمان اجرا (Runtime Error) است. Syntax Error زمانی رخ می‌دهد که قواعد نوشتاری پایتون را رعایت نکرده باشیم:

if age >= 18
    print("مجاز است")

در اینجا علامت : فراموش شده است، بنابراین برنامه حتی قبل از اجرا شدن با خطای نحوی مواجه می‌شود. اما در Runtime Error کد از نظر نحوی صحیح است و برنامه شروع به اجرا می‌کند، ولی در هنگام اجرا با مشکلی مواجه می‌شود:

number = 10
result = number / 0
print(result)

این کد از نظر نحوی درست است، اما تقسیم یک عدد بر صفر امکان‌پذیر نیست و خطای ZeroDivisionError ایجاد می‌شود. برای کنترل بسیاری از خطاهای زمان اجرا می‌توانیم از try و except استفاده کنیم.

دستور try و except

برای مدیریت خطا در پایتون معمولاً از دو دستور try و except استفاده می‌کنیم. کدهایی که احتمال دارد هنگام اجرا باعث ایجاد خطا شوند، داخل بخش try قرار می‌گیرند. اگر هنگام اجرای این کدها خطایی رخ دهد، پایتون اجرای بخش try را متوقف کرده و وارد بخش except می‌شود. ساختار کلی به این صورت است:

try:
    # کدی که ممکن است خطا ایجاد کند
except:
    # کدی که هنگام رخ دادن خطا اجرا می‌شود

به این مثال توجه کنید:

فرض کنید می‌خواهیم عددی را از کاربر دریافت کنیم:

try:
    number = int(input("یک عدد وارد کنید: "))
    print(number)
except:
    print("لطفاً یک عدد معتبر وارد کنید.")

اگر کاربر عدد 25 را وارد کند:

یک عدد وارد کنید: 25
25

اما اگر عبارت hello را وارد کند:

یک عدد وارد کنید: hello
لطفاً یک عدد معتبر وارد کنید.

در حالت دوم، تبدیل hello به عدد باعث ایجاد خطا می‌شود. پایتون به‌جای متوقف کردن برنامه، وارد بخش except می‌شود و پیام مناسب را نمایش می‌دهد.

یک مثال دیگر

خطای تقسیم بر صفر یکی دیگر از خطاهای رایج است:

try:
    number = int(input("یک عدد وارد کنید: "))
    result = 100 / number
    print(result)
except:
    print("در محاسبه مشکلی رخ داد.")

اگر کاربر 4 وارد کند:

25.0

اما اگر 0 وارد کند، برنامه به‌جای متوقف شدن، پیام بخش except را نمایش می‌دهد:

در محاسبه مشکلی رخ داد.

نکته مهم

بهتر است در برنامه‌های واقعی، به‌جای استفاده از except به‌تنهایی، نوع خطایی که انتظار داریم را مشخص کنیم. این کار باعث می‌شود مدیریت خطا دقیق‌تر باشد.

برای مثال:

try:
    number = int(input("یک عدد وارد کنید: "))
except ValueError:
    print("ورودی باید یک عدد باشد.")

در اینجا فقط خطای ValueError مدیریت می‌شود. در ادامه، انواع خطاهای رایج مانند ValueError و ZeroDivisionError را بررسی می‌کنیم و یاد می‌گیریم چگونه هر خطا را به‌صورت جداگانه مدیریت کنیم.

انواع خطا و مدیریت هر خطا

در پایتون خطاهای مختلفی وجود دارند و هر کدام نشان‌دهنده یک مشکل خاص در برنامه هستند. برای مدیریت بهتر خطا، می‌توانیم نوع خطا را در except مشخص کنیم.

خطای ValueError

این خطا معمولاً زمانی ایجاد می‌شود که مقدار مناسبی برای یک عملیات وارد نشده باشد. برای مثال، اگر بخواهیم یک متن را به عدد تبدیل کنیم:

number = int("hello")

پایتون نمی‌تواند عبارت "hello" را به عدد تبدیل کند و خطای ValueError ایجاد می‌شود. می‌توانیم این خطا را به شکل زیر مدیریت کنیم:

try:
    number = int(input("یک عدد وارد کنید: "))
    print(number)
except ValueError:
    print("لطفاً فقط عدد وارد کنید.")

اگر کاربر بنویسد:

25

برنامه بدون مشکل اجرا می‌شود. اما اگر بنویسد:

hello

پیام زیر نمایش داده می‌شود:

لطفاً فقط عدد وارد کنید.
 

خطای ZeroDivisionError

این خطا زمانی ایجاد می‌شود که بخواهیم عددی را بر صفر تقسیم کنیم.

try:
    number = int(input("یک عدد وارد کنید: "))
    result = 100 / number
    print(result)
except ZeroDivisionError:
    print("تقسیم بر صفر امکان‌پذیر نیست.")

اگر کاربر 0 وارد کند، خطای ZeroDivisionError رخ می‌دهد و پیام مناسب نمایش داده می‌شود.

 

مدیریت چند نوع خطا

گاهی ممکن است در یک بخش از برنامه، بیش از یک نوع خطا رخ دهد. در این شرایط می‌توانیم چند except داشته باشیم. مثلاً:

try:
    number = int(input("یک عدد وارد کنید: "))
    result = 100 / number
    print(result)

except ValueError:
    print("لطفاً یک عدد وارد کنید.")

except ZeroDivisionError:
    print("عدد صفر قابل قبول نیست.")

در این مثال:

  • اگر کاربر hello وارد کند، ValueError مدیریت می‌شود.
  • اگر کاربر 0 وارد کند، ZeroDivisionError مدیریت می‌شود.
  • اگر کاربر عددی مثل 5 وارد کند، برنامه بدون خطا ادامه پیدا می‌کند.

این روش نسبت به استفاده از except خالی، دقیق‌تر و قابل کنترل‌تر است.

نکته مهم

ترتیب exceptها اهمیت دارد. پایتون هر خطا را با exceptهایی که از بالا به پایین نوشته شده‌اند بررسی می‌کند و اولین مورد مناسب را اجرا می‌کند.

دستور else در مدیریت خطا

در ساختار مدیریت خطا، علاوه بر try و except می‌توانیم از دستور else نیز استفاده کنیم. کدهای داخل else فقط زمانی اجرا می‌شوند که هیچ خطایی در بخش try رخ نداده باشد.

ساختار کلی:

try:
    # کدی که ممکن است خطا ایجاد کند
except:
    # در صورت رخ دادن خطا
else:
    # اگر خطایی رخ ندهد

به این مثال توجه کنید:

try:
    number = int(input("یک عدد وارد کنید: "))
except ValueError:
    print("ورودی نامعتبر است.")
else:
    print("عدد شما:", number)

اگر کاربر 25 وارد کند:

یک عدد وارد کنید: 25
عدد شما: 25

اما اگر hello وارد کند:

یک عدد وارد کنید: hello
ورودی نامعتبر است.

در حالت دوم، بخش else اجرا نمی‌شود؛ چون هنگام اجرای try خطا رخ داده است.

مزیت استفاده از else:

می‌توانستیم دستور print را هم داخل try قرار دهیم:

try:
    number = int(input("یک عدد وارد کنید: "))
    print("عدد شما:", number)
except ValueError:
    print("ورودی نامعتبر است.")

اما وقتی بخشی از کد فقط در صورت موفقیت‌آمیز بودن عملیات باید اجرا شود، استفاده از else باعث می‌شود ساختار برنامه واضح‌تر باشد.

مثلاً:

try:
    age = int(input("سن خود را وارد کنید: "))
except ValueError:
    print("سن باید به صورت عدد وارد شود.")
else:
    if age >= 18:
        print("شما بزرگسال هستید.")
    else:
        print("شما زیر 18 سال هستید.")

در این مثال، ابتدا تلاش می‌کنیم ورودی را به عدد تبدیل کنیم. اگر تبدیل با موفقیت انجام شد، بخش else اجرا می‌شود و می‌توانیم از مقدار age استفاده کنیم.

دستور finally

دستور دیگری که در مدیریت خطا استفاده می‌شود، finally است. کدهای داخل finally در هر صورت اجرا می‌شوند؛ یعنی چه خطایی رخ دهد و چه خطایی رخ ندهد.

ساختار کلی:

try:
    # کد اصلی
except:
    # در صورت خطا
finally:
    # در هر صورت اجرا می‌شود

مثال:

try:
    number = int(input("یک عدد وارد کنید: "))
    print(100 / number)

except ValueError:
    print("لطفاً یک عدد وارد کنید.")

except ZeroDivisionError:
    print("تقسیم بر صفر امکان‌پذیر نیست.")

finally:
    print("پایان برنامه")

اگر کاربر 20 وارد کند:

5.0
پایان برنامه

اگر کاربر 0 وارد کند:

تقسیم بر صفر امکان‌پذیر نیست.
پایان برنامه

و اگر hello وارد کند:

لطفاً یک عدد وارد کنید.
پایان برنامه

همان‌طور که می‌بینید، در هر سه حالت عبارت پایان برنامه نمایش داده می‌شود.

کاربرد مهم finally

finally معمولاً برای کارهایی استفاده می‌شود که باید در پایان عملیات انجام شوند؛ حتی اگر برنامه با خطا مواجه شده باشد. برای مثال، هنگام کار با فایل‌ها یا ارتباط با منابع خارجی، می‌توان از finally برای انجام عملیات پاک‌سازی و آزاد کردن منابع استفاده کرد.

دریافت اطلاعات خطا با as

گاهی فقط نمی‌خواهیم بدانیم که خطایی رخ داده است؛ بلکه می‌خواهیم اطلاعات خود خطا را نیز دریافت کنیم. برای این کار می‌توانیم از as در دستور except استفاده کنیم.

ساختار کلی:

try:
    # کدی که ممکن است خطا ایجاد کند
except ErrorType as error:
    print(error)

در اینجا متغیر error اطلاعات مربوط به خطایی که رخ داده است را در اختیار ما قرار می‌دهد.

مثال

try:
    number = int(input("یک عدد وارد کنید: "))
    result = 100 / number
    print(result)

except ValueError as error:
    print("خطا:", error)

except ZeroDivisionError as error:
    print("خطا:", error)

اگر کاربر به‌جای عدد، hello وارد کند، پایتون اطلاعات خطای ایجادشده را در متغیر error قرار می‌دهد. خروجی ممکن است چیزی شبیه این باشد:

خطا: invalid literal for int() with base 10: 'hello'

اگر کاربر 0 وارد کند:

خطا: division by zero

استفاده از as زمانی مفید است که بخواهیم جزئیات خطا را مشاهده کنیم، ثبت کنیم یا در ادامه برنامه از آن استفاده کنیم.

ایجاد خطا با raise

تا اینجا بیشتر درباره خطاهایی صحبت کردیم که پایتون به‌صورت خودکار ایجاد می‌کند. اما گاهی برنامه‌نویس خودش می‌خواهد در صورت برقرار بودن یک شرایط، خطایی ایجاد کند. برای این کار از دستور raise استفاده می‌کنیم. مثلاً فرض کنید می‌خواهیم برنامه‌ای بنویسیم که سن کاربر را دریافت کند. اگر سن منفی باشد، این مقدار برای ما قابل قبول نیست.

age = int(input("سن خود را وارد کنید: "))

if age < 0:
    raise ValueError("سن نمی‌تواند منفی باشد.")

print("سن شما:", age)

اگر کاربر 20 وارد کند:

سن شما: 20

اما اگر -5 وارد کند، خودمان یک ValueError ایجاد کرده‌ایم:

ValueError: سن نمی‌تواند منفی باشد.
try:
    age = int(input("سن خود را وارد کنید: "))

ترکیب raise با try و except

می‌توانیم خطایی را که خودمان ایجاد کرده‌ایم، با except مدیریت کنیم:

try:
    age = int(input("سن خود را وارد کنید: "))

    if age < 0:
        raise ValueError("سن نمی‌تواند منفی باشد.")

    print("سن شما:", age)

except ValueError as error:
    print("خطا:", error)

حالا اگر کاربر -5 وارد کند، برنامه متوقف نمی‌شود و پیام زیر نمایش داده می‌شود:

خطا: سن نمی‌تواند منفی باشد.
نکته مهم

raise به ما اجازه می‌دهد شرایط نامعتبر را خودمان تشخیص دهیم و یک Exception مناسب ایجاد کنیم. این موضوع در برنامه‌های بزرگ‌تر اهمیت زیادی دارد، زیرا می‌توانیم از ورود داده‌های نامعتبر به بخش‌های مختلف برنامه جلوگیری کنیم.

📝 تمرین اول

برنامه‌ای بنویسید که یک عدد از کاربر دریافت کند. اگر کاربر به‌جای عدد، متن وارد کرد، برنامه به‌جای متوقف شدن پیام مناسبی نمایش دهد. راهنما: از try و except ValueError استفاده کنید

📝 تمرین دوم

برنامه‌ای بنویسید که دو عدد از کاربر دریافت کند و عدد اول را بر عدد دوم تقسیم کند. برنامه باید: خطای وارد کردن مقدار غیرعددی را مدیریت کند. خطای تقسیم بر صفر را مدیریت کند. در صورت موفقیت، نتیجه تقسیم را نمایش دهد. راهنما: به دو except نیاز دارید.

📝 تمرین سوم

برنامه‌ای بنویسید که سن کاربر را دریافت کند. اگر سن کمتر از صفر بود، با استفاده از raise یک ValueError ایجاد کنید. سپس با except این خطا را مدیریت کرده و پیام مناسبی نمایش دهید.

📝 تمرین چهارم

برنامه‌ای برای دریافت قیمت یک کالا بنویسید. اگر قیمت منفی بود، با استفاده از raise خطا ایجاد کنید. اگر قیمت معتبر بود، ۱۰ درصد تخفیف محاسبه و قیمت نهایی نمایش داده شود. در پایان، در هر شرایطی عبارت زیر نمایش داده شود:
پایان محاسبه
راهنما: در این تمرین از try، except، else، finally و raise استفاده کنید.

📝 تمرین پنجم

برنامه‌ای بنویسید که رمز عبور کاربر را دریافت کند. اگر رمز عبور کمتر از ۸ کاراکتر بود، با استفاده از raise یک ValueError ایجاد کنید. سپس خطا را با except مدیریت کنید و پیام مناسبی به کاربر نمایش دهید.

📝 تمرین ششم

یک برنامه ساده برای خودپرداز بنویسید که موجودی حساب را برابر 5000000 تومان در نظر بگیرد. برنامه باید مبلغ برداشت را از کاربر دریافت کند و: اگر ورودی عددی نبود، خطای مناسب نمایش دهد. اگر مبلغ برداشت صفر یا منفی بود، خطا ایجاد کند. اگر مبلغ برداشت بیشتر از موجودی بود، خطا ایجاد کند. در صورت معتبر بودن مبلغ، موجودی جدید را نمایش دهد.

اتصال به پایگاه داده Database

تا اینجا با مفاهیم اصلی پایتون و نحوه کار با فایل‌ها و ماژول‌ها آشنا شدیم. در مرحله بعد، وارد دنیای پایگاه‌های داده (Database) می‌شویم؛ جایی که می‌توان اطلاعات را به‌صورت منظم ذخیره، مدیریت و بازیابی کرد. در این بخش ابتدا با مفهوم پایگاه داده و SQLite آشنا می‌شویم و سپس یاد می‌گیریم چگونه با استفاده از پایتون به یک پایگاه داده متصل شویم و اطلاعات مورد نیاز خود را در آن ذخیره و مدیریت کنیم.

گام بعدی : اتصال به پایگاه داده

برای شرکت در آزمون آماده‌اید؟

با ورود به پنل کاربری می‌توانید جهت ثبت نام در آزمون‌ها و دسترسی به منابع آموزشی اقدام نمایید. کارشناسان ما در اسرع وقت با شما تماس می‌گیرند.

شروع کار با Django

شروع کار با Django در دوره آموزش جامع پایتون با مفاهیمی مانند متغیرها، شرط‌ها، حلقه‌ها، توابع، کلاس‌ها، فایل‌ها و کار

ادامه مطلب »

عملیات CRUD در SQLite

عملیات CRUD درSQLite در بخش قبل با مفهوم پایگاه داده، SQLite و نحوه اتصال پایتون به پایگاه داده آشنا شدیم.

ادامه مطلب »

توابع در پایتون

توابع در پایتون اگر هنگام برنامه‌نویسی مجبور شوید یک قطعه کد را بارها تکرار کنید، برنامه شما طولانی، شلوغ و

ادامه مطلب »

مجموعه در پایتون

مجموعه (Set) در پایتون به زبان ساده، Set مجموعه‌ای از عناصر منحصربه‌فرد (Unique) است که ترتیب مشخصی ندارد و اجازه

ادامه مطلب »

تاپل در پایتون

تاپل (Tuple) در پایتون بعد از آشنایی با لیست (List)، نوبت به یکی دیگر از ساختارهای داده در پایتون یعنی

ادامه مطلب »

لیست در پایتون

لیست (List) در پایتون پرکاربردترین ساختار داده​ تا اینجا یاد گرفتید که هر متغیر فقط یک مقدار را در خود

ادامه مطلب »

آموزش نصب پایتون

آموزش نصب پایتون و ابزارهای موردنیاز (راهنمای کامل برای ویندوز) اگر تصمیم گرفته‌اید برنامه‌نویسی را یاد بگیرید، احتمالاً نام زبان

ادامه مطلب »