معالجة الأخطاء في بايثون – سلسلة بايثونات لتعلم لغة البايثون

4 4٬948

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

قبل البدء ننصحكم بالإطلاع على سلسلة بايثونات لتعلم لغة البايثون من خلال زيارة الروابط التالية:

  1. لغة بايثون للمبتدئين – سلسلة بايثونات لتعلم البايثون والانطلاق في عالم البرمجة.
  2. النصوص في بايثون.
  3. المتغيرات والتراكيب في بايثون.
  4. جُمل التحكم في بايثون.
  5. الدوال والوحدات بايثون.
  6. مُعالجة الأخطاء في بايثون.
  7. البرمجة الكائنية في بايثون.

كيف أفهم معالجة الأخطاء بشكل صحيح؟

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

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

ما هو معالجة الأخطاء؟

نعني بمعالجة الأخطاء الطريقة التي تضمن استمرار عمل البرنامج بشكل سليم أثناء ظهور الأخطاء. في بايثون، نستخدم تعبير try/except في تعريف “مُعالج الأخطاء” الذي سيقوم بدور مُراقب وقوع الخطأ في جزء مُعين من الشيفرة البرمجية ثم استقبال الخطأ عند حدوثه ومعالجته بشكل سليم بحيث يجعل من البرنامج يستمر في العمل.

الاستراتيجية الرئيسية في عمل معالجة الإخطاء تتكون من جزئين:

  1. إحاطة الشيفرة البرمجية التي نتوقع حدوث أخطاء فيها بتعبير try.
  2. كتابة الشيفرة البرمجية التي سيتم تنفيذها عند حدوث الخطأ في تعبير exception.
معالجة الأخطاء في بايثون - التعبير الأساسي
معالجة الأخطاء في بايثون – التعبير الأساسي

توفر البايثون خيارات إضافية لمعالجة الأخطاء هي تعبير else و finally. نستخدم else في حالة لم يحدث أي خطأ في الشيفرة البرمجية ونريد أن ننفذ شيفرة برمجية معينة. نستخدم تعبير finally عندما نُريد تنفيذ شيفرة برمجية بشكل دائم بغض النظر عن وجود خطأ من عدمه.

ما هي أنواع الأخطاء التي قد نواجهها في بايثون؟

يُوجد نوعين من الأخطاء:

  1. الأخطاء Errors: وهي التي تكون ناتجة عن خطأ في قواعد كتابة لغة البرمجة وُتسمى Syntax Errors أو الأخطاء المنطقية Logical Errors الناتجة عن قصور في فهم طبيعة المشكلة.
  2. الاستثناءات Exceptions: وهي الأخطاء التي تحدث أثناء عمل/تشغيل البرنامج وتنقسم إلى استثناءات مبنية Builtin Exceptions واستثناءات مُعرفة من قبل المستخدم User defined exceptions.

القائمة التالية هي أنواع الاستثناءات المبنية في بايثون:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

الأمثلة التالية هي لأنواع من الإستثناءات غير المعالجة والتي قد تنتج في الشيفرة البرمجية:

استثناء KeyError

products = {1:"Mobile", 2:"TV", 3:"Car"} 

#This will through KeyError exception
print(products[4])

استثناء NameError

x = 10 
y = 3

#This will through NameError exception
print(z + x + y)

استثناء TypeError

x = 10 

#This will through TypeError exception
print("x is: " + x)

استثناء ImportError

#This will through ImportError exception 

import Pythonat

عند وقوع الأخطاء، وعند عدم معالجتها سيتوقف البرنامج عن التنفيذ وسيتم طباعة أو إظهار نص يحتوي على نوع الخطأ ورسالة تفصيلية تتضمن السطر واسم الملف الذي وقع فيه الخطأ.

كيف نستخدم try/except؟

بعد أن تعرفنا على بعض الأخطاء (الاستثناءات) وكيف تظهر أثناء تنفيذ الشيفرة البرمجية، الصيغة التالية هي الصيغة العامة لكتابة مُعالج الأخطاء في بايثون:

try:
code.......
code.......
code.......

except ExceptionName1:
code.......
code.......

except ExceptionName2:
code.......
code.......

except ExceptionName3:
code.......
code.......

except:
code.......
code.......

