بنية اللغة

من موسوعة حسوب
< Python
مراجعة 19:22، 29 نوفمبر 2018 بواسطة Mohammed Taher (نقاش | مساهمات) (←‏بنية السطر)
(فرق) → مراجعة أقدم | المراجعة الحالية (فرق) | مراجعة أحدث ← (فرق)
اذهب إلى التنقل اذهب إلى البحث

تُقرأ شيفرات بايثون بواسطة المحلّل parser. مدخلات المحلّل هي تدفّق من العلامات tokens التي ينشئها محلل المفردات lexical analyzer.

يصف هذا القسم طريقة تقسيم ملفات بايثون إلى علامات بواسطة محلل المفردات.

بنية السطر

تقسم شيفرة بايثون إلى نوعين من الأسطر هما الأسطر المنطقية والأسطر الفيزيائية.

الأسطر المنطقية Logical lines

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

الأسطر الفيزيائية Physical lines

السطر الفيزيائي هو سلسلة من الحروف التي تنتهي بتسلسل نهاية السطر (end-of-line sequence). ويمكن استخدام تسلسلات انهاء السطور القياسية التابعة لأيّ من المنصات المعروفة ضمن ملفات الشيفرة المصدرية في بايثون. فيمكن استخدام تسلسل يونكس تغذية السطر LF (linefeed)‎ في ترميز ASCII‎، أو تسلسل ويندوز وهما تغذية السطر وعلامة الإرجاع CR LF في ترميز ASCII، أو استخدام تسلسل ماكنتوش وهو علامة الإرجاع CR.

الدمج الصريح للسطور

يمكن دمج سطرين فيزيائين أو أكثر في سطور منطقية باستخدام حرف الخط المائل العكسي (\) وكما يلي:

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

فعلى سبيل المثال: 

if 1900 < year < 2100 and 1 <= month <= 12 \
   and 1 <= day <= 31 and 0 <= hour < 24 \
   and 0 <= minute < 60 and 0 <= second < 60:
        return 1

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

الدمج الضمني للسطور

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

month_names = ['Januari', 'Februari', 'Maart',      # هذه هي
               'April',   'Mei',      'Juni',       # أسماء أشهر
               'Juli',    'Augustus', 'September',  # السنة الميلادية
               'Oktober', 'November', 'December']   # في اللغة الألمانية

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

الإزاحة Indentation

تستخدم المسافات البيضاء (الفراغات spaces أو علامات الجدولة tabs) في بداية السطر المنطقي لحساب مستوى الإزاحة لذلك السطر، والذي يُستخدم بدوره لتحديد مجموعة العبارات التي تنتمي إلى كتلة واحدة.

تستبدل علامات الجدول (من اليسار إلى اليمين) بمسافة واحدة إلى ثمان مسافات بيضاء ليكون عدد الحروف من مضاعفات العدد 8 (هذه القاعدة مشابهة لما هو موجود في يونكس). ويحدّد مجموع المسافات البيضاء التي تسبق أول حرف غير فارغ (non-blank) إزاحة السطر. 

ولا يمكن تقسيم الإزاحة بين عدة سطور فيزيائية باستخدام الخط المائل العكسي، وتحدّد المسافات البيضاء التي تسبق أول خطّ مائل عكسي مقدار الإزاحة.

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

تعتمد بايثون على الإزاحة (indentation) لتجميع العبارات البرمجية، ويمكن استخدام المسافات البيضاء spaces أو علامات الجدولة tabs لإزاحة الأسطر. 

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

>>> x = 4
>>>  print(x)
  File "<stdin>", line 1
    print(x)
    ^
IndentationError: unexpected indent
>>> if (x < 3):
... print("Less than 3")
  File "<stdin>", line 2
    print("Less than 3")
        ^
IndentationError: expected an indented block

حسب دليل التنسيق PEP8 الذي تتبعه بايثون، ينصح باستخدام 4 مسافات بيضاء ‎4-‎spaces للإزاحة وتجنب استخدام علامات الجدولة tabs.

جدير بالذكر أنّ معظم محرّرات النصوص الحالية تدعم خاصية الإزاحة التلقائية auto-indent الأمر الذي يسهّل كتابة شيفرات بايثون بصورة كبيرة.

يتضمن المثال التالي شيفرة بايثون ذات إزاحات صحيحة:

def perm(l):
        # l حساب جميع توافيق
    if len(l) <= 1:
                  return [l]
    r = []
    for i in range(len(l)):
             s = l[:i] + l[i+1:]
             p = perm(s)
             for x in p:
              r.append(l[i:i+1] + x)
    return r

أما المثال التالي فيتضمن عددًا من الأخطاء في الإزاحة:

 def perm(l):                       # خطأ: إزاحة السطر الأول
for i in range(len(l)):             # خطأ: عدم وجود إزاحة
    s = l[:i] + l[i+1:]
        p = perm(l[:i] + l[i+1:])   # خطأ: إزاحة غير متوقعة
        for x in p:
                r.append(l[i:i+1] + x)
            return r                # خطأ: إزاحة غير متناسقة

التعليقات Comments

