2.4 · تدبير الأخطاء والاستثناءات

المستوى 2 · هياكل البيانات والبرمجة كائنية التوجه

2.4تدبير الأخطاء والاستثناءات

الهدف: تدبير try/except/finally وإنشاء استثناءاتك الخاصة.
الوقت المقدّر: 12 دقيقة · قراءة ذاتية · إذا كان لديك 5 دقائق فقط: اقرأ «الأساسي في 30 ثانية» + المخطط.

الأساسي في 30 ثانية

  • أطر المحفوف بدقة : ‏try على التحويل والملف والشبكة — لا كل البرنامج أبدا.
  • التقط بدقة لا باتساع : ‏except ‏ValueError/FileNotFoundError مستهدَف — ‏except العاري أو pass يدفن الأخطاء.
  • أبلغ مبكرا وبقوة : ‏raise لثوابتك، وelse/finally في محلهما، سجل ثم تدهور بنظافة.

حالة مستمرة — نبيل يجعل استيراد الشهر موثوقا

الفصل الأخير : استيراد نبيل الشهري يتعطل عند أول طارئ — تصدير غائب، ومبلغ غير رقمي، ومجموع مقسوم على صفر عندما لا عملية بيع. المستخدمون يرون أثرا أحمر. جعله موثوقا : تحويل المبالغ في try/except ‏ValueError مع إعادة الطلب، والفتح في try/except ‏FileNotFoundError برسالة واضحة، والقسمة محمية ضد ZeroDivisionError، والمبالغ السالبة مرفوضة بـ raise منذ إنشاء عملية Vente ‏(2.3). والباقي يصعد بأثره : لا شيء مُسكَت. استيراد المستوى 2 مُسلَّم : بيانات ونص وكائنات وأخطاء مُدبَّرة.

خاتمة الخيط الرابط 2.1-2.3 : استيراد نبيل لا يتعطل بعد اليوم عند أول طارئ.

1. الاستثناء ليس كارثة

ValueError وKeyError وFileNotFoundError وZeroDivisionError : كائنات إعلامية لا إهانات. try/except يؤطر المحفوف بدقة (تحويل مدخل، فتح ملف، قسمة) — لا كل البرنامج أبدا : الالتقاط الواسع يخفي الأخطاء. التتبع (Traceback) يُقرَأ من الأسفل إلى الأعلى : نوع الخطأ ثم السطر المخطئ. نبيل يطبق ذلك : وحده تحويل المبالغ مؤطر، لا كل الاستيراد.

2. try/except/else/finally : لكل دوره

try تحوي المحفوف، وexcept ValueError تلتقط نوعا دقيقا برسالة مفيدة، وelse تنفذ التتمة إن سار كل شيء، وfinally تنظف دائما (تغلق وتحرر — حتى عند الخطأ). raise ValueError("...") تُبلغ عن ثوابتك : المبلغ السالب مرفوض مبكرا وبقوة منذ الإنشاء. نبيل يرفض هكذا المبالغ السالبة في __init__ : يُبلَّغ عن الخطأ عند المصدر، لا بعد ثلاث دوال.

3. اترك يمر ما لا تعالج

القاعدة الذهبية : لا نلتقط إلا ما نعرف علاجه (إعادة الطلب، قيمة افتراضية، رسالة واضحة). والباقي يصعد بأثره : إسكاته بـ except: pass يدفن أخطاء حية — أسوأ منعكس. except العاري يخفي كل شيء، بما فيه ما يجب أن تراه. في الإنتاج، نسجل ثم نتدهور بنظافة (رسالة للمستخدم وتوقف مضبوط). استيراد نبيل يعيد طلب المبالغ غير الصالحة، ويُبلغ عن التصدير الغائب — ويترك غير المتوقع يصعد.

خطأ شائع في الفهم: « للاحتياط، ألتقط كل شيء بـ except: وأضع pass ». لا، فهي أضمن طريقة لعدم رؤية شيء : ‏except العاري يلتقط حتى أخطاء كودك ويخفيها pass — فيواصل البرنامج ببيانات خاطئة دون أي إشارة. قاعدة نبيل : ‏except مستهدَف (ValueError وFileNotFoundError) + علاج حقيقي (إعادة الطلب والافتراضي والرسالة) ؛ وما لا نعرف علاجه يصعد ويُسجَّل.
أخطاء مُدبَّرة أطر وعالج وأبلغ try ‏(المحفوف) التحويلوالملف — مقطع ضيقexcept ‏(الدقيق) نوعمستهدَف + علاج حقيقيraise/log ‏(أبلغ) الثوابتمبكرا وغير المتوقع يصعد
أطر وعالج وأبلغ
نص المخطط (SEO / قارئات الشاشة / الترجمة): 1) نبيل يؤطر المحفوف بدقة بـ try (تحويل المبالغ وفتح التصدير) — لا كل البرنامج أبدا. 2) يلتقط بدقة (‏except ‏ValueError/FileNotFoundError) بعلاج حقيقي : إعادة الطلب ورسالة واضحة وelse للتتمة وfinally للتنظيف. 3) يُبلغ مبكرا بـ raise (المبلغ السالب مرفوض منذ __init__) ويترك غير المتوقع يمر بأثره، مسجلا — ولا except: pass أبدا. الدرس : افشل مبكرا وبقوة، ولا تُسكِت أبدا.

