معالجة الأخطاء (Try & Except): كيف تمنع سكربتاتك من الانهيار الفجائي؟
ماذا سنتعلم اليوم؟
سنتعلم كيف نستخدم try و except في بايثون لجعل سكربتاتنا أكثر قوة وموثوقية، ونمنعها من الانهيار الفجائي عند حدوث أخطاء غير متوقعة.
الخطوة 1: فهم الأخطاء وكيف تحدث
قبل أن نتعلم كيفية معالجة الأخطاء، دعنا نفهم ما هي الأخطاء وكيف تتسبب في توقف السكربتات. الأخطاء (أو الاستثناءات - Exceptions) هي أحداث تحدث أثناء تنفيذ البرنامج وتخل بالتدفق الطبيعي. على سبيل المثال، محاولة القسمة على صفر أو تحويل نص غير رقمي إلى عدد.
ملاحظة تقنية: في بايثون، عندما يحدث خطأ، يتم "رفع" استثناء (exception is raised). إذا لم يتم التعامل مع هذا الاستثناء، يتوقف البرنامج عن العمل ويعرض رسالة خطأ.
لنرى مثالاً بسيطاً لكود سينهار:
# مثال على كود ينهار بسبب خطأ # محاولة القسمة على صفر ستؤدي إلى ZeroDivisionError # محاولة تحويل نص غير رقمي إلى عدد ستؤدي إلى ValueError num1 = 10 num2_input = input("أدخل رقمًا للقسمة عليه: ") # المستخدم قد يدخل نصًا أو صفرًا try: num2 = int(num2_input) # محاولة تحويل المدخل إلى عدد صحيح result = num1 / num2 # محاولة إجراء القسمة print(f"النتيجة: {result}") except ValueError: print("خطأ: المدخل ليس رقمًا صحيحًا.") except ZeroDivisionError: print("خطأ: لا يمكن القسمة على صفر.") print("انتهى البرنامج.")
إذا أدخلت 'abc' أو '0' في السكربت أعلاه، سيتوقف البرنامج ويعرض رسالة خطأ لأننا لم نقم بمعالجة هذه الحالات بشكل صحيح في هذا المثال الأولي.
الخطوة 2: الأساسيات: try و except
تسمح لنا كتل try و except في بايثون بتجربة تنفيذ جزء من الكود الذي قد يتسبب في خطأ، وإذا حدث خطأ، يمكننا "التقاطه" والتعامل معه بدلاً من السماح للبرنامج بالانهيار.
try: تحتوي هذه الكتلة على الكود الذي قد يسبب خطأ.except: تحتوي هذه الكتلة على الكود الذي يتم تنفيذه إذا حدث خطأ معين داخل كتلةtry.
هنا كيف يمكننا تعديل الكود السابق لمعالجة خطأ ValueError:
# استخدام try و except لمعالجة خطأ محدد (ValueError) num1 = 10 num2_str = input("أدخل رقمًا للقسمة عليه: ") try: num2 = int(num2_str) # <-- هذا السطر قد يرفع ValueError إذا كان num2_str ليس رقمًا result = num1 / num2 print(f"النتيجة: {result}") except ValueError: # <-- إذا حدث ValueError، يتم تنفيذ هذه الكتلة print("خطأ: المدخل ليس رقمًا صحيحًا. يرجى إدخال رقم.") print("انتهى البرنامج.")
الآن، إذا أدخل المستخدم نصًا غير رقمي، لن ينهار البرنامج. بدلاً من ذلك، سيطبع الرسالة التي حددناها في كتلة except.
الخطوة 3: معالجة أخطاء متعددة وكتل else و finally
يمكننا جعل معالجة الأخطاء أكثر تفصيلاً من خلال:
- معالجة أخطاء متعددة: استخدام عدة كتل
exceptلأنواع مختلفة من الأخطاء. else: كتلة اختيارية يتم تنفيذها إذا لم يتم رفع أي استثناء في كتلةtry.finally: كتلة اختيارية يتم تنفيذها دائمًا، بغض النظر عما إذا كان هناك استثناء أم لا. تستخدم عادة لتنظيف الموارد (مثل إغلاق الملفات).
# معالجة أخطاء متعددة و استخدام else و finally num1 = 10 try: num2_str = input("أدخل رقمًا للقسمة عليه: ") num2 = int(num2_str) # محاولة تحويل المدخل إلى عدد صحيح result = num1 / num2 # محاولة إجراء القسمة except ValueError: # معالجة خطأ إذا لم يكن المدخل رقمًا print("خطأ: المدخل ليس رقمًا صحيحًا. يرجى إدخال رقم.") except ZeroDivisionError: # معالجة خطأ القسمة على صفر print("خطأ: لا يمكن القسمة على صفر. يرجى إدخال رقم آخر.") except Exception as e: # معالجة أي خطأ آخر غير متوقع (يجب أن تكون في النهاية) print(f"حدث خطأ غير متوقع: {e}") # طباعة تفاصيل الخطأ else: # يتم تنفيذ هذه الكتلة إذا لم تحدث أي أخطاء في كتلة try print(f"العملية تمت بنجاح. النتيجة: {result}") finally: # يتم تنفيذ هذه الكتلة دائمًا، سواء حدث خطأ أم لا print("انتهى تنفيذ كتلة معالجة الأخطاء.") print("البرنامج اكتمل عمله.")
ملاحظة تقنية: كتلةexcept Exception as e:هي كتلة شاملة تلتقط أي نوع من الاستثناءات. يجب وضعها دائمًا بعد كتلexceptالمحددة لأنها ستلتقط جميع الاستثناءات قبل أن تتمكن الكتل الأكثر تحديدًا من معالجتها.
الكود النهائي الكامل
هذا هو السكربت الكامل الذي يجمع كل المفاهيم التي تعلمناها لمعالجة الأخطاء بفعالية:
# سكربت كامل لمعالجة الأخطاء (Try & Except) في عملية القسمة print("مرحبًا بك في برنامج القسمة الآمن!") def safe_division(): num1_str = input("الرجاء إدخال الرقم الأول (البسط): ") num2_str = input("الرجاء إدخال الرقم الثاني (المقام): ") try: # محاولة تحويل المدخلات إلى أعداد صحيحة num1 = int(num1_str) num2 = int(num2_str) # محاولة إجراء عملية القسمة result = num1 / num2 except ValueError: # معالجة خطأ إذا كان أحد المدخلات ليس رقمًا صحيحًا print("\nخطأ: أحد المدخلات أو كلاهما ليس رقمًا صحيحًا. يرجى إدخال أرقام فقط.") return # إنهاء الدالة بعد الخطأ except ZeroDivisionError: # معالجة خطأ إذا حاول المستخدم القسمة على صفر print("\nخطأ: لا يمكن القسمة على صفر. يرجى إدخال رقم آخر للمقام.") return # إنهاء الدالة بعد الخطأ except Exception as e: # معالجة أي خطأ آخر غير متوقع قد يحدث print(f"\nحدث خطأ غير متوقع: {e}") # طباعة تفاصيل الخطأ للمساعدة في التصحيح return # إنهاء الدالة بعد الخطأ else: # هذه الكتلة تُنفذ فقط إذا لم تحدث أي أخطاء في كتلة try print(f"\nالعملية تمت بنجاح! {num1} مقسومًا على {num2} يساوي: {result}") finally: # هذه الكتلة تُنفذ دائمًا، سواء حدث خطأ أم لا print("\nانتهى جزء معالجة الأخطاء لعملية القسمة.") # استدعاء الدالة لتشغيل البرنامج safe_division() print("شكرًا لاستخدامك برنامجنا. إلى اللقاء!")
النتيجة المتوقعة
عند تشغيل السكربت، ستتلقى رسائل مختلفة بناءً على مدخلاتك:
- إذا أدخلت أرقامًا صحيحة وغير صفرية:
مرحبًا بك في برنامج القسمة الآمن! الرجاء إدخال الرقم الأول (البسط): 10 الرجاء إدخال الرقم الثاني (المقام): 2 العملية تمت بنجاح! 10 مقسومًا على 2 يساوي: 5.0 انتهى جزء معالجة الأخطاء لعملية القسمة. شكرًا لاستخدامك برنامجنا. إلى اللقاء! - إذا أدخلت نصًا غير رقمي (مثل 'hello'):
مرحبًا بك في برنامج القسمة الآمن! الرجاء إدخال الرقم الأول (البسط): 10 الرجاء إدخال الرقم الثاني (المقام): hello خطأ: أحد المدخلات أو كلاهما ليس رقمًا صحيحًا. يرجى إدخال أرقام فقط. انتهى جزء معالجة الأخطاء لعملية القسمة. شكرًا لاستخدامك برنامجنا. إلى اللقاء! - إذا حاولت القسمة على صفر:
مرحبًا بك في برنامج القسمة الآمن! الرجاء إدخال الرقم الأول (البسط): 10 الرجاء إدخال الرقم الثاني (المقام): 0 خطأ: لا يمكن القسمة على صفر. يرجى إدخال رقم آخر للمقام. انتهى جزء معالجة الأخطاء لعملية القسمة. شكرًا لاستخدامك برنامجنا. إلى اللقاء!
كما ترى، في جميع الحالات، لا ينهار السكربت، بل يتعامل مع الأخطاء بطريقة أنيقة ويستمر في التنفيذ حتى النهاية (طباعة رسالة "شكرًا لاستخدامك برنامجنا. إلى اللقاء!").