11  الخطأ

ينقسم الخطأ لثلاثة أنواع:

  1. نحوي (Syntactic): وهو الخطأ في مبنى اللغة؛ أي: مخالفة قواعدها وقوانينها.
  2. منطقي (Logical): وهو تعبيرٌ صحيحٌ نحويًّا لكنَّه لا يؤدي المقصود الذي في ذهنك.
  3. عملي (Runtime): ويسمى الاستثناء وهو حالة غير مثالية يجب أن يتعامل معها الرنامج.

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

الخطأ النحوي

الأخطاء النحوية تتعلق بتركيب اللغة لا أكثر ولا أقل. إليك ثلاثة أمثلة.

1. فقدان النقطتين :

لاحظ عدم النقطيتن بعد الشرط (if x > 5).

if x > 5
    print("x")
  Cell In[1], line 1
    if x > 5
            ^
SyntaxError: expected ':'

2. علامات اقتباس غير متوازنة

لاحظ عدم علامة الاقتباس (") للنص.

print("x
  Cell In[2], line 1
    print("x
          ^
SyntaxError: unterminated string literal (detected at line 1)

3. اسم غير صالح

لاحظ أن بايثون تسمح بالشرطة السفلية (_) لكن هنا ستعملنا الشرطة (-) التي يظنها علامة طرح.

my-variable = 10
  Cell In[3], line 1
    my-variable = 10
    ^
SyntaxError: cannot assign to expression here. Maybe you meant '==' instead of '='?

أخطاء المحاذاة

من الأخطاء النحوية الشائعة في بايثون: خطأ المحاذاة (Indentation Error).

وذلك أن بايثون تقبل نوعين من المسافات البادئة للسطر:

  1. إما بحرف المسافة التي بين الكلمات \s
  2. أو بحرف المسافة بين الأعمدة \t

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

وإليك بعض الأمثلة لما يحصل من أخطاء في المحاذاة:

  1. عدم وجود مسافة بادئة، عندما تكون متوقعة:
if True:
print("x")
  Cell In[4], line 2
    print("x")
    ^
IndentationError: expected an indented block after 'if' statement on line 1
  1. عدم تطابق المحاذاة:
if True:
    print("x")
     print('y')
  Cell In[5], line 3
    print('y')
    ^
IndentationError: unexpected indent

تجويد العبارة

من تجويد العبارة تسمية المتغيرات بما يدل على وظيفتها، مثل:

rate = 50
hours_per_day = 6
days = 5
pay = rate * hours_per_day * days
print(pay)
1500

وإن كان ليس من الخطأ النحوي كتابتها بطريقة مختلفة وبأسماء غير معبِّرة، إلا أنه فعلٌ غير مستحسن:

r, hpd, d = 50, 6, 5
p = r * hpd * d
print(p)
1500

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

الخطأ المنطقي

وهي التي نقصدها حين نقول: بَق (Bug) بمعنى: مشكلة في البرنامج. ويسمى البرنامج الذي يساعد في إصلاح المشاكل البرمجية: المدقق (Debugger). وتسمى وعملية البحث عنها وإصلاحها: التدقيق (Debugging).

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

  • افتراضات غير صحيحة
  • خطوات غير مؤديَّة للمقصود

وإليك بعض الأمثلة ..

1. استعمال الإجراء الخاطئ

هنا يريد المبرمج استعمال دالَّة التربيع (Square) فظنَّها math.sqrt لكن هذه (Square Root) أي: الجذر التربيعي. والصحيح أن يختار: math.pow(4, 2) لرفع 4 للقوة 2.

import math

square = math.sqrt(4)

2. استعمال العامل الخاطئ

هنا تمَّت المقارنة بين نوعين مختلفين أصلاً: int و str لكنَّ المبرمج لم يستوعِب ذلك، فحصل الخطأ وهو لا يدري لماذا x لا تساوي y عندما يكون كلاهما 16؟ وهذا قد يبدو لك واضحًا وذلك لأننا عزلنا المثال عن غيره من التفاصيل فظهر جليًّا.

x = 16
y = "16"
if (x == y):
    print('equal')

3. مستوى محاذاة خاطئ

هنا كانت النية تقتضي أن تكون print(j) داخل الحلقة الداخلية. لكن إن كانت النيَّة كما كُتب فليس بخطأ طبعًا.

for i in range(2):
    for j in range(3):
        print(i)  
    print(j)
0
0
0
2
1
1
1
2

4. خطأ الحافَّة

خطأ الحافَّة (Off-by-one error)، يكاد يكون أشهر الأخطاء في البرمجة.

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

for i in range(5, 0, -1):
    print(i)
5
4
3
2
1

كشف الأخطاء المنطقية

لكونها جملاً صحيحة في ذاتها؛ لا يستطيع البرنامج كشف هذه الأخطاء لوحده. بل يجب على من يُدركُ حقيقة المطلوب من البرنامج أن يتكفل بذلك. وهنا تكون الحاجة ماسَّة لجمل التوكيد: assert وقد رأيناها كثيرًا.

والتدقيق؛ إذْ أفضل طريقة لحل الأخطاء المنطقية هي تنفيذ القطعة البرمجية والنظر في الناتج، وتتبع المنطق مرة أخرى إلى النص البرمجي سطرًا بسطر. يمكنك استخدام عبارات الطباعة print لتصحيح الأخطاء وفهم تدفق البرنامج. وقد يكون الأفضل من ذلك استعمال المدقق (Debugger).

ومراجعة الأقران: بحيث يطلع على النص البرمجي شخص آخر، فإنه قد يرى منه ما تعذر عليك رؤيته. وقد يتم تنظيمه بين أعضاء الفريق الواحد بأحد برمجيات التعاون مثل: GitHub وGitLab وBitbucket وغيرها. لكن ليس شرطًا أن يكون بطريقة منظَّمة حتى تستفيد منه.

المصطلحات

العربية الإنجليزية
الخطأ النحوي Syntactic Error
الخطأ المنطقي Logical Error
الخطأ العملي Runtime Error
الاستثناء Exception
أخطاء المحاذاة Indentation Error
أسلوب الكتابة Code Style
خطأ الحافَّة Off-by-one Error
المدقق Debugger
التدقيق Debugging
جمل التوكيد Assert Statements
مراجعة الأقران Peer Review
برمجيات التعاون Collaboration Tools