مقدمة إلى بايثون

مقدمة

مرحبًا بك في البرنامج التعليمي على الإنترنت حول لغة Python من Google. ويستند إلى دورة Python التمهيدية المقدَّمة داخليًا. كما هو موضّح في صفحة الإعداد، تغطي هذه المواد الإصدار 3 من لغة Python.

إذا كنت تبحث عن دورة تدريبية مفتوحة على الإنترنت (MOOC) مصاحبة، جرِّب الدورات التدريبية من Udacity وCoursera (مقدمة في البرمجة [للمبتدئين] أو مقدمة في لغة Python). أخيرًا، إذا كنت تبحث عن تعلّم ذاتي على الإنترنت بدون مشاهدة فيديوهات، يمكنك تجربة الدورات التدريبية المدرَجة في نهاية هذه المشاركة، إذ يقدّم كل منها محتوى تعليميًا بالإضافة إلى مترجم تفاعلي للغة Python يمكنك التدريب عليه. ما المقصود بـ "المترجم" الذي ذكرناه؟ سنتعرّف على ذلك في القسم التالي.

مقدمة عن اللغة

بايثون هي لغة ديناميكية ومفسَّرة (مجمَّعة في رمز بايت). لا تتضمّن رموز المصدر تعريفات أنواع المتغيّرات أو المَعلمات أو الدوال أو الطرق. يؤدي ذلك إلى جعل الرمز قصيرًا ومرنًا، كما تفقد عملية التحقّق من نوع الرمز المصدري في وقت الترجمة. تتتبّع لغة Python أنواع جميع القيم في وقت التشغيل وتضع علامة على الرموز التي لا معنى لها أثناء تنفيذها.

تتمثّل إحدى الطرق الممتازة لمعرفة طريقة عمل رموز Python البرمجية في تشغيل مترجم Python وكتابة الرموز مباشرةً فيه. إذا كان لديك أي سؤال مثل "ماذا يحدث إذا أضفت int إلى list؟"، فإنّ كتابة السؤال في مفسّر Python هي الطريقة الأسرع والأفضل على الأرجح لمعرفة ما سيحدث. (يمكنك الاطّلاع أدناه على ما يحدث فعلاً).

$ python3        ## Run the Python interpreter
Python 3.X.X (XXX, XXX XX XXXX, XX:XX:XX) [XXX] on XXX
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 6       ## set a variable in this interpreter session
>>> a           ## entering an expression prints its value
6
>>> a + 2
8
>>> a = 'hi'    ## 'a' can hold a string just as well
>>> a
'hi'
>>> len(a)      ## call the len() function on a string
2
>>> a + len(a)  ## try something that doesn't work
Traceback (most recent call last):
  File "", line 1, in 
TypeError: can only concatenate str (not "int") to str
>>> a + str(len(a))  ## probably what you really wanted
'hi2'
>>> foo         ## try something else that doesn't work
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'foo' is not defined
>>> ^D          ## type CTRL-d to exit (CTRL-z in Windows/DOS terminal)

يخبرك السطران اللذان تعرضهما لغة Python بعد كتابة python وقبل ظهور الطلب >>> عن إصدار لغة Python الذي تستخدمه ومكان إنشائه. طالما أنّ أول ما تتم طباعته هو "Python 3"، من المفترض أن تعمل هذه الأمثلة لديك.

كما هو موضّح أعلاه، من السهل تجربة المتغيّرات وعوامل التشغيل. بالإضافة إلى ذلك، يعرض المترجم الفوري خطأ وقت التشغيل، أو "يرفع" في لغة Python، إذا حاول الرمز قراءة متغير لم يتم تعيين قيمة له. مثل C++‎ وJava، إنّ Python حساسة لحالة الأحرف، لذا فإنّ "a" و "A" هما متغيران مختلفان. تشير نهاية السطر إلى نهاية الجملة، لذا على عكس C++‎ وJava، لا تتطلّب لغة Python إضافة فاصلة منقوطة في نهاية كل جملة. تبدأ التعليقات بعلامة "#" وتمتد إلى نهاية السطر.

رمز المصدر Python

تستخدم ملفات مصدر Python الامتداد ".py" ويُطلق عليها اسم "وحدات". باستخدام وحدة Python hello.py، أسهل طريقة لتشغيلها هي استخدام أمر الصدفة "python hello.py Alice" الذي يستدعي مترجم Python لتنفيذ الرمز في hello.py، مع تمرير وسيط سطر الأوامر "Alice" إليه. يمكنك الاطّلاع على صفحة المستندات الرسمية لمعرفة جميع الخيارات المختلفة المتاحة عند تشغيل Python من سطر الأوامر.

