مقدمة
هذا دليل تعليمي موجز للمبتدئين في لغة البرمجة بايثون. بايثون لغة برمجة مفتوحة المصدر ومتعددة المنصات. تتميز بعدة خصائص تجعلها مختلفة عن لغات البرمجة الأخرى، وسهلة الاستخدام للغاية للمستخدمين الجدد.
صُممت لغة بايثون لتكون سهلة القراءة والفهم، مما يجعلها سهلة التعلم والفهم.
وهي لغة مفسرة، أي أن البرامج المكتوبة بها لا تحتاج إلى ترجمة قبل تنفيذها. يمكن تنفيذ كود بايثون فوراً، أو حتى سطراً بسطر إذا رغبت.
يمكن تضمينها في برامج أخرى كلغة برمجة نصية. يحتوي فريكاد على مُفسِّر بايثون مُدمج. يمكنك كتابة كود بايثون للتحكم في أجزاء من فريكاد. هذه ميزة قوية جداً، إذ تُمكّنك من بناء أدواتك الخاصة.
وهي قابلة للتوسيع، حيث يمكنك بسهولة إضافة وحدات جديدة إلى تثبيت بايثون الخاص بك وتوسيع وظائفه. على سبيل المثال، هناك وحدات تسمح لبايثون بقراءة وكتابة الصور، والتواصل مع تويتر، وجدولة المهام التي يُنفذها نظام التشغيل، وغيرها.
هذه مقدمة أساسية بسيطة، وليست بأي حال من الأحوال دليل تعليمي شامل. لكن نأمل أن يوفر نقطة انطلاق جيدة لمزيد من الاستكشاف لبرنامج فريكاد وآلياته. ننصح بشدة على إدخال التعليمات البرمجية المذكورة أدناه في مفسر لغة بايثون لاختبارها.
المفسر
عادةً، عند كتابة برامج الحاسوب، تفتح محرر نصوص أو بيئة برمجة خاصة (وهي في الأساس محرر نصوص مزود ببعض الأدوات الإضافية)، وتكتب البرنامج، ثم تقوم بتجميعه compile وتشغيله execute. غالباً ما يحدث خطأ أو أكثر أثناء الكتابة، مما يؤدي إلى عدم عمل البرنامج. قد تتلقى رسالة خطأ توضح لك سبب المشكلة. عندها تعود إلى محرر النصوص، وتصحح الأخطاء، ثم تعيد تشغيل البرنامج، وتكرر العملية حتى يعمل البرنامج كما هو مطلوب.
في بايثون، يمكن إتمام هذه العملية بالكامل بسلاسة داخل مُفسِّر بايثون. المُفسِّر عبارة عن نافذة بايثون تحتوي على موجه أوامر، حيث يمكنك ببساطة كتابة كود بايثون. إذا كنت قد ثبّت بايثون على جهازك (قم بتنزيله من موقع بايثون الإلكتروني [١] إذا كنت تستخدم ويندوز أو ماك، أو ثبّته من مستودع الحزم package repository. إذا كنت تستخدم جنو/لينكس GNU/Linux)، فستجد مُفسِّر بايثون في قائمة ابدأ. ولكن، كما ذُكر سابقاً، يحتوي فريكاد على مُفسِّر بايثون مُدمج: وحدة تحكم بايثون Python console.
إذا لم تجدها، فانقر على View → Panels → Python console. يمكن تغيير حجم وحدة تحكم بايثون وفصلها لتصبح نافذة حرة أيضاً.
يعرض المفسر إصدار بايثون، ثم رمز >>> الذي يمثل موجه الأوامر. كتابة التعليمات البرمجية في المفسر بسيطة: كل سطر يمثل تعليمة واحدة. عند الضغط على Enter، سيتم تنفيذ سطر التعليمات البرمجية (فوراً بعد تفسيره وبشكل غير مرئي). على سبيل المثال، جرب كتابة ما يلي:
print("hello")
print()
هو أمر في لغة بايثون، يقوم، كما هو واضح، بطباعة شيء ما على الشاشة. عند الضغط على مفتاح الإدخال (Enter)، يتم تنفيذ العملية، وتُطبع الرسالة "hello". في حال حدوث خطأ، على سبيل المثال، لنفترض أننا كتبنا:
print(hello)
سيُعلمك بايثون بذلك فوراً. في هذه الحالة، لا يتعرف بايثون على hello. تُشير الأحرف " " إلى أن المحتوى عبارة عن سلسلة نصية، وهو مصطلح برمجي يُشير إلى نص. بدون هذه الأحرف، لا يتعرف الأمر print() على hello. بالضغط على السهم العلوي، يمكنك العودة إلى آخر سطر من التعليمات البرمجية وتصحيحه.
يحتوي مفسر لغة بايثون أيضاً على نظام مساعدة مدمج. لنفترض أننا لا نفهم سبب الخطأ في print(hello) ونريد معلومات محددة حول الأمر:
help(print)
ستحصل على وصف طويل وكامل لكل ما يمكن أن يفعله الأمر print().
الآن وقد فهمت مفسرلغة بايثون، يمكننا المتابعة إلى الأمور الأكثر جدية.
المتحولات
في كثير من الأحيان، تحتاج في البرمجة إلى تخزين قيمة تحت اسم. وهنا يأتي دور المتحولات. على سبيل المثال، اكتب هذا:
a = "hello"
print(a)
ربما تفهم ما حدث هنا، لقد حفظنا السلسلة "hello" تحت الاسم a. الآن وقد أصبح a معلوماً، يمكننا استخدامه في أي مكان، على سبيل المثال في الأمر print(). يمكننا استخدام أي اسم نريده، كل ما علينا فعله هو الالتزام ببعض القواعد البسيطة، مثل عدم استخدام المسافات أو علامات الترقيم، وعدم استخدام كلمات بايثون المفتاحية. على سبيل المثال، يمكننا كتابة:
hello = "my own version of hello"
print(hello)
لم يعد hello قيمة غير مُعرَّفة. يمكن تعديل المتحولات في أي وقت، ولهذا سُميت المتحولات، إذ يمكن أن يتغير محتواها. على سبيل المثال:
myVariable = "hello"
print(myVariable)
myVariable = "good bye"
print(myVariable)
لقد قمنا بتغيير قيمة myVariable. يمكننا أيضاً نسخ المتغيرات:
var1 = "hello"
var2 = var1
print(var2)
يُنصح بتسمية متحولاتك بأسماء ذات دلالة. فبعد فترة، قد تنسى ما يمثله متغيرٌ اسمه a، ولكن إذا سميته، على سبيل المثال، myWelcomeMessage، فسيسهل عليك تذكر وظيفته. إضافةً إلى ذلك، يصبح الكود أقرب إلى أن يكون موثقاً ذاتياً.
حالة الأحرف مهمة للغاية، فـ myVariable ليس هو نفسه myvariable. إذا أدخلت print(myvariable) فسيظهر خطأ يفيد بأن المتحول غير مُعرَّف.
الأرقام
بالطبع، تستطيع برامج بايثون التعامل مع جميع أنواع البيانات، وليس فقط النصوص. لكن من المهم أن تعرف بايثون نوع البيانات التي تتعامل معها. رأينا في مثال طباعة "hello" أن الأمر print() تعرّف على سلسلة نصية "hello". باستخدام المحرف " "، حددنا أن ما يلي هو نص.
يمكننا دائماً التحقق من نوع بيانات المتحول باستخدام الأمر type():
myVar = "hello"
type(myVar)
سيُخبرنا ذلك أن محتوى myVar هو 'str'، وهو اختصار لكلمة سلسلة نصية. لدينا أيضاً أنواع بيانات أساسية أخرى مثل الأعداد الصحيحة والأعداد العشرية.
firstNumber = 10
secondNumber = 20
print(firstNumber + secondNumber)
type(firstNumber)
يعلم بايثون أن 10 و20 عددان صحيحان، لذا يتم تخزينهما على شكل 'int'، ويمكن لبايثون التعامل معهما كما يتعامل مع الأعداد الصحيحة. انظر إلى نتائج هذا:
firstNumber = "10"
secondNumber = "20"
print(firstNumber + secondNumber)
هنا أجبرنا بايثون على اعتبار المتغيرين ليسا رقمين، بل نصين. تستطيع بايثون جمع نصين معاً، ولكن في هذه الحالة، لن تُجري أي عملية حسابية. لكننا كنا نتحدث عن الأعداد الصحيحة. هناك أيضاً أعداد عشرية. الفرق هو أن الأعداد العشرية تحتوي على جزء عشري، بينما لا تحتوي الأعداد الصحيحة على جزء عشري.
var1 = 13
var2 = 15.65
print("var1 is of type ", type(var1))
print("var2 is of type ", type(var2))
يمكن خلط الأعداد الصحيحة والأعداد العشرية معاً دون مشاكل:
total = var1 + var2
print(total)
print(type(total))
بما أن var2 عدد عشري، فإن بايثون يقرر تلقائياً أن النتيجة يجب أن تكون أيضاً عدداً عشرياً. ولكن هناك حالات لا يعرف فيها بايثون نوع البيانات الذي يجب استخدامه. على سبيل المثال:
varA = "hello 123"
varB = 456
print(varA + varB)
ينتج عن ذلك خطأ، حيث أن varA عبارة عن سلسلة نصية وvarB عبارة عن عدد صحيح، ولا يعرف بايثون كيفية التعامل مع هذا الخطأ. ومع ذلك، يمكننا إجبار بايثون على التحويل بين الأنواع:
varA = "hello"
varB = 123
print(varA + str(varB))
الآن وقد أصبح كلا المتغيرين نصيين، تعمل العملية. لاحظ أننا قمنا بتحويل varB إلى نص عند الطباعة، لكننا لم نغير varB نفسه. إذا أردنا تحويل varB إلى نص بشكل دائم، فسنحتاج إلى القيام بما يلي:
varB = str(varB)
يمكننا أيضاً استخدام int() و float() للتحويل إلى عدد صحيح وعدد عشري إذا أردنا ذلك:
varA = "123"
print(int(varA))
print(float(varA))
لا بد أنك لاحظت استخدامنا للأمر print() بطرقٍ متعددة. فقد طبعنا متحولات، ومجاميع، وبيانات مختلفة مفصولة بفواصل commas، وحتى نتيجة أمر بايثون آخر. ربما لاحظت أيضاً هذين الأمرين:
type(varA)
print(type(varA))
سنحصل على النتيجة نفسها. هذا لأننا داخل المفسر، وكل شيء يُطبع تلقائياً. عندما نكتب برامج أكثر تعقيدًا تعمل خارج المفسر، لن تُطبع تلقائياً، لذا سنحتاج إلى استخدام الأمر print(). بناءً على ذلك، دعونا نتوقف عن استخدامه هنا. من الآن فصاعداً، سنكتب ببساطة:
myVar = "hello friends"
myVar
اللوائح
نوع بيانات آخر مفيد هو اللوائح. اللوائح عبارة عن مجموعة من البيانات الأخرى. لتعريف لائحة، نستخدم [ ]:
myList = [1, 2, 3]
type(myList)
myOtherList = ["Bart", "Frank", "Bob"]
myMixedList = ["hello", 345, 34.567]
كما ترون، يمكن أن تحتوي اللائحة على أي نوع من البيانات. يمكنك القيام بالعديد من الأشياء باستخدام اللائحة. على سبيل المثال، عدّ عناصرها:
len(myOtherList)
أو استرجاع عنصر واحد:
myName = myOtherList[0]
myFriendsName = myOtherList[1]
بينما تُعيد الوظيفة len() العدد الإجمالي للعناصر في اللائحة، فإن العنصر الأول في اللائحة يكون دائماً في الموضع 0، لذا في لائحتناmyOtherList، سيكون العنصر "Bob" في الموضع 2. ويمكننا القيام بأمور أخرى كثيرة مع اللوائح، مثل فرز العناصر وإضافة أو حذف عناصر.
من المثير للاهتمام أن السلسلة النصية تشبه إلى حد كبير لائحة الأحرف في لغة بايثون. جرب القيام بما يلي:
myvar = "hello"
len(myvar)
myvar[2]
عادةً ما يمكنك فعله بواسطة السلاسل النصية يمكن فعله باللوائح. في الواقع، كل من القوائم والسلاسل النصية عبارة عن سلاسل.
إلى جانب السلاسل النصية والأعداد الصحيحة والأعداد العشرية واللوائح، هناك أنواع بيانات أساسية أخرى، مثل القواميس dictionaries، ويمكنك حتى إنشاء أنواع البيانات الخاصة بك باستخدام الأصناف classes.
المحاذاة
من أهم استخدامات اللوائح إمكانية "استعراضها" والتعامل مع كل عنصر فيها. على سبيل المثال، انظر إلى هذا:
alldaltons = ["Joe", "William", "Jack", "Averell"]
for dalton in alldaltons:
print(dalton + " Dalton")
استخدمنا الأمر for in للتكرار (مصطلح برمجي) على لائحتنا، ونفذنا إجراءً ما على كل عنصر. لاحظ الصيغة الخاصة: ينتهي الأمر for بـ :، مما يشير إلى أن ما يلي سيكون كتلة من أمر واحد أو أكثر. في المفسر، مباشرةً بعد إدخال سطر الأوامر الذي ينتهي بـ :، سيتغير موجه الأوامر إلى ...، مما يعني أن بايثون يعلم أن هناك المزيد من الأوامر قادمة.
كيف ستعرف لغة بايثون عدد الأسطر التالية التي يجب تنفيذها داخل عملية for in؟ تعتمد بايثون في ذلك على المسافة البادئة. يجب أن تبدأ الأسطر التالية بمسافة فارغة، أو عدة مسافات فارغة، أو علامة جدولة، أو عدة علامات جدولة. وطالما بقيت المسافة البادئة ثابتة، ستُعتبر الأسطر جزءً من كتلة for in. إذا بدأت سطراً بمسافتين والسطر التالي بأربع مسافات، فسيحدث خطأ. عند الانتهاء، اكتب سطراً آخر بدون مسافة بادئة، أو اضغط على مفتاح الإدخال Enter للخروج من كتلة for in.
تُسهم المحاذاة أيضاً في سهولة قراءة البرنامج. فإذا استخدمتَ محاذاة واسعة (كاستخدام علامات الجدولة بدلًا من المسافات) عند كتابة برنامج كبير، فسيكون لديك رؤية واضحة لما يتم تنفيذه داخل كل سطر. وسنرى أن أوامر أخرى تستخدم أيضاً كتلاً برمجية واضحة بطريقة محاذاتها.
يمكن استخدام الأمر for in للعديد من المهام التي يجب تكرارها. على سبيل المثال، يمكن دمجه مع الأمر range():
serie = range(1, 11)
total = 0
print("sum")
for number in serie:
print(number)
total = total + number
print("----")
print(total)
إذا كنت تُشغّل أمثلة التعليمات البرمجية في مُفسّر الأوامر عن طريق النسخ واللصق، فستجد أن كتلة النص السابقة تُظهر خطأً. بدلاً من ذلك، انسخ النص إلى نهاية الكتلة التي تم محاذاتها، أي نهاية السطر total = total + number، ثم الصقه في مُفسّر الأوامر. في مُفسّر الأوامر، اضغط على Enter حتى تختفي علامة النقاط الثلاث ويتم تشغيل التعليمات البرمجية. ثم انسخ السطرين الأخيرين متبوعًا بـ Enter أخرى. ستظهر الإجابة النهائية.
إذا كتبت في المفسر help(range) فسترى:
range(...)
range(stop) -> list of integers
range(start, stop[, step]) -> list of integers
تشير الأقواس المربعة هنا إلى مُعامل اختياري. مع ذلك، من المتوقع أن تكون جميع القيم أعدادًا صحيحة. فيما يلي، سنجبر مُعامل الخطوة على أن يكون عددًا صحيحًا باستخدام int():
number = 1000
for i in range(0, 180 * number, int(0.5 * number)):
print(float(i) / number)
مثال آخر لـ range():
alldaltons = ["Joe", "William", "Jack", "Averell"]
for n in range(4):
print(alldaltons[n], " is Dalton number ", n)
يتميز الأمر range() بخاصية غريبة، وهي أنه يبدأ بـ 0 (إذا لم تحدد رقم البداية)، وأن رقمه الأخير سيكون أقل بواحد من رقم النهاية الذي تحدده. هذا بالطبع، لكي يعمل بشكل جيد مع أوامر بايثون الأخرى. على سبيل المثال:
alldaltons = ["Joe", "William", "Jack", "Averell"]
total = len(alldaltons)
for n in range(total):
print(alldaltons[n])
من الاستخدامات الأخرى المثيرة للاهتمام لكتل الأوامر التي تملك محاذاة واحدة استخدام الأمر if. يُنفذ هذا الأمر كتلة برمجية فقط إذا تحقق شرط معين، على سبيل المثال:
alldaltons = ["Joe", "William", "Jack", "Averell"]
if "Joe" in alldaltons:
print("We found that Dalton!!!")
بالطبع سيتم طباعة الجملة دائماً، ولكن حاول استبدال السطر الثاني بما يلي:
if "Lucky" in alldaltons:
ثم لا يتم طباعة أي شيء. يمكننا أيضاً تحديد عبارة else:
alldaltons = ["Joe", "William", "Jack", "Averell"]
if "Lucky" in alldaltons:
print("We found that Dalton!!!")
else:
print("Such Dalton doesn't exist!")
الوظائف (التوابع)
يوجد عدد قليل جداً من أوامر بايثون القياسية، ونحن نعرف بالفعل العديد منها. ولكن يمكنك إنشاء أوامرك الخاصة. في الواقع، معظم الوحدات الإضافية التي يمكنك إضافتها إلى تثبيت بايثون الخاص بك تفعل ذلك تحديداً، فهي تضيف أوامر يمكنك استخدامها. يُطلق على الأمر المخصص في بايثون اسم وظيفة (أو تابع)، ويتم إنشاؤه على النحو التالي:
def printsqm(myValue):
print(str(myValue) + " square meters")
printsqm(45)
يُعرّف الأمر def() وظيفة جديدة، حيث تُعطيها اسماً، وتُحدد داخل الأقواس الوسائط التي ستستخدمها. الوسائط هي البيانات التي تُمرر إلى الوظيفة. على سبيل المثال، انظر إلى الأمر len() . إذا كتبتَ len() فقط، فسيُخبرك بايثون أنه يحتاج إلى وسيط. وهذا واضح: فأنت تريد معرفة طول شيء ما. إذا كتبتَ len(myList)، فإن myList هو الوسيط الذي تُمرره إلى الوظيفة len(). وتُعرّف الوظيفة len() بطريقةٍ تُمكّنها من معرفة كيفية التعامل مع هذا الوسيط. وقد فعلنا الشيء نفسه مع الوظيفةprintsqm .
يمكن أن يكون اسم myValue أي شيء، وسيُستخدم فقط داخل الوظيفة. إنه مجرد اسم تُطلقه على الوسيط لتتمكن من التعامل معه. بتحديد الوسائط، تُخبر الوظيفة أيضاً بعدد الوسائط المتوقعة. على سبيل المثال، إذا قمت بما يلي:
printsqm(45, 34)
سيحدث خطأ. لقد تمت برمجة وظيفتنا لاستقبال وسيط واحد فقط، ولكنها استقبلت وسيطين، وهما 45 و34. لنجرب مثالاً آخر:
def sum(val1, val2):
total = val1 + val2
return total
myTotal = sum(45, 34)
هنا أنشأنا وظيفة تستقبل وسيطين، وتجمعهما، ثم تُعيد القيمة الناتجة. تُعدّ إعادة القيمة مفيدةً للغاية، إذ يُمكننا استخدامها في عملياتٍ مختلفة، مثل تخزينها في المتحول myTotal.
الوحدات
الآن وقد أصبحت لديك فكرة جيدة عن كيفية عمل لغة بايثون، ستحتاج إلى معرفة شيء آخر: كيفية العمل مع الملفات والوحدات النمطية.
حتى الآن، كنا نكتب تعليمات بايثون سطراً وراء سطر في المفسر. من الواضح أن هذه الطريقة غير مناسبة للبرامج الكبيرة. عادةً ما يُخزَّن كود برامج بايثون في ملفات بامتداد .py، وهي مجرد ملفات نصية عادية، ويمكن استخدام أي محرر نصوص (مثل gedit في لينكس، أو emacs، أو vi، أو حتى المفكرة في ويندوز) لإنشائها وتعديلها.
توجد عدة طرق لتشغيل برنامج بايثون. في نظام ويندوز، ما عليك سوى النقر بزر الفأرة الأيمن على الملف، وفتحه باستخدام بايثون، ثم تشغيله. ولكن يمكنك أيضاً تشغيله من مُفسِّر بايثون نفسه. وللقيام بذلك، يجب أن يعرف المُفسِّر مكان البرنامج. في برنامج فريكاد، أسهل طريقة هي وضع البرنامج في مجلد يعرفه مُفسِّر بايثون الخاص بـ فريكاد افتراضياً، مثل مجلد المستخدم Mod الخاص بـ فريكاد:
def sum(a,b):
return a + b
print("myTest.py succesfully loaded")
احفظ الملف باسم myTest.py في مجلد scripts، واكتب في نافذة المفسر ما يلي:
import myTest
بدون إضافة الامتداد .py. سيؤدي هذا إلى تنفيذ محتويات الملف، سطراً سطراً، كما لو كنا قد كتبناها في المفسر. سيتم إنشاء وظيفة الجمع، وطباعة الرسالة. تُسمى الملفات التي تحتوي على وظائف، مثل ملفنا، وحدات برمجية.
عندما نكتب اسم الوظيفة sum() في المفسر، فإننا ننفذها على النحو التالي:
sum(14, 45)
لكن عندما نستورد import وحدة تحتوي على وظيفة sum() يكون بناء الجملة مختلفاً بعض الشيء:
myTest.sum(14, 45)
أي أن الوحدة تُستورد كـ"حاوية"، وجميع وظائفها موجودة داخل تلك الحاوية. وهذا مفيد جداً، إذ يُتيح لنا استيراد العديد من الوحدات مع الحفاظ على تنظيمها بشكل جيد. باختصار، عندما ترى something.somethingElse، مع وجود نقطة بينهما، فهذا يعني أن somethingElse موجود داخل something.
يمكننا أيضًا استيراد الوظيفة sum الخاصة بنا مباشرة إلى مساحة المفسر الرئيسية:
from myTest import *
sum(12, 54)
تقوم جميع الوحدات تقريباً بذلك: فهي تُعرّف الوظائف وأنواع البيانات الجديدة والأصناف classes التي يمكنك استخدامها في المفسر أو في وحدات بايثون الخاصة بك، لأنه لا يوجد ما يمنعك من استيراد وحدات أخرى داخل وحدتك!
كيف نعرف الوحدات البرمجية المتوفرة لدينا، والوظائف الموجودة بداخلها، وكيفية استخدامها (أي ما هي الوسائط التي تحتاجها)؟ لقد رأينا سابقاً أن بايثون تحتوي على دالة help(). تنفيذ:
help("modules")
سيعطينا هذا قائمة بجميع الوحدات المتاحة. يمكننا استيراد أي منها واستعراض محتواها باستخدام الأمر dir():
import math
dir(math)
سنستعرض جميع الوظائف الموجودة في وحدة math، بالإضافة إلى وظائف أخرى تحمل أسماءً غريبة مثل __doc__ و__file__ و__name__. تحتوي كل وظيفة في وحدة جيدة على __doc__ تشرح كيفية استخدامها. على سبيل المثال، نرى أن هناك وظيفة sin() داخل وحدة الرياضيات. هل تريد معرفة كيفية استخدامها؟
print(math.sin.__doc__)
قد لا يكون الأمر واضحاً، ولكن على جانبي doc يوجد حرفي شرطة سفليان.
وأخيراً، نصيحة أخيرة: عند العمل على كود جديد أو موجود، يُفضّل عدم استخدام امتداد ملف ماكرو فريكاد، .FCMacro، واستخدام الامتداد القياسي .py بدلاً منه. والسبب هو أن بايثون لا يتعرف على امتداد .FCMacro. إذا استخدمتَ .py، يُمكن تحميل الكود بسهولة باستخدام import، كما رأينا سابقاً، وإعادة تحميله أيضاً باستخدام importlib.reload().
import importlib
importlib.reload(myTest)
على أية حال هناك بديل:
exec(open("C:/PathToMyMacro/myMacro.FCMacro").read())
نأمل أن تكون لديك الآن فكرة جيدة عن كيفية عمل لغة بايثون، ويمكنك البدء في استكشاف ما يقدمه برنامج فريكاد. جميع وظائف بايثون في فريكاد منظمة بشكل جيد في وحدات مختلفة. بعضها مُحمّل (مستورد) تلقائياً عند تشغيل فريكاد. جرّبها بنفسك:
dir()