Latest web development tutorials

أخطاء Python3 والاستثناءات

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

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

خطأ في بناء الجملة

بيثون أخطاء في بناء الجملة أو خطأ تحليلي المكالمة، مبتدئين، كثيرا ما يواجهون، كأمثلة

>>> while True print('Hello world')
  File "<stdin>", line 1, in ?
    while True print('Hello world')
                   ^
SyntaxError: invalid syntax

في هذا المثال، يتم فحص الطباعة وظيفة () عن الأخطاء قبل أن مفقود بنقطتين (:).

وأشار محلل من الخطأ من حزبه، وفي المكان الخطأ في العثور على أول علامة على السهم الصغير.

غير طبيعي

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

معظم لن يكون معالج استثناء في شكل رسائل الخطأ عرض هنا:

>>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: Can't convert 'int' object to str implicitly

يبدو غير طبيعي في أنواع مختلفة، وتطبع هذه الأنواع كجزء من المعلومات: أمثلة على أنواع ZeroDivisionError، NameError وTypeError.

الجزء الأمامي من رسالة الخطأ يظهر سياق استثناء يحدث، مكدس الاستدعاءات وعرضها في شكل معلومات محددة.

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

في المثال التالي، يسمح للمستخدمين بإدخال عدد صحيح صحيح، ولكن يسمح للمستخدم ليقطع برنامج (باستخدام مراقبة-C أو أساليب نظام التشغيل المقدمة). وانقطاع المستخدم يسبب استثناء KeyboardInterrupt.

>>> while True:
        try:
            x = int(input("Please enter a number: "))
            break
        except ValueError:
            print("Oops!  That was no valid number.  Try again   ")
   

محاولة الأعمال بيان على النحو التالي؛

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

قد تحتوي على بيان أكثر من محاولة باستثناء شرط، للتعامل مع استثناءات محددة مختلفة. في معظم فرع واحد وسيتم تنفيذ.

معالج فقط لتجهيز المناظر استثناء شرط المحاولة، بدلا من غيرها من معالج الاستثناء المحاولة.

وباستثناء بند يمكن معالجة الاستثناءات المتعددة التي سيتم وضعها في قوس باعتباره الصفوف (tuple)، على سبيل المثال:

    except (RuntimeError, TypeError, NameError):
        pass

آخر باستثناء بند قد تجاهل اسم استثناء، ستعامل على أنها البدل. يمكنك استخدام هذا الأسلوب لطباعة رسالة الخطأ، ومن ثم القيت مرة أخرى.

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except:
    print("Unexpected error:", sys.exc_info()[0])
    raise

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

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

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

معالجة الاستثناء لا يتعامل فقط مع تلك الاستثناءات تحدث محاولة مباشرة الشرط، ولكن أيضا لدعوة بند معالج (حتى المكالمات وظيفة غير مباشرة) حيث القيت. على سبيل المثال:

>>> def this_fails():
        x = 1/0
   
>>> try:
        this_fails()
    except ZeroDivisionError as err:
        print('Handling run-time error:', err)
   
Handling run-time error: int division or modulo by zero

رمي استثناء

يستخدم الثعبان بيان رمي لرفع استثناء محدد. على سبيل المثال:

>>> raise NameError('HiThere')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: HiThere

رفع تحدد معلمة واحدة فقط باستثناء أن يلقى. يجب أن يكون مثيل غير عادي من فئة أو غير طبيعية (أي استثناء فئة فرعية).

إذا كنت تريد أن تعرف إذا كان يطرح استثناء، لا تريد التعامل معها، ثم بيان بسيط يمكن رفعه القيت مرة أخرى.

>>> try:
        raise NameError('HiThere')
    except NameError:
        print('An exception flew by!')
        raise
   
An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
NameError: HiThere

استثناءات المعرفة

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

>>> class MyError(Exception):
        def __init__(self, value):
            self.value = value
        def __str__(self):
            return repr(self.value)
   
>>> try:
        raise MyError(2*2)
    except MyError as e:
        print('My exception occurred, value:', e.value)
   
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
__main__.MyError: 'oops!'

في هذا المثال، الطبقة استثناء __init الافتراضي __ () هو الكتابة.

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

class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class InputError(Error):
    """Exception raised for errors in the input.

    Attributes:
        expression -- input expression in which the error occurred
        message -- explanation of the error
    """

    def __init__(self, expression, message):
        self.expression = expression
        self.message = message

class TransitionError(Error):
    """Raised when an operation attempts a state transition that's not
    allowed.

    Attributes:
        previous -- state at beginning of transition
        next -- attempted new state
        message -- explanation of why the specific transition is not allowed
    """

    def __init__(self, previous, next, message):
        self.previous = previous
        self.next = next
        self.message = message

معظم الأسماء هي الاستثناء إلى "خطأ" في النهاية، تماما مثل التسمية القياسية غير طبيعية.


السلوك تنظيف محددة

بيان محاولة ديه بند اختياري آخر، وهو يعرف ان سلوك التنظيف تحت أي ظرف من الظروف أداء. على سبيل المثال:

>>> try:
        raise KeyboardInterrupt
	finally:
        print('Goodbye, world!')
   
Goodbye, world!
KeyboardInterrupt

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

إذا تم طرح استثناء في بند محاولة (أو إلا وشرط آخر)، ولكن ليس لديهم أي إلا أنها توقفت، ثم هذا سوف تثار مرة أخرى بعد تنفيذ شرط أخيرا.

هنا هو مثال أكثر تعقيدا (الواردة في البيان نفسه في محاولة فيما عدا وبند أخيرا):

>>> def divide(x, y):
        try:
            result = x / y
        except ZeroDivisionError:
            print("division by zero!")
        else:
            print("result is", result)
        finally:
            print("executing finally clause")
   
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

السلوك تنظيف محددة سلفا

بعض الكائنات تحدد معيار السلوك تنظيف، بغض النظر عن ما إذا كان يتم استخدام النظام بنجاح مرة واحدة لا تحتاج إليها، ثم تنظيف يتم تنفيذ هذا السلوك القياسية.

هذا المثال يبين يحاول هذا الجانب لفتح ملف ثم طباعة محتويات على الشاشة:

for line in open("myfile.txt"):
    print(line, end="")

المشكلة أعلاه مع هذا الرمز هو أنه عندما انتهى، يبقى الملف مفتوحا، لم يغلق.

وسيتم الانتهاء من الأجسام كلمات مع بيان يمكن ضمان مثل الملفات باستخدام التنفيذ الصحيح للله أساليب التنظيف:

with open("myfile.txt") as f:
    for line in f:
        print(line, end="")

بعد الانتهاء من رمز أعلاه، حتى لو كانت المشاكل في هذه العملية، يتم إغلاق ملف و دائما.