في ما يلي برنامج hello.py بسيط جدًا (لاحظ أنّ مقاطع الرمز البرمجي يتم تحديدها بدقة باستخدام المسافة البادئة بدلاً من الأقواس المتعرجة، وسنتحدّث عن ذلك لاحقًا):

#!/usr/bin/python3

# import modules used here -- sys is a very standard one
import sys

# Gather our code in a main() function
def main():
    print('Hello there', sys.argv[1])
    # Command line args are in sys.argv[1], sys.argv[2] ...
    # sys.argv[0] is the script name itself and can be ignored

# Standard boilerplate to call the main() function to begin
# the program.
if __name__ == '__main__':
    main()

يبدو تشغيل هذا البرنامج من سطر الأوامر على النحو التالي:

$ python3 hello.py Guido
Hello there Guido
$ ./hello.py Alice  ## without needing 'python3' first (Unix)
Hello there Alice

عمليات الاستيراد ووسيطات سطر الأوامر وlen()

تنفّذ العبارات الخارجية في ملف Python أو "الوحدة" عملية الإعداد لمرة واحدة، ويتم تنفيذ هذه العبارات من أعلى إلى أسفل في المرة الأولى التي يتم فيها استيراد الوحدة في مكان ما، ما يؤدي إلى إعداد المتغيرات والدوال. يمكن تشغيل وحدة Python مباشرةً، كما هو موضح أعلاه python3 hello.py Bob، أو يمكن استيرادها واستخدامها بواسطة وحدة أخرى. عند تشغيل ملف Python مباشرةً، يتم ضبط المتغيّر الخاص "__name__" على "__main__". لذلك، من الشائع استخدام الرمز النموذجي if __name__ ==... الموضّح أعلاه لاستدعاء الدالة main()‎ عند تشغيل الوحدة مباشرةً، ولكن ليس عند استيراد الوحدة من خلال وحدة أخرى.

في برنامج Python عادي، تحتوي القائمة sys.argv على وسيطات سطر الأوامر بالطريقة العادية، حيث يمثّل sys.argv[0] البرنامج نفسه، ويمثّل sys.argv[1] الوسيطة الأولى، وهكذا. إذا كنت تعرف argv أو عدد الوسيطات، يمكنك ببساطة طلب هذه القيمة من Python باستخدام len(sys.argv)، تمامًا كما فعلنا في رمز المفسّر التفاعلي أعلاه عند طلب طول سلسلة. بشكل عام، يمكن أن تخبرك len() بمدة السلسلة وعدد العناصر في القوائم والمجموعات (وهي بنية بيانات أخرى تشبه المصفوفة) وعدد أزواج المفتاح والقيمة في القاموس.

الدوال المعرَّفة من قِبل المستخدم

يتم تعريف الدوال في Python على النحو التالي:

# Defines a "repeat" function that takes 2 arguments.
def repeat(s, exclaim):
    """
    Returns the string 's' repeated 3 times.
    If exclaim is true, add exclamation marks.
    """

    result = s + s + s # can also use "s * 3" which is faster (Why?)
    if exclaim:
        result = result + '!!!'
    return result

لاحظ أيضًا كيف يتم تجميع الأسطر التي تشكّل الدالة أو عبارة if من خلال امتلاكها جميعًا لمستوى المسافة البادئة نفسه. عرضنا أيضًا طريقتَين مختلفتَين لتكرار السلاسل، باستخدام عامل الجمع (+) الذي يسهل استخدامه، ولكن يمكن أيضًا استخدام علامة الضرب (*) لأنّها عامل "التكرار" في Python، ما يعني أنّ '-' * 10 ينتج عنه '----------'، وهي طريقة رائعة لإنشاء "خط" على الشاشة. في تعليق الرمز، أشرنا إلى أنّ علامة الضرب (*) تعمل بشكل أسرع من علامة الجمع (+)، والسبب هو أنّ علامة الضرب تحسب حجم العنصر الناتج مرة واحدة، بينما يتم إجراء هذا الحساب في كل مرة يتم فيها استدعاء علامة الجمع. يُطلق على كل من + و * اسم عوامل التشغيل "المحمّلة بشكل زائد" لأنّها تعني أشياء مختلفة للأرقام مقارنةً بالسلاسل (وأنواع البيانات الأخرى).

