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

مقدمة

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

إذا كنت تبحث عن دورة تدريبية مصاحبة على الإنترنت من جامعة مفتوحة، جرِّب الدورات التدريبية من Udacity وCoursera (مقدمة إلى البرمجة [للمبتدئين] أو مقدمة إلى لغة بايثون). أخيرًا، إذا كنت تبحث عن تعلم ذاتي على الإنترنت بدون مشاهدة الفيديوهات، جرِّب الفيديوهات المدرَجة في نهاية هذه المشاركة، حيث تعرض كلّ منها محتوى تعليميًا بالإضافة إلى مترجم 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."، من المفترض أن تعمل هذه الأمثلة على جهازك.

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

رمز مصدر Python

تستخدم ملفات Python المصدرية امتداد "‎.py" وتُعرف باسم "الوحدات". باستخدام وحدة Python hello.py، تكون أسهل طريقة لتشغيلها هي باستخدام الأمر shell "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] هو الوسيطة الأولى، وما إلى ذلك. إذا كنت تعرف argc أو عدد الوسيطات، يمكنك ببساطة طلب هذه القيمة من 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") تصف وظيفة الدالة. يمكن أن يكون نص وصف الدالة سطرًا واحدًا أو وصفًا مكوّنًا من عدة أسطر كما هو موضّح في المثال أعلاه. (نعم، هذه عبارة عن "علامات اقتباس ثلاثية"، وهي ميزة فريدة في لغة بايثون!) إنّ المتغيّرات المحدّدة في الدالة تكون محلية لهذه الدالة، لذا فإنّ "النتيجة" في الدالة أعلاه منفصلة عن متغيّر "النتيجة" في دالة أخرى. يمكن أن تأخذ عبارة return وسيطة، وفي هذه الحالة تكون القيمة التي يتم إرجاعها إلى المُتصل.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

على سبيل المثال، لدينا وحدة "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 العادية". تشمل الوحدات أو الحِزم الشائعة الاستخدام ما يلي:

  • sys: للوصول إلى exit() وargv وstdin وstdout وما إلى ذلك
  • re — التعبيرات العادية
  • os — واجهة نظام التشغيل ونظام الملفات

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

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

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

  • أجرِ عملية بحث على Google، بدءًا من كلمة "python" مثل "python list" أو "python string صغيرة". وغالبًا ما تكون النتيجة الأولى هي الإجابة. يبدو أنّ هذه الطريقة تعمل بشكل أفضل مع لغة 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