هل تعلم ؟

كتب نبيل يوما « except: pass » لإسكات خطأ — وبقي تقرير الجزائر صفرا أسبوعا دون تنبيه أحد.
صحيح : إسكات خطأ يدفن الخطأ حيا — نلتقط بدقة ونعالج.

خطأ مُسكَت يعمل ضدك بصمت.

🔎 مثال ملموس — 🔎 مثال ملموس — إدخال نبيل المتين دون إسكات

الدقيق مُلتقط، والباقي كان سيصعد، كما عند نبيل :

def lire_montant(texte):
    try:
        montant = float(texte)
    except ValueError:
        raise ValueError(f"مبلغ غير صالح : {texte!r}") from None
    if montant < 0:
        raise ValueError("المبلغ السالب ممنوع")
    return montant

try:
    print(lire_montant("1250.5"))
except ValueError as e:
    print(f"خطأ : {e}")

القراءة : ‏ValueError مستهدَف، والثابت مُبلَّغ بـ raise، ورسالة مفيدة.

الدرس : لا except: pass أبدا — فهي تدفن الأخطاء الحية.

مفردات القسم

الاستثناء (Exception)
خطأ يقع عند التنفيذ (ZeroDivisionError وValueError وFileNotFoundError…) يوقف البرنامج إن لم يُدبَّر. يُقرَأ من الأسفل إلى الأعلى في التتبع.

مثال بسيط: تصدير نبيل الغائب يرفع FileNotFoundError.

ما ليس كذلك: خطأ صياغة يمنع الانطلاق.

رد فعل: تعطل عند التنفيذ = استثناء يُقرَأ.

try / except
try تحوي الكود المحفوف (مقطع ضيق) ؛ وexcept تلتقط نوعا دقيقا وتنفذ علاجا حقيقيا بدل التعطل.

مثال بسيط: نبيل يحيط float(montant) بـ except ‏ValueError.

ما ليس كذلك: except عارٍ يلتقط كل شيء دون علاج.

رد فعل: محفوف دقيق = try + ‏except مستهدَف.

else / finally
else : التتمة إن لم يقع خطأ ؛ وfinally : تُنفَّذ في كل الحالات، مثالية لتحرير مورد (إغلاق ملف).

مثال بسيط: نبيل يعرض « اكتمل الاستيراد » في finally.

ما ليس كذلك: تنظيف لا يدور إلا عند النجاح.

رد فعل: تنظيف مضمون = finally.

raise
ترفع طوعا استثناء للإبلاغ عن وضع شاذ (ثابت مُنتَهَك) : الفشل مبكرا وبقوة، عند المصدر.

مثال بسيط: عملية Vente لنبيل ترفض المبالغ السالبة بـ raise.

ما ليس كذلك: عودة صامتة تترك بيانات خاطئة تمر.

رد فعل: ثابت مُنتَهَك = raise فوري.

التتبع (Traceback)
أثر الخطأ الذي تعرضه بايثون : يُقرَأ من الأسفل إلى الأعلى، ويشير إلى نوع الخطأ والسطر المخطئ. يُسجَّل ولا يُخفَى.

مثال بسيط: نبيل يقرأ أسفل التتبع ليجد التحويل المخطئ.

ما ليس كذلك: رسالة مخفية بـ except: pass.

رد فعل: التتبع = اقرأ الأسفل وصحح السطر.

في التطبيق — تطبيقيا — جعل برنامج موثوقا بـ try/except

  1. اطلب مبلغا وحوله : أحط float() بـ try/except ‏ValueError يعيد الطلب عند مدخل غير رقمي.
  2. دبر متوسطا بالتقاط ZeroDivisionError (لا عملية بيع) برسالة واضحة بدل التعطل.
  3. افتح التصدير بـ try/except ‏FileNotFoundError ؛ وأضف finally تعرض « اكتمل الاستيراد » في كل الحالات.
  4. اكتب دالة ترفع (raise) ‏ValueError لمبلغ سالب، واختبرها بـ try/except.