المثال التالي يُوضح كيفية معالجة خطأ القسمة على صفر ZeroDivisionError:

try: 
x = 10 / 0
except ZeroDivisionError:
print("You can't divide by zero")

في حالة توقعنا بحدوث أخطاء متعددة، يُمكننا كتابة معالج الأخطاء بطريقة تُعالج أكثر من خطأ كما يلي:

try: 
x = 10 / 0
except ZeroDivisionError:
print("You can't divide by zero")
except FloatingPointError:
print("There is error: Floating Point Error")
except KeyError:
print("Your key is not found!")

في بعض الأحيان قد لا نعرف أي الأخطاء التي قد تحدث خلال عمل البرنامج، لذلك يُمكننا في نهاية الجزء الخاص بمُعالج الأخطاء أن نُضيف تعبير except يكون عامًا ويُمكنه إلتقاط أي خطأ غير معروف كما يلي:

try: 
x = 10 / 0
except ZeroDivisionError:
print("You can't divide by zero")
except FloatingPointError:
print("There is error: Floating Point Error")
except KeyError:
print("Your key is not found!")
except:
print("Unknown error has been occurred!")

كيف نستخدم finally و else ؟

عند معالجة الأخطاء في بايثون يُوجد خيار اضافي يُعطينا المزيد من الإمكانيات في التعامل مع الأخطاء والاستثناءات. الخيار الاضافي هو استخدام تعبير else وتعبير finally. الشكل التالي يُوضح الصيغة العامة لمُعالج الأخطاء باستخدام else و finally:

معالجة الأخطاء في بايثون - التعبير الأساسي
معالجة الأخطاء في بايثون – التعبير الأساسي

المثال التالي يُوضح كيفية استخدام تعبير else و finally. بداخل try نُعرف متغير content ونعطيه قيمة None ثم نكتب السطر الخاص بقراءة ملف نصي. في حالة كان الملف النصي موجودًا سيتم تنفيذ الجزء الخاص بـ else ثم finally، أما في حالة لم يكن الملف موجودًا سيتولد لدينا استثناء من نوع FileNotFoundError ثم سيتم تنفيذ الجزء الخاص بـ except ثم الجزء الخاص بـ finally:

try: 
content = None
f = open("pythonat-datacamp.txt")
except FileNotFoundError:
print("The file not found")
else:
print("Processing file....")
content = f.read()
print(content)
print("Closing file")
f.close()
finally:
print("Processing file finished.")

كيف نُعرف إستثناء في بايثون؟

من الممكن أن نعُرف الإستثناء الخاص بنا. يتم ذلك من خلال تعريف فئة class ترث من الإستثناء العام Exception. المثال التالي يُوضح كيفية تعريف استثناء باسم pythonatException والذي نُريد أن نُظهره عند ادخال نص من المستخدم لا يبدأ بكلمة Pythonat. سنستخدم الكلمة المحجوزة في بايثون raise لإظهار الاستثناء الخاص بنا في المكان الذي نريده:

import re

class pythonatException(Exception):
def __init__(self, messege = None):
if messege:
self.messege = messege
else:
self.messege = None

def __str__(self):
if self.messege:
return 'pythonatException is raised. {}'.format(self.messege)
else:
return 'pythonatException is raised'


def main():
user_data = input("Enter 'Pythonat ' then your text: ")
if re.match("Pythonat ", user_data):
print("Thank you, your text includes 'Pythonat '")
else:
raise pythonatException("Enter 'Pythonat ' at the begining please")



if __name__ == '__main__':
main()

إلى هنا نكون انتهينا من شرح موضوع معالجة الأخطاء في بايثون. نتمنى أن نكون وُفقنا في إيصال المعلومة بالشكل الصحيح حول الموضوع ونسعد بأي ملاحظة في التعليقات. كما نتمنى منكم مشاركة مقالات بايثونات في منصات التواصل الاجتماعي مثل تويتر وفيسبوك حتى تعم الفائدة.

4 Comments
  1. […] معالجة الأخطاء في بايثون. […]

  2. Abdullah n says

    شكرا لك مقال رائع
    اتمنى فيه مقال تشرح فيه self كالمثال الاخير وشكرا لكم

اترك ردًا

Your email address will not be published.