تدعم بايثون - شأنها في ذلك شأن أي لغة برمجية أخرى - استخدام التعليقات، والتعليقات في بايثون هي كل ما يأتي بعد العلامة ('#'). تفيد التعليقات في إضافة الملاحظات والتوضيحات في ثنايا الشيفرة البرمجية.

>>> # عدد المولات في النموذج
... no_of_moles = 1.2

يمكن كتابة التعليقات في سطر منفصل، كما هو موضح في المثال السابق، ويمكن إضافتها إلى نهاية السطر كما يلي:

percentage = (minute * 100) / 60        # النسبة المئوية من الساعة

سطر شيبانك shebang line

تستخدم هذه الأسطر في أنظمة يونكس و BSD لجعل شيفرات بايثون قابلة للتنفيذ بصورة مباشرة مثل شيفرات الصدفة، وذلك بإضافة سطر مثل:

#!/usr/bin/env python3.5

(على فرض أن مفسّر بايثون موجود في متغير النظام PATH لدى المستخدم) في بداية ملف الشيفرة الذي يجب أن يكون قابلًا للتنفيذ (executable) أيضًا.

يجب أن يكون الرمزان ‎#!‎ أوّل حرفين في الملف، وفي بعض المنصّات، يجب أن تكون نهاية السطر على نمط يونكس ('‎\n') وليس نمط ويندوز (‎'\r\n'‎). 

يمكن جعل ملف الشيفرة قابلًا للتنفيذ باستخدام الأمر chmod في الصدفة:

$ chmod +x myscript.py

مفهوم نمط قابلية التنفيذ (executable mode) غير موجود في أنظمة ويندوز، إذ يربط برنامج تثبيت بايثون ملفات ‎.py بصورة تلقائية مع python.exe؛ لذا يؤدي النقر المزدوج على ملفات بايثون إلى تشغيل الشيفرة مباشرة. ويمكن استخدام اللاحقة ‎.pyw لمنع نافذة سطر الأوامر من الظهور عند تنفيذ الشيفرة.

ملاحظة: بالنسبة لبايثون فإنّ البرنامج Program والشيفرة Script والبرمجية Software تعني شيئًا واحدًا.

التصريح عن الترميز encoding

إن كان التعليق في السطر الأول أو الثاني من شيفرة بايثون مطابقًا للتعبير النمطي  coding[=:]\s*([-\w.]+)‎ فإنّ هذا السطر يمثّل التصريح عن ترميز ذلك الملف، وتمثّل المجموعة الأولى ضمن هذا التعبير اسم الترميز المطلوب استخدامه.

يجب أن يكون التصريح عن الترميز في سطر منفرد، وإن كانت عبارة التصريح هذه في السطر الثاني يجب أن يكون السطر الأوّل تعليقًا فقط. 

ينصح باستخدام الصيغة التالية للتعبير عن الترميز:

# -*- coding: <encoding-name> -*-

والتي يتعرّف عليها محرر الشيفرات البرمجية GNU Emacs. وينصح كذلك باستخدام الصيغة التالية عند استخدام محرّر النصوص VIM:

# vim:fileencoding=<encoding-name>

في حال عدم التصريح عن أي ترميز ضمن ملف الشيفرة، يُصار إلى اعتماد الترميز الافتراضي UTF-8

المعرّفات والكلمات المفتاحية

يجب أن تبدأ المعرّفات (تعرف أيضًا بالأسماء) بأحد الأحرف الهجائية (كبيرة أو صغيرة) أو بشرطة سفلية ('_')، أمّا باقي الاسم فيمكن أن يتكوّن من الأحرف الهجائية (كبيرة أو صغيرة) أو الأعداد (0-9) أو الشرطة السفلية ('_')، ويجب أن لا يحتوي على فواصل، وأن لا يكون اسم المتغير أحد الكلمات المحجوزة في بايثون.

المعرّفات في بايثون حساسة لحالة الأحرف، وهذا يعني أن var و Var هما معرّفان مختلفان.

يبيّن المثال التالي بعض المعرّفات الصالحة:

>>> x = 5
>>> name = "Salim"
>>> NH3_Concentrations = [1.3, 1.2, 1.15, 1.03, 0.98]
>>> _time = 0

في حال مخالفة المعرّف لقواعد التسمية تطلق اللغة خطأ الصيغة SyntaxError:

>>> 2x = 4
  File "<stdin>", line 1
    2x = 4
     ^
SyntaxError: invalid syntax
>>> my name = "Mohammed"
  File "<stdin>", line 1
    my name = "Mohammed"
          ^
>>> more@ = 1000000
  File "<stdin>", line 1
    more@ = 1000000
          ^
SyntaxError: invalid syntax
>>> class = 'Advanced Python'
  File "<stdin>", line 1
    class = 'Advanced Python'
          ^
SyntaxError: invalid syntax

الكلمات المفتاحية

المعرّفات التالية تستخدم ككلمات محجوزة أو ما يعرف بالكلمات المفتاحية keywords ولا يمكن استخدام هذه الكلمات كأسماء للمعرّفات العادية. 

False      class      finally    is         return
None       continue   for        lambda     try
True       def        from       nonlocal   while
and        del        global     not        with
as         elif       if         or         yield
assert     else       import     pass
break      except     in         raise

مصادر