جاري تحميل المحتوى...
أثناء كتابة البرامج قد تظهر أخطاء لأسباب مختلفة: قد تكون صياغة الكود غير صحيحة، أو قد تحدث مشكلة أثناء التنفيذ، أو قد يعمل البرنامج دون توقف لكنه يعطي نتيجة غير صحيحة. في هذا الفصل ستتعلم كيف تميز بين هذه الحالات، وكيف تقرأ رسائل الخطأ الأساسية، وكيف تستخدم try وexcept لمعالجة بعض الحالات المتوقعة.
قد يحدث الخطأ لأننا كتبنا صياغة غير صحيحة، أو استخدمنا قيمة لا تناسب العملية، أو حاولنا الوصول إلى عنصر غير موجود، أو وضعنا منطقًا لا يحقق الهدف المطلوب.
وجود خطأ لا يعني دائمًا الشيء نفسه. لذلك من المفيد أولًا تحديد نوع المشكلة بدل تجربة تعديلات عشوائية.
| النوع | الفكرة المبسطة | مثال |
|---|---|---|
| Syntax Error | صياغة الكود تخالف قواعد Python. | نسيان النقطتين بعد شرط. |
| Runtime Error | الصياغة صحيحة، لكن مشكلة تظهر أثناء التنفيذ. | القسمة على صفر. |
| Logical Error | البرنامج يعمل، لكن النتيجة لا تحقق المنطق المطلوب. | إضافة الخصم بدل طرحه. |
يحدث Syntax Error عندما لا تتوافق كتابة الكود مع قواعد Python.
في المثال التالي توجد مشكلة في صياغة جملة الشرط:
if age >= 18
print("Adult")
المشكلة هي غياب النقطتين : بعد الشرط.
الصيغة الصحيحة:
if age >= 18:
print("Adult")
عندما توجد مشكلة من هذا النوع لا يستطيع Python تنفيذ الكود بالصورة الطبيعية قبل تصحيح الصياغة.
قد تكون صياغة الكود صحيحة، لكن تظهر مشكلة أثناء التنفيذ بسبب قيمة أو حالة معينة.
number = 10
print(number / 0)
هذا الكود صحيح من ناحية الصياغة، لكن أثناء التنفيذ تحدث ZeroDivisionError لأن القسمة على صفر غير مسموحة في هذا السياق.
سنستخدم كلمة Error بصورة عامة لوصف المشكلات، بينما نتعامل مع Exceptions مثل ValueError وZeroDivisionError بوصفها حالات يمكن أن تظهر أثناء التنفيذ ويمكن معالجة الحالات المتوقعة منها باستخدام try وexcept.
الخطأ المنطقي مختلف؛ فالبرنامج قد يعمل دون ظهور Exception، لكنه يعطي نتيجة لا تطابق الهدف.
price = 100
discount = 20
final_price = price + discount
print(final_price)
الكود يعمل ويطبع 120. لكن إذا كان الهدف تطبيق خصم قدره 20، فالمنطق الصحيح هو الطرح:
final_price = price - discount
إذًا Logical Error لا يعني تلقائيًا وجود Exception.
عندما يحدث Exception قد يعرض Python Traceback يساعدك على معرفة ما حدث.
Traceback (most recent call last):
File "app.py", line 2, in <module>
print(10 / 0)
ZeroDivisionError: division by zero
للمبتدئ، ركز أولًا على ثلاث معلومات:
ZeroDivisionError.division by zero.غالبًا يكون السطر الأخير من Traceback نقطة بداية مفيدة لفهم نوع المشكلة.
سنركز على عدد محدود من Exceptions المرتبطة بما تعلمته سابقًا.
SyntaxErrorيظهر عندما تكون صياغة Python غير صحيحة.
if age >= 18
print("Adult")
NameErrorيحدث عند محاولة استخدام اسم غير معرف.
print(score)
إذا لم يتم تعريف score قبل هذا السطر، يمكن أن يحدث NameError.
TypeErrorيحدث عندما تكون العملية غير مناسبة للأنواع المستخدمة.
print("Age: " + 20)
هنا تحاول العملية + الجمع مباشرة بين str وint بهذه الصورة، فيحدث TypeError.
يمكن كتابة المثال بطريقة مناسبة مثل:
print("Age:", 20)
أو باستخدام f-string:
age = 20
print(f"Age: {age}")
ValueErrorقد تكون العملية نفسها صحيحة من ناحية الصياغة، لكن القيمة لا تصلح لها.
age = int("abc")
استدعاء int() صحيح، لكن النص "abc" لا يمثل عددًا صحيحًا صالحًا للتحويل، لذلك يحدث ValueError.
ZeroDivisionErrorresult = 10 / 0
القسمة على صفر في هذا المثال تؤدي إلى ZeroDivisionError.
IndexErrorتعلمت أن Lists تستخدم الفهارس للوصول إلى عناصرها.
numbers = [10, 20, 30]
print(numbers[5])
الفهرس 5 غير موجود في هذه List، لذلك يحدث IndexError.
KeyErrorيمكن أن يظهر عند محاولة الوصول إلى Key غير موجود في Dictionary باستخدام الأقواس.
student = {
"name": "Ali"
}
print(student["age"])
المفتاح "age" غير موجود، لذلك يحدث KeyError.
إذا كان غياب المفتاح حالة متوقعة فعلًا، فقد يكون get() مناسبًا في بعض الحالات التي تعلمتها سابقًا:
print(student.get("age"))
لكن get() ليست بديلًا عامًا لكل مشكلة؛ الاختيار يعتمد على منطق البرنامج.
FileNotFoundErrorيرتبط هذا النوع بما تعلمته عن الملفات النصية.
with open("missing.txt", "r", encoding="utf-8") as file:
content = file.read()
إذا لم يكن الملف missing.txt موجودًا في المسار المطلوب، يمكن أن يحدث FileNotFoundError.
tryتوضع داخل try التعليمات التي نعرف أنها قد تواجه حالة متوقعة نريد التعامل معها.
try:
number = int(input("أدخل رقمًا: "))
print(number)
except ValueError:
print("الرجاء إدخال رقم صحيح")
إذا كانت القيمة قابلة للتحويل إلى int، يكمل التنفيذ داخل try. وإذا حدث ValueError تنتقل المعالجة إلى except ValueError.
exceptمن الأفضل تعليميًا أن نحدد الحالة التي نعرف كيف نتعامل معها.
try:
age = int("abc")
except ValueError:
print("القيمة لا تمثل عددًا صحيحًا")
في هذا المثال نعرف أن التحويل قد يؤدي إلى ValueError، لذلك نذكر هذا النوع صراحة.
لا نجعل الشكل التالي أسلوبنا الأساسي:
except:
pass
معالجة الخطأ لا تعني إخفاء كل الأخطاء دون فهم سببها.
exceptقد تحتوي مجموعة تعليمات على أكثر من حالة متوقعة، ويمكن معالجة كل حالة بصورة منفصلة.
try:
number = int(input("أدخل رقمًا: "))
result = 10 / number
print(result)
except ValueError:
print("القيمة ليست رقمًا صحيحًا")
except ZeroDivisionError:
print("لا يمكن القسمة على صفر")
إذا كان الإدخال غير قابل للتحويل إلى عدد، تتعامل ValueError مع الحالة. وإذا كان العدد هو 0 يصل التنفيذ إلى القسمة وتحدث ZeroDivisionError.
try/excepttry:
number = int("5")
print(number)
except ValueError:
print("خطأ")
التحويل ينجح، لذلك يظهر 5 ولا ينفذ فرع except ValueError.
try:
number = int("abc")
print(number)
except ValueError:
print("قيمة غير صالحة")
يحدث ValueError أثناء التحويل، فينتقل التنفيذ إلى except ValueError وتظهر الرسالة.
else مع tryيمكن استخدام else بصورة تمهيدية لتنفيذ تعليمات عندما ينتهي جزء try دون حدوث Exception تتم معالجتها.
try:
number = int("25")
except ValueError:
print("قيمة غير صالحة")
else:
print(number)
التحويل ينجح، لذلك لا ينفذ except وينفذ else ويظهر 25.
finallyتستخدم finally في هذا المستوى لتنفيذ تعليمات في نهاية المحاولة سواء حدث Exception في المسار المعروض أو لم يحدث.
try:
number = int("25")
except ValueError:
print("خطأ")
finally:
print("انتهت المحاولة")
في المثال يظهر "انتهت المحاولة" في النهاية.
لن نستخدم finally هنا لإدارة الملفات يدويًا، لأنك تعلمت في الفصل السابق استخدام with open(...).
هناك فرق بين فشل تحويل القيمة وبين التحقق من معناها بعد نجاح التحويل.
try:
age = int(input("العمر: "))
except ValueError:
print("أدخل رقمًا صحيحًا")
else:
if age >= 0:
print("العمر مقبول")
else:
print("العمر لا يمكن أن يكون سالبًا")
try/except تعالج هنا فشل التحويل إلى int، بينما يستخدم if للتحقق المنطقي من القيمة بعد نجاح التحويل.
try/except مع الملفاتإذا كان غياب الملف حالة متوقعة يمكن معالجتها بوضوح:
try:
with open("notes.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)
except FileNotFoundError:
print("الملف غير موجود")
إذا كان الملف موجودًا تتم قراءته. وإذا لم يكن موجودًا في المسار المطلوب، تتعامل except FileNotFoundError مع هذه الحالة.
لا نضع try/except حول البرنامج كاملًا بلا سبب. نستخدمها عندما توجد حالة متوقعة نعرف كيف نتعامل معها.
الهدف هو:
لا نحتاج في هذا الفصل إلى Debugger أو Breakpoints أو أدوات متقدمة.
بعض المشكلات تحدث أثناء التنفيذ، وبعضها Logical Error لا ينتج Exception.
ValueError وTypeErrorint("abc") مثال على ValueError لأن القيمة النصية لا تمثل عددًا صالحًا.
أما:
"Age: " + 20
فهو مثال على TypeError لأن العملية تستخدم نوعين بطريقة غير مناسبة.
except عام دون حاجةحدد Exception التي تتوقعها وتعرف كيف تتعامل معها عندما يكون ذلك ممكنًا في أمثلة هذا المستوى.
passتجاهل المشكلة لا يعني إصلاحها. لا نستخدم except: pass كأسلوب تعليمي في هذا الفصل.
قد يعمل البرنامج دون Exception، لكن تكون النتيجة المنطقية غير صحيحة.
السطر الأخير غالبًا يحتوي اسم Exception ورسالة مفيدة تساعد على بدء التحليل.
إذا كان التحويل باستخدام int() يفشل بسبب نص مثل "abc" فالمشكلة هنا ValueError، وليس IndexError مثلًا.
حدد هل مثال بسيط يحتوي على نقطتين مفقودتين بعد if يمثل Syntax Error أم Runtime Error أم Logical Error.
جرّب تحديد نوع Exception في أمثلة منفصلة تستخدم اسمًا غير معرف وقسمة على صفر وفهرسًا غير موجود.
اكتب مثالًا يستخدم try وexcept ValueError لمعالجة تحويل نص غير صالح إلى int.
اكتب مثالًا يحتوي على ValueError محتملة وZeroDivisionError محتملة، واستخدم except منفصلة لكل منهما.
استخدم else لطباعة القيمة عندما ينجح تحويل النص إلى عدد.
استخدم finally لطباعة رسالة قصيرة في نهاية محاولة تحويل قيمة.
اكتب مثالًا يحاول قراءة ملف نصي ويعالج FileNotFoundError برسالة واضحة.
اكتب عملية حسابية تعمل دون Exception لكنها تحتوي Logical Error، ثم صحح المنطق.
NameError يرتبط باستخدام اسم غير معرف.TypeError يرتبط بعملية غير مناسبة للأنواع المستخدمة.ValueError قد يحدث عندما تكون القيمة غير مناسبة للتحويل.ZeroDivisionError يحدث في مثال القسمة على صفر.IndexError يرتبط بفهرس غير موجود.KeyError يرتبط بمفتاح Dictionary غير موجود عند الوصول المباشر.FileNotFoundError قد يحدث عند محاولة قراءة ملف غير موجود.try.except تعالج Exception المطابقة.except لحالات مختلفة.else يمكن أن تنفذ عند نجاح try دون Exception تتم معالجتها.finally تنفذ في نهاية المسار المعروض سواء حدث Exception أم لا.if يختلف عن معالجة فشل التحويل باستخدام try/except.في الفصل التالي ستتعرف على Modules وStandard Library وكيفية الاستفادة من أكواد وأدوات منظمة جاهزة ضمن Python.
نشر في ١١ أغسطس ٢٠٢٦