تخطَّ إلى المحتوى

التعامل مع الأخطاء في Python: try و except

الدرس 15 من 25 · Python

الأخطاء جزء طبيعي من البرمجة. المستخدم قد يكتب كلمة بدلاً من رقم، أو يقسم على صفر، أو يطلب ملفاً غير موجود. في كل هذه الحالات تتوقف Python وتعرض رسالة خطأ مخيفة. في هذا الدرس ستتعلم كيف تلتقط الأخطاء وتتعامل معها بهدوء، بحيث يكمل برنامجك عمله بدلاً من أن ينهار.

عندما يحدث خطأ أثناء التشغيل، تسمّيه Python استثناءً (Exception). وهذه أشهر الأنواع التي ستقابلها:

الخطأ متى يحدث؟ مثال
ZeroDivisionError القسمة على صفر 10 / 0
ValueError قيمة غير مناسبة int("abc")
TypeError نوع غير مناسب "5" + 5
IndexError فهرس غير موجود [1, 2][5]
KeyError مفتاح غير موجود في القاموس {"a": 1}["b"]
NameError متغير غير معرّف print(x)

لا تخف من رسائل الخطأ! اقرأ آخر سطر فيها دائماً: فيه نوع الخطأ ووصفه، وهذا يدلك على المشكلة غالباً.

الفكرة بسيطة: ضع الكود الذي قد يسبب خطأ داخل try، واكتب ما تريد فعله عند حدوث الخطأ داخل except:

def to_number(text):
try:
return int(text)
except ValueError as e:
print("خطأ:", e)
return 0
print(to_number("42"))
print(to_number("أربعة"))
الناتج
42
خطأ: invalid literal for int() with base 10: 'أربعة'
0
  • في الاستدعاء الأول نجح التحويل، فلم يُنفّذ except أبداً.
  • في الثاني فشل التحويل، فقفزت Python مباشرة إلى except بدلاً من أن يتوقف البرنامج.
  • الكتابة as e تحفظ تفاصيل الخطأ في المتغير e لتعرضها أو تسجلها.

تخيّل try مثل لاعب السيرك على الحبل، و except هي شبكة الأمان تحته: إذا سقط، لا ينتهي العرض، بل تلتقطه الشبكة ويكمل.

يمكنك إضافة جزأين اختياريين:

  • else: يُنفّذ فقط إذا لم يحدث خطأ.
  • finally: يُنفّذ دائماً، حدث خطأ أم لم يحدث.
def safe_divide(a, b):
try:
result = a / b
except ZeroDivisionError:
print("لا يمكن القسمة على صفر!")
return None
else:
print("تمت القسمة بنجاح")
return result
finally:
print("انتهت المحاولة")
print(safe_divide(10, 2))
print(safe_divide(10, 0))
الناتج
تمت القسمة بنجاح
انتهت المحاولة
5.0
لا يمكن القسمة على صفر!
انتهت المحاولة
None

لاحظ أن رسالة finally ظهرت في الحالتين. يُستخدم finally عادة لأعمال «التنظيف» مثل إغلاق ملف، لأنها يجب أن تحدث مهما كانت النتيجة.

مثال عملي: إدخال رقم صحيح

Section titled “مثال عملي: إدخال رقم صحيح”

من أشهر استخدامات try أن تطلب من المستخدم رقماً، وتعيد السؤال حتى يكتب رقماً صحيحاً:

while True:
try:
age = int(input("كم عمرك؟ "))
break
except ValueError:
print("من فضلك اكتب رقماً، مثل 14")
print(f"عمرك {age} سنة")
الناتج
كم عمرك؟ أربعة عشر
من فضلك اكتب رقماً، مثل 14
كم عمرك؟ 14
عمرك 14 سنة

هنا اجتمعت while True و break من درس سابق مع try و except، لتصنع برنامجاً لا ينهار مهما كتب المستخدم.

أحياناً تريد أنت أن تعلن عن خطأ، عندما تصل لدالتك قيمة غير منطقية:

def set_age(age):
if age < 0:
raise ValueError("العمر لا يمكن أن يكون سالباً")
return age
try:
set_age(-5)
except ValueError as e:
print("رسالة الخطأ:", e)
الناتج
رسالة الخطأ: العمر لا يمكن أن يكون سالباً

اكتب برنامج «آلة حاسبة آمنة» يطلب رقمين ويقسم الأول على الثاني، ويتعامل مع خطأين: كتابة شيء غير الرقم (ValueError)، والقسمة على صفر (ZeroDivisionError). يمكنك كتابة أكثر من except واحدة بعد try. مثال:

الناتج
الرقم الأول: 10
الرقم الثاني: 0
لا يمكن القسمة على صفر!
  • استخدام except فارغة: تخفي أخطاء حقيقية. حدّد نوع الخطأ.
  • وضع كود كثير داخل try: يصعّب معرفة السطر الذي فشل.
  • تجاهل الخطأ بصمت: except ValueError: pass بدون أي رسالة تجعل المستخدم لا يفهم ما حدث. اعرض رسالة مفيدة دائماً.

سؤال

ما نوع الخطأ الذي يسببه int('abc')؟

سؤال

متى يُنفّذ جزء finally؟

  • الأخطاء أثناء التشغيل تسمى استثناءات، واقرأ آخر سطر في رسالة الخطأ لتفهمها.
  • ضع الكود الذي قد يفشل في try، والتعامل مع الخطأ في except نوع_الخطأ:.
  • else تُنفّذ عند النجاح، و finally تُنفّذ دائماً.
  • raise تطلق خطأً بنفسك عند وصول قيمة غير منطقية.
  • حدّد نوع الخطأ دائماً، ولا تستخدم except فارغة.