التعامل مع الاستثناءات في لغة بايثون Python

في لغة البرمجة بايثون ميزتان رئيسيتان للتعامل مع الأخطاء غير المتوقعة وهما:

  • معالجة الاستثناءات.
  • التأكيدات.

قائمة بالتأكيدات المعيارية

اسم الاستثناء الوصف
Exception الصف الأساسي لكافة الاستثناءات
StopIteration تستخدم عندما لا تؤشر الطريقة next() على أي غرض من الأغراض.
SystemExit تستدعى من قبل التابع sys.exit()
StandardError الصف الأساسي لكافة الاستثناءات ماعدا StopIteration و SystemExit
ArithmeticError الصف الأساسي لكافة الأخطاء الخاصة بالحساب الرقمي.
OverflowError تستدعى عندما يتجاوز الحساب الحد الأعظمي للنموذج الرقمي.
FloatingPointError تستدعى عندما يفشل حساب الفاصلة العائمة.
ZeroDivisonError تستدعى عندما يحدث التفسيم على الصفر من أجل كلفة النماذج الرقمية.
AssertionError تستدعى في حالة فشل تعليمة التأكيد.
AttributeError تستدعى عند فشل مرجع المساهمة أو الإسناد.
EOFError تستدعى عندما لا يكون هناك دخل من التابع raw_input() أو من التابع input() وتم الوصول إلى نهاية الملف.
ImportError تستدعى عند فشل تعليمات الاستدعاء.
KeyboardInterrupt تستدعى عند تنفيذ برنامج المقاطعة وعادة بضغط Ctrl+c
LookupError الصف الأساسي من أجل كافة أخطاء البحث.
IndexError

KeyError

تستدعى عندما لا يتم إيجاد المؤشر في التتالي.

تستدعى عند عدم وجود مفتاح مخصص في القاموس.

NameError تستدعى عند عدم وجود المعرف في الفراغ الاسمي الموضعي او العام.
UnboundLocalError

EnvironmentError

تستدعى عند محاولة إسناد متحول موضعي ضمن التابع او الطريقة ولكن دون قيمة مسندة له.

الصف الأساسي لكافة الاستثناءات التي تحدث خارج بيئة بايثون.

IOError

IOError

تستدعى عند فشل عملية الدخل والخرج.

تستدعى من أجل أخطاء مرتبطة بالنظام.

SyntaxError

IndentationError

تستدعى عند وجود خطأ برمجي.

تستدعى عندما لا يتم التعريف بشكل مناسب.

SystemError تستدعى عندما يكتشف المترجم مشكلة داخلية ولكن عتد حدوث هذا الخطأ فإن المترجم لا يخرج من البرنامج.
SystemExit تستدعى عندما ينهي استخدام المترجم من قبل التابع sys.exit() .
ValueError تستدعى عندما يكون للتابع المبني من أجل نموذج البيانات نموذج صالح من المدخلات .
RuntimeError تستدعى لا يصنف الخطأ المتولد ضمن أي صنف من الأصناف.
NotImplementedError تستدعى عندما طريقة ال abstract تكون غير مطبقة فعلياً (تطبق هذه الطريقة في حالة وجود صف موروث).

التأكيدات في بايثون

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


التعليمة assert

عندما يتم استدعاء هذه التعليمة فإن بايثون تقوم بتقييم التعبير المرافق والذي يؤمل أن يكون صحيحاً وإذا كان خاطئاً فإنه يتم استدعاء الاستثناء AssertionError .

الشيفرة البرمجية –

assert Expression[, Arguments]

إذا فشل التأكيد فإن بايثون تستخدم ArgumentExpression كمدخل لـ AssertionError ولها استثناءات يمكن التعامل معها مثل أي استثناءات اخرى باستخدام التعليمة try-except ولكن إذا لم يتم التعامل معها فإنه يتم إنهاء البرنامج.

مثال

#!/usr/bin/python
def KelvinToFahrenheit(Temperature):
assert (Temperature>=0),"Colder than absolute zero!"
return ((Temperature-273)*1.8)+32
print KelvinToFahrenheit(273)
print int(KelvinToFahrenheit(505.78))
print KelvinToFahrenheit(-5)

فتظهر النتيجة التالية

32.0
451
Traceback (most recent call last):
File "test.py", line 9, in
print KelvinToFahrenheit(-5)
File "test.py", line 4, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!

ما هو الاستثناء ؟

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


التعامل مع الاستثناء

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

الشيفرة البرمجية

try:
You do your operations here;
......................
except ExceptionI:
If there is ExceptionI, then execute this block.
except ExceptionII:
If there is ExceptionII,then execute this block.
......................
else:
If there is no exception then execute this block.

بعض النقاط التوضيحية حول هذه الشيفرة البرمجية:

  • التعليمة try يمكن أن تحوي على تعليمات استثناء متعددة ويعتبر هذا مفيداً عندما تحتوي الكتلة على عدة تعليمات يمكن أن ينتج عنها استثناءات متعددة.
  • من الممكن تضمين عبارة استثناء مولدة والتي يمكنها التعامل مع أي استثناء.
  • بعد عبارة الاستثناء يمكن تضمين عبارة else- ويتم تنفيذ الشيفرة ضمنها إذا لم تسبب الشيفرة الموجودة ضمن كتلة ال try أي استثناء.
  • الكتلة else- مكان جيد للشيفرة التي لا تحتاج حماية من الكتلة try-.