تحدّد الكلمة الرئيسية def الدالة مع مَعلماتها بين قوسَين ويتم ترك مسافة بادئة للرمز الخاص بها. يمكن أن يكون السطر الأول من الدالة سلسلة مستندات ("docstring") تصف ما تفعله الدالة. يمكن أن يكون سلسلة التوثيق سطرًا واحدًا أو وصفًا متعدد الأسطر كما في المثال أعلاه. (نعم، هذه "علامات اقتباس ثلاثية"، وهي ميزة فريدة في Python). المتغيرات المحدّدة في الدالة تكون محلية بالنسبة إلى تلك الدالة، وبالتالي فإنّ "النتيجة" في الدالة أعلاه منفصلة عن المتغير "النتيجة" في دالة أخرى. يمكن أن تأخذ عبارة return وسيطة، وفي هذه الحالة تكون هذه هي القيمة التي يتم إرجاعها إلى المتصل.

في ما يلي رمز يستدعي الدالة repeat() أعلاه، ويطبع القيمة التي تعرضها:

def main():
    print(repeat('Yay', False))      ## YayYayYay
    print(repeat('Woo Hoo', True))   ## Woo HooWoo HooWoo Hoo!!!

في وقت التشغيل، يجب تحديد الدوال من خلال تنفيذ "def" قبل استدعائها. من الشائع تحديد دالة main() في أسفل الملف مع الدوال التي تستدعيها أعلاه.

المسافة البادئة

من الميزات غير العادية في Python أنّ المسافة البيضاء البادئة لفقرة من الرمز البرمجي تؤثر في معناها. يجب أن يكون لجميع الجمل البرمجية المنطقية، مثل تلك التي تشكّل دالة، المسافة البادئة نفسها، ويجب أن تكون المسافة البادئة مضبوطة من المسافة البادئة للدالة الرئيسية أو "if" أو أي شيء آخر. إذا كان أحد الأسطر في مجموعة يتضمّن مسافة بادئة مختلفة، سيتم وضع علامة عليه كخطأ في الصيغة.

قد يبدو استخدام المسافات البيضاء في Python غريبًا بعض الشيء في البداية، لكنه منطقي وقد اعتدتُ عليه بسرعة كبيرة. تجنَّب استخدام علامات التبويب لأنّها تعقّد نظام المسافة البادئة بشكل كبير (بالإضافة إلى أنّ علامات التبويب قد تعني أشياء مختلفة على منصات مختلفة). اضبط أداة التعديل على إدراج مسافات بدلاً من علامات التبويب لرموز Python البرمجية.

السؤال الشائع الذي يطرحه المبتدئون هو: "كم عدد المسافات التي يجب أن أستخدمها للمسافة البادئة؟" وفقًا لدليل أسلوب Python الرسمي (PEP 8)، يجب استخدام 4 مسافات بادئة. (معلومة طريفة: تنص إرشادات الأسلوب الداخلية في Google على ترك مسافة بادئة بمقدار مسافتين).

التحقّق من الرمز البرمجي أثناء التشغيل

لا يجري Python سوى القليل من عمليات التحقّق في وقت الترجمة البرمجية، ويؤجّل جميع عمليات التحقّق من النوع والاسم وما إلى ذلك في كل سطر إلى حين تنفيذ هذا السطر. لنفترض أنّ الدالة main() أعلاه تستدعي الدالة repeat() على النحو التالي:

def main():
    if name == 'Guido':
        print(repeeeet(name) + '!!!')
    else:
        print(repeat(name))

تحتوي عبارة if على خطأ واضح، حيث تم إدخال الدالة repeat() عن طريق الخطأ باسم repeeeet(). الأمر المضحك في لغة Python هو أنّ هذا الرمز البرمجي يتم تجميعه وتشغيله بشكل جيد طالما أنّ الاسم في وقت التشغيل ليس "Guido". لن يتم رصد عدم توفّر هذه الدالة إلا عندما تحاول عملية التنفيذ تنفيذ repeeeet()، وسيظهر خطأ في هذه الحالة. هناك أيضًا خطأ ثانٍ في هذا المقتطف، وهو أنّه لم يتم تعيين قيمة للاسم قبل مقارنته بـ "Guido". ستعرض لغة Python الخطأ NameError إذا حاولت تقييم متغير غير معيّن. في ما يلي بعض الأمثلة التي توضّح أنّه عند تشغيل برنامج Python للمرة الأولى، ستكون بعض الأخطاء الأولى التي تظهر لك عبارة عن أخطاء إملائية بسيطة أو متغيرات غير مهيأة مثل هذه. هذا أحد المجالات التي تتفوّق فيها اللغات التي تتضمّن نظام أنواع أكثر تفصيلاً، مثل Java، إذ يمكنها رصد هذه الأخطاء في وقت الترجمة (ولكن بالطبع عليك الحفاظ على جميع معلومات الأنواع هذه، وهذا يمثّل مفاضلة).