تتوقع الأخطاء بـ try/except/finally وترفع استثناءاتك : برامجك تصبح متينة أمام الطارئ.

نص جاهز — تبرير الاستهداف في مراجعة الكود (30 ثانية)

« لاستيراد نبيل، كل try ضيقة : التحويل في ValueError، والتصدير في FileNotFoundError، وعلاج حقيقي وراءهما. والمبالغ السالبة تذهب في raise منذ الإنشاء. ولا except ‏pass : ما لا نعرف علاجه يصعد ويُسجَّل — لا ندفن خطأ أبدا. »

يُقال مع عرض except عارٍ مستبدَل بـ except مستهدَفين.

قالب للنسخ — استيراد موثوق من البداية إلى النهاية

import json
from pathlib import Path

def lire_montant(texte):
    montant = float(texte)
    if montant < 0:
        raise ValueError("المبلغ السالب ممنوع")
    return montant

fichier = Path("ventes.json")
try:
    lignes = json.loads(fichier.read_text(encoding="utf-8"))
except FileNotFoundError:
    print("التصدير غير موجود : تحقق من ventes.json")
    lignes = []
try:
    montants = [lire_montant(str(l)) for l in lignes]
except ValueError as e:
    print(f"سطر غير صالح تم تجاهله : {e}")
    montants = []
else:
    print(f"{len(montants)} مبالغ مقروءة")
finally:
    print("اكتمل الاستيراد")

تصدير غائب

ملف الشهر غائب : FileNotFoundError تعرض رسالة واضحة بدل أثر أحمر.

متوسط دون عملية بيع

لا عملية بيع في الجزائر اليوم : ZeroDivisionError مُلتقط، و« لا متوسط » معروض.

مبلغ ممنوع

مبلغ سالب يطلق raise منذ عملية Vente : الفشل مبكرا والإبلاغ عند المصدر.

✓ ممارسات جيدة

  • تأطير المحفوف بدقة بمقاطع try ضيقة.
  • التقاط أنواع دقيقة بعلاج حقيقي (else/finally في محلهما).
  • الرفع بـ raise للثوابت ؛ والتسجيل ثم التدهور بنظافة.

✗ أخطاء شائعة

  • استعمال except: العاري أو except: pass (يخفي ويدفن الأخطاء).
  • تأطير كل البرنامج في try واحدة.
  • الإسكات بدل العلاج (المواصلة ببيانات خاطئة).

النقاط الأساسية

  • try/except تلتقط الأخطاء بدل ترك البرنامج يتعطل — مقطع ضيق على المحفوف.
  • استهدف نوع الخطأ (ValueError وFileNotFoundError…) بدل except فارغ.
  • else = التتمة إن سار كل شيء ؛ وfinally تُنفَّذ دائما : مثالية لتحرير مورد.
  • raise ترفع استثناء للإبلاغ عن وضع شاذ ؛ وSyntaxError لا تُدبَّر بـ try.

تحدي 48 ساعة — طبق غدا

اجعل سكربتا حقيقيا موثوقا (سكربت نبيل أو سكربتك) : ‏try ضيقة + ‏except مستهدَفة على كل نقطة هشة (تحويل وملف وقسمة)، وraise لثابت، وfinally حقيقية — واطرد كل except: pass.

قائمة الخروج من القسم
  • أستطيع شرح try/except/else/finally ودور كل منها.
  • أعرف الالتقاط بدقة والرفع بـ raise لثوابتي.
  • حذفت كل except عارٍ أو مُسكَت من كودي.
تقييم ذاتي 1-5 : هل مقاطع try ضيقة ومستهدَفة ؟هل أُبلغ مبكرا بدل الإسكات ؟

أسئلة شائعة

هل نلتقط كل الأخطاء بـ except عام ؟

لا : « except: » العاري يخفي كل شيء، بما فيه أخطاء يجب أن تراها. التقط استثناءات مستهدَفة (except ‏ValueError) لتدبير ما تتوقعه فقط، واترك الباقي يصعد. وهي قاعدة ذهبية للموثوقية.

ما الفرق بين خطأ الصياغة والاستثناء ؟

خطأ الصياغة (SyntaxError) يمنع البرنامج من الانطلاق : الكود مكتوب خطأ. والاستثناء يقع عند تنفيذ كود صحيح وإلا (ملف غائب وقسمة على صفر). وحدها الاستثناءات تُدبَّر بـ try/except.

تحقّق من فهمك

ماذا يجب تجنبه مطلقا في تدبير الأخطاء ؟

موارد إضافية (اختياري، للتعمّق أكثر)

اختبار المستوى 2أسئلة جديدة وأصعب للتحقق من مكتسباتك