مثال

#!/usr/bin/python

try:
fh= open("testfile","w")
fh.write("This is my test file for exception handling!!")
except IOError:
print "Error: can\'t find file or read data"
else:
print "Written content in the file successfully"
fh.close()

فتظهر النتيجة التالية

Written content in the file successfully

مثال

في المثال التالي تتم محاولة فتح ملف عند تعذر الكتابة لذلك ينتج الاستثناء

#!/usr/bin/python

try:
fh= open("testfile","r")
fh.write("This is my test file for exception handling!!")
except IOError:
print "Error: can\'t find file or read data"
else:
print "Written content in the file successfully"

فتظهر النتيجة التالية

Error: can't find file or read data

العبارة except دون أية استثناءات تعرف هذه العبارة وفق التالي

try:
You do your operations here;
......................
except:
If there is any exception,then execute this block.
......................
else:
If there is no exception then execute this block.

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


العبارة except مع استثناءات متعددة

تعرف وفق التالي

try:
You do your operations here;
......................
except(Exception1[,Exception2[,...ExceptionN]]]):
If there is any exception from the given exception list,
then execute this block.
......................
else:
If there is no exception then execute this block.

العبارة try-finally

تعتبر هذه العبارة مكاناً مناسباً لوضع أية شيفرة برمجية يجب تنفيذها وسواء أعادت هذه العبارة استثناءاً أم لا فإن الشيفرة البرمجية لها هي

try:
You do your operations here;
......................
Due to any exception,this may be skipped.
finally:
This would always be executed.
......................

ملاحظة

لا يمكن استخدام العبارة else بشكل مترافق مع العبارة finally .

مثال

#!/usr/bin/python

try:
fh= open("testfile","w")
fh.write("This is my test file for exception handling!!")
finally:
print"Error: can\'t find file or read data"

فتظهر النتيجة التالية

Error: can't find file or read data

مثال

#!/usr/bin/python

try:
fh= open("testfile","w")
try:
fh.write("This is my test file for exception handling!!")
finally:
print"Going to close the file"
fh.close()
except IOError:
print"Error: can\'t find file or read data"

عندما يتم وضع استثناء ضمن كتلة try فإن التنفيذ يتجاوز وبشكل تلقائي إلى الكتلة finallyوعندما يتم تنفيذ كافة التعليمات في كتلة ال finally
فإنه يتم استدعاء الاستثناء مرة أخرى ويتم التعامل معه ضمن تعليمات ال except إذا كان موجوداً ضمن الطبقة العليا التالية من التعليمة try-except.


المدخل الخاص بالاستثناء

المدخل الخاص بالاستثناء ما هو إلا قيمة تحمل معلومات إضافية حول المشكلة الحاصلة ومحتوى هذا المدخل تختلف وفقاً للاستثناء.
يتم الحصول على مدخل الاستثناء متحول ضمن عبارة الاستثناء كالتالي:

try:
You do your operations here;
......................
except ExceptionType, Argument:
You can print value of Argument here...

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

مثال

#!/usr/bin/python

# Define a function here.
def temp_convert(var):
try:
return int(var)
except ValueError, Argument:
print"The argument does not contain numbers\n", Argument

# Call above function here.
temp_convert("xyz");

فتظهر النتيجة التالية

The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'

استدعاء الاستثناءات

يتم ذلك باستخدام عدة طرق وفق تعليمة الاستدعاء.

الشيفرة البرمجية

raise[Exception[,args[,traceback]]]

هنا Exceptionهي نموذج من الاستثناء و argument هي قيمة مدخل الاستثناء وهو اختياري وفي حال لم يوضع بشكل صريح فإن مدخل الاستثناء لاشيء.

مثال

يمكن أن يكون الاستثناء سلسلة أو صفاً أو غرضاً ولكنها في المعظم صفوف مع مدخلات تمثل مسافة الصف كما ان تعريف استثناءات جديدة أمر سهل يتم وفق التالي:

def functionName( level ):
if level <1:
raise "Invalid level!", level
# The code below to this would not be executed
# if we raise the exception

مثال

من أجل التقاط الاستثناء السابق يجب كتابة عبارة الاستثناء كالتالي-

try:
Business Logic here...
except "Invalid level!":
Exception handling here...
else:
Rest of the code here...

الاستثناءات المعرفة من قبل المستخدم

يتم ذلك باشتقاق الصفوف من الاستثناءات المبنية المعيارية.
في المثال التالي يتم إنشاء الصف والذي هو صف فرعي من RuntimeError وهو مفيد عند الحاجة لعرض معلومات مفصلة اكثر عند التقاط الاستثناء.
في الكتلة try يتم استدعاء الاستثناء المعرف من قبل المستخدم والتقاطه ضمن كتلة الاستثناء. يستخدم المتحول e لإنشاء المسافة ضمن الصف Networkerror .

class Networkerror(RuntimeError):
def __init__(self, arg):
self.args=arg

لذلك عندما يتم تعريف الصف كما في الأعلى فإنه يمكن استدعاء الاستثناء كالتالي-

try:
raise Networkerror("Bad hostname")
except Networkerror,e:
print e.args