قدّمت لغة Python 3 تلميحات الأنواع. تتيح لك تلميحات الأنواع تحديد نوع كل وسيطة في الدالة، بالإضافة إلى نوع العنصر الذي تعرضه الدالة. على سبيل المثال، في الدالة التي تمّت إضافة تعليقات توضيحية إليها def is_positive(n: int) -> bool:، تكون الوسيطة n عبارة عن int وتكون القيمة المعروضة عبارة عن bool. سنتعرّف على معنى هذه الأنواع لاحقًا. مع ذلك، تكون تلميحات الأنواع اختيارية تمامًا. ستلاحظ أنّ المزيد والمزيد من الرموز البرمجية تستخدم تلميحات الأنواع، لأنّه في حال استخدامها، يمكن لبعض أدوات التعديل، مثل cider-v وVS.code، إجراء عمليات تحقّق للتأكّد من أنّه يتم استدعاء الدوال باستخدام أنواع الوسيطات الصحيحة. ويمكنه حتى اقتراح وسيطات والتحقّق من صحتها أثناء تعديل الرمز. لن يتناول هذا البرنامج التعليمي تلميحات الأنواع، ولكننا نريد التأكّد من أنّك على دراية بها إذا سمعت عنها أو رأيتها في أي مكان.

أسماء المتغيّرات

بما أنّ متغيّرات Python لا تتضمّن أي نوع موضّح في رمز المصدر، من المفيد جدًا إعطاء أسماء ذات معنى لمتغيّراتك لتذكير نفسك بما يحدث. لذا، استخدِم "name" إذا كان اسمًا واحدًا، و"names" إذا كانت قائمة أسماء، و"tuples" إذا كانت قائمة من الصفوف. ينتج العديد من أخطاء Python الأساسية عن نسيان نوع القيمة الموجودة في كل متغير، لذا استخدِم أسماء المتغيرات (كل ما لديك حقًا) للمساعدة في الحفاظ على الأمور واضحة.

في ما يتعلق بالتسمية الفعلية، تفضّل بعض اللغات استخدام أجزاء_مسطّرة لأسماء المتغيرات المكوّنة من "أكثر من كلمة واحدة"، بينما تفضّل لغات أخرى استخدام أسلوب camelCasing. بشكل عام، تفضّل لغة Python طريقة استخدام الشرطة السفلية، ولكنها توجّه المطوّرين إلى استخدام طريقة camelCasing في حال الدمج مع رموز Python البرمجية الحالية التي تستخدم هذا النمط. عدد الأحرف القابلة للقراءة يمكنك الاطّلاع على مزيد من المعلومات في القسم الخاص باصطلاحات التسمية في PEP 8.

كما يمكنك تخمين ذلك، لا يمكن استخدام كلمات مثل "if" و"while" كأسماء للمتغيرات، وسيظهر لك خطأ في بناء الجملة إذا فعلت ذلك. ومع ذلك، احرص على عدم استخدام العناصر المضمّنة كأسماء للمتغيرات. على سبيل المثال، على الرغم من أنّ الأسماء str وlist وprint قد تبدو أسماءً جيدة، إلا أنّك ستتجاوز متغيرات النظام هذه. لا تُعدّ العناصر المضمّنة كلمات رئيسية، وبالتالي فهي عرضة للاستخدام غير المقصود من قِبل مطوّري Python الجدد.

مزيد من المعلومات حول الوحدات ومساحات الأسماء

لنفترض أنّ لديك الوحدة "binky.py" التي تحتوي على "def foo()". الاسم المؤهّل بالكامل للدالة foo هو "binky.foo". بهذه الطريقة، يمكن لمختلف وحدات Python النمطية تسمية الدوال والمتغيرات بأي اسم تريده، ولن تتعارض أسماء المتغيرات، فـ module1.foo يختلف عن module2.foo. في مصطلحات Python، نقول إنّ binky وmodule1 وmodule2 لكلّ منها "مساحات أسماء" خاصة بها، وهي كما تتوقّع روابط بين أسماء المتغيّرات والكائنات.

على سبيل المثال، لدينا وحدة "sys" القياسية التي تحتوي على بعض تسهيلات النظام القياسية، مثل قائمة argv ودالة exit(). باستخدام العبارة "import sys"، يمكنك بعد ذلك الوصول إلى التعريفات في وحدة sys وإتاحتها من خلال اسمها المؤهَّل بالكامل، مثل sys.exit(). (نعم، تحتوي "sys" أيضًا على مساحة اسم).

  import sys

  # Now can refer to sys.xxx facilities
  sys.exit(0)

هناك نموذج استيراد آخر يبدو على النحو التالي: "from sys import argv, exit". يؤدي ذلك إلى إتاحة argv وexit() باسميهما المختصرين، ولكننا ننصح باستخدام الشكل الأصلي مع الأسماء المؤهَّلة بالكامل لأنّه يسهل كثيرًا تحديد مصدر الدالة أو السمة.

تتضمّن عملية التثبيت العادية لمترجم Python العديد من الوحدات والحِزم، لذا ليس عليك اتّخاذ أي إجراء إضافي لاستخدامها. ويُشار إليها مجتمعةً باسم "مكتبة Python العادية". تشمل الوحدات/الحِزم الشائعة الاستخدام ما يلي:

  • sys — access to exit(), argv, stdin, stdout, ...
  • re — التعبيرات العادية
  • os — واجهة نظام التشغيل ونظام الملفات

يمكنك الاطّلاع على مستندات جميع وحدات ومجموعات المكتبة القياسية على الرابط http://docs.python.org/library.

المساعدة على الإنترنت وhelp() وdir()

تتوفّر مجموعة متنوعة من الطرق للحصول على المساعدة بشأن Python.

  • أجرِ بحثًا على Google يبدأ بالكلمة "python"، مثل "قائمة python" أو "سلسلة python بأحرف صغيرة". غالبًا ما تكون النتيجة الأولى هي الإجابة. يبدو أنّ هذه التقنية تعمل بشكل أفضل مع لغة Python مقارنةً باللغات الأخرى لسبب ما.
  • يوفّر موقع مستندات Python الرسمي docs.python.org مستندات عالية الجودة. ومع ذلك، أجد غالبًا أنّ البحث على Google باستخدام بضع كلمات يكون أسرع.
  • تتوفّر أيضًا قائمة بريدية رسمية خاصة بالمعلّمين مصمَّمة خصيصًا للمستخدمين الجدد في Python و/أو البرمجة.
  • يمكن العثور على العديد من الأسئلة (والإجابات) على StackOverflow وQuora.
  • استخدِم الدالتين help() وdir() (انظر أدناه).

داخل مفسّر Python، تسترد الدالة help() سلاسل المستندات الخاصة بالوحدات والدوال والطرق المختلفة. تشبه سلاسل المستندات هذه javadoc في Java. تخبرك الدالة dir() بسمات أحد العناصر. في ما يلي بعض الطرق لاستدعاء الدالتَين help() وdir() من المترجم:

  • help(len) — سلسلة مساعدة للدالة المضمّنة len()، لاحظ أنّها "len" وليس "len()"، وهو استدعاء للدالة، وهو ما لا نريده
  • help(sys): سلسلة مساعدة لوحدة sys (يجب تنفيذ import sys أولاً)
  • dir(sys): تشبه dir() help() ولكنّها تعرض قائمة سريعة بالرموز المحدّدة أو "السمات"
  • help(sys.exit): سلسلة مساعدة للدالة exit() في الوحدة sys
  • help('xyz'.split): سلسلة مساعدة للطريقة split() الخاصة بكائنات السلسلة يمكنك استدعاء help() باستخدام العنصر نفسه أو مثال على هذا العنصر، بالإضافة إلى سمته. على سبيل المثال، الاتصال بالرقم help('xyz'.split) هو نفسه الاتصال بالرقم help(str.split).
  • help(list): سلسلة مساعدة بشأن عناصر list
  • dir(list): تعرض سمات العنصر list، بما في ذلك طُرقها
  • help(list.append): سلسلة مساعدة لطريقة append() لعناصر list