البحث في الموقع
المحتوى عن 'python 101'.
-
تعرّفنا فيما سبق من دروس هذه السلسلة على أساسيات لغة بايثون، من مُتغيّرات وحلقات تكرار إلى الدوال، وقد حان الوقتُ للدخول إلى أساسيات البرمجة كائنية التوجّه Object Oriented Programming وهي ببساطة طريقة أخرى للبرمجة بحيث تكون أجزاء الشّيفرة مجموعة داخل دوال تُسمّى التوابع methods والدوال تكون داخل صنف معيّن Class. عند إنشاء كائن object من هذا الصنف فإنّنا نستطيع أن نُنفّذ عليه مُختلف العمليات الموجودة داخل التوابع والتي بدورها توجد داخل الصنف. هناك تسميّات عربية أخرى لهذا النّوع من البرمجة، لذا لا تقلق إذا صادَفتَ أحد هذه التّسميات في أماكن أخرى، فكلّها تُشير إلى نفس المعنى: برمجة غرضيّة التوجه برمجة شيئية المنحى برمجة كائنيّة المنحى بنية الصنف Class الصنف ببساطة يحتوي على أجزاء مُختلفة من الشيفرة تماما مثل الدالة، الفرق هنا هو أنّ الصنف يحتوي على دوال كذلك، وهذه الدوال تُسمى التّوابع، ويحتوي كذلك على مُتغيّرات وتنقسم هذه الأخيرة إلى نوعين، مُتغيّر الصنف، والمُتغيّر العادي، الفرق بينهما هو أنّك تستطيع الوصول إلى مُتغيّر الصنف في أي مكان داخل الصنف (سواء داخل التوابع أو خارجها). إنشاء صنف لإنشاء صنف في لغة بايثون كلّ ما عليك فعله هو كتابة كلمة class وبعدها اسم الصنف ثمّ إلحاق نقطتين، بعدها اكتب الشيفرة بإزاحة أربع مسافات: >>> class My_class: ... pass أنشأنا أعلاه صنفًا بسيطا باسم My_class وهو لا يفعل أي شيء يُذكر (كلمة pass تُخبر بايثون بالمرور دون تنفيذ أي شيء). إذا كتبت اسم الصنف على مفسّر بايثون فستجد مُخرجا كالتّالي: >>> My_class <class __main__.My_class at 0x7fd0efc41460> لاحظ بأنّ الكلمة الأولى من المُخرج هي class أي أنّنا أصبحنا نمتلك صنفًا جديدًا، ما يتبع at هو المكان في الذاكرة الذي وُضع فيه الصنف ويتغيّر بين الحين والآخر. إنشاء كائن من صنف بعد أن أنشأنا الصنف سنتمكّن الآن من إنشاء كائن من هذا الصنف، والكائن مُجرّد اسم تماما كالمُتغيّر: my_object = My_class() الآن الكائن my_object هو من صنف My_class. تعريف المتغيرات داخل صنف يُمكننا أن نُعرّف مُتغيّرات في الصنف تماما كما نُعرّف المُتغيّرات بشكل عادي. class My_class: my_variable = 'This is my variable' للوصول إلى المُتغيّر ننشئ أولا كائنا من الصنف وبعدها نكتب اسم الكائن ثمّ نقطة ثمّ اسم المُتغيّر: my_object = My_class() print my_object.my_variable المُخرج: This is my variable يُمكن كذلك الحصول على النّتيجة ذاتها في سطر واحد: print My_class().my_variable إنشاء التوابع التوابع هي دوال خاصّة بالصنف، ويُمكننا إنشاء التابع بنفس الطّريقة التي نُنشئ بها الدالة، الإختلاف هنا هو أنّ جميع التوابع يجب أن تُعرّف مع مُعامل باسم self وذلك للإشارة إلى أنّ الدالة/التابع تابع للصنف، لننشئ تابعا داخل صنف الآن. class My_class: my_variable = 'This is my variable' def my_method(self): print 'This is my method' الآن إذا أنشأنا كائنا فإنّنا سنتمكّن من الوصول إلى التابع، وتذكّر بأنّ التابع تلحقه الأقواس: my_object = My_class() my_object.my_method() المُخرج: This is my method يُمكن كذلك الحصول على النّتيجة ذاتها في سطر واحد: My_class().my_method() كما تُلاحظ فقد نُفّذت الشيفرة الموجودة داخل التّابع my_method ويُمكننا كذلك أن نجعل التّابع يقبل المُعاملات، لكن تذكّر الحفاظ على الكلمة self كمُتغيّر أول. class My_class: my_variable = 'This is my variable' def my_method(self, my_parameter): print 'This is my method ; {} is my parameter'.format(my_parameter) يُمكنك استدعاء التّابع كالتّالي: my_object = My_class() my_object.my_method('Parameter1') my_object.my_method('Parameter2') المُخرج: This is my method ; Parameter1 is my parameter This is my method ; Parameter2 is my parameter في البرنامج السّابق، أنشأنا أولا صنفًا باسم My_class وقُمنا بتعريف مُتغيّر، ثمّ بتعريف تابع باسم my_method يقبل مُعاملين self و my_parameter، بالنّسبة لاستدعاء التّابع، فنحتاج فقط إلى تمرير المُعاملات الموجودة بعد المُعامل selfولا نحتاج إلى تعيين قيمة لهذا المُعامل. مُلاحظة: يُمكنك إعادة تسميّة المُعامل الأول كما تشاء، أي أنّ البرنامج التّالي سيعمل دون مشاكل. class My_class: def my_method(this, my_parameter): print '{} is my parameter'.format(my_parameter) ولكن رغم ذلك فالمُتعارف عليه بين مُبرمجي لغة بايثون هو استعمال self، وفي كثير من اللغات الأخرى تُستعمل this عوضا عن self، أما في برامِجك فمن المُفضّل الإبقاء على هذه التّسميّة المُتعارف عنها، وذلك لتكون شيفراته سهلة القراءة. الوصول إلى متغيرات الصنف داخل التوابع تأمّل الصنف التّالي: class Person: lastname = 'Dyouri' job = 'Writer, Developer' def say_hello(self): name = 'Abdelhadi' print 'Hello, My name is {}'.format(name) البرنامج أعلاه بسيط جدا، أولا نعرّف صنف باسم Person وبعدها نقوم بتعيين قيمتين للمُتغيّرين name و lastname، وبعدها عرّفنا تابعا باسم say_hello يطبع جملة Hello, My name is Abdelhadi. كلّ شيء جيد، لكن ماذا لو أردنا أن نصل إلى المُتغيّرات الأخرى الموجودة خارج التّابع، فلا يُمكننا مثلا أن نقوم بالأمر كالتّالي: class Person: lastname = 'Dyouri' job = 'Writer, Developer' def say_hello(self): name = 'Abdelhadi' print 'Hello, My name is {}'.format(name) print lastname print job ستحصل على الخطأ التّالي: global name 'lastname' is not defined لتفادي هذا الخطأ سنستعمل كلمة self قبل المُتغيّر. class Person: lastname = 'Dyouri' job = 'Writer, Developer' def say_hello(self): name = 'Abdelhadi' print 'Hello, My name is {}'.format(name) print 'My Last name is {} '.format(self.lastname) print 'I am a {}'.format(self.job) استدعاء التّابع: me = Person() me.say_hello() المُخرج: Hello, My name is Abdelhadi My Last name is Dyouri I am a Writer, Developer لاحظ بأنّنا قُمنا بالوصول إلى مُتغيّر lastname عن طريق استدعائه بـ self.lastname وكذا الحال مع المُتغيّر job، وهذه الطّريقة مُشابهة لاستخدام كلمة global الفرق هنا أنّ هذه الأخيرة تُمكن من الوصول إلى المُتغيّر في كامل البرنامج، أمّا كلمة self فتُشير إلى المُتغيّر المُعرّف في الصنف الحاليّة فقط. لتفهم أكثر كيفيّة عمل الكلمة self فقط تخيّل بأنّها تحمل نفس اسم الصنف، مثلا: class Person: lastname = 'Dyouri' job = 'Writer, Developer' def say_hello(self): name = 'Abdelhadi' print 'Hello, My name is {}'.format(name) print 'My Last name is {} '.format(Abd.lastname) print 'I am a {}'.format(Abd.job) لاحظ بأنّنا غيّرنا كلمة self إلى اسم الصنف واستمرّ عمل البرنامج دون مشاكل. وبنفس الطّريقة يُمكنك أن تستدعي تابعا داخل تابع آخر في نفس الصنف: class Person: def say_name(self): print 'Abdelhadi' def say_hello(self): print 'Hello My name is:' self.say_name() المُخرج: Hello My name is: Abdelhadi ما حدث هو أنّ التّابع say_hello قام بطباعة جملة :Hello My name is ثمّ قام باستدعاء التّابع say_name الذي قام بدوره بطباعة الاسم Abdelhadi. لماذا تستعمل البرمجة الكائنية، ومتى يجب علي استخدامها قد تُلاحظ بأنّ ما يُمكنك فعله بالبرمجة الكائنيّة يُمكن القيام به بالدوال والمُتغيّرات فقط. هذا صحيح، وهو أمر واضح، البرمجة الكائنيّة تُستعمل أساسا إذا كان البرنامج الذي تبنيه مُعقّدا مع العديد من الوظائف المُتعلّقة ببعضها (كمكتبة برمجيّة)، مثلا لنقل بأنّك تُطوّر برنامجا مسؤولا عن جلب بيانات من موقع مُعيّن، وبعدها التّعديل عليها، ثمّ إخراج مستند PDF يحتوي على هذه البيانات بشكل يُسهّل قراءتها، هنا ستحتاج إلى صنف لجلب البيانات والتّعديل عليها، وصنف أخرى لتحويل البيانات إلى نصّ مقروء واضح ثمّ إلى ملفّ PDF. إذا نشرت برنامجك مع صديقك وأراد أن يعمل على الجزء الثاني لإضافة وظيفة تُمكن المُستخدم من طباعة المُستند فلا يُعقل أن يضطر للمرور على كل ما يتعلّق بجلب البيانات فقط لأنّه يريد أن يضيف خاصيّة لا علاقة لها بجلب البيانات. استعمال البرمجة الكائنيّة في هذا المشروع سيسمح لك بالتّركيز على الجزء الأول، وسيسمح لصديقك بالتّركيز على تطوير الجزء الثاني. خلاصة الأمر هي أنّك لست مضطرا لاستعمال البرمجة الكائنيّة إلا إذا كان برنامجك طويلا يحتوي على وظائف تتعلّق ببعضها البعض (وظائف من نفس الصنف)، ونسبة استخدام الآخرين لشيفرتك عالية. تمارين التمرين 1 أنشئ صنفًا باسمك، وقم بتعريف مُتغيّرين lastname (الاسم العائلي) و age (العمر)، ثم أنشئ كائنا باسم me (أنا) وقم بطباعة اسمك العائلي وعمرك. التمرين 2 أنشئ صنفًا باسم Car (سيارة) وقم بتعريف مُتغيّرات لصفات السّيارة، مثلا brand لاسم الشّركة، release_date لتاريخ الإعلان عن السّيارة. التمرين 3 أضف توابع إلى الصنف Car التي أنشأتها في التّمرين الثّاني، يُمكن أن تكون التوابع عبارة عن عمليّات تقوم بها السّيارة مثلا move للحركة، stop للتوقّف، slow_down لتخفيض السّرعة، وقم بطباعة جمل تفيد بأنّ العمليّة قد نجحت. المفروض أن يتمكّن الآخرون من إنشاء كائنات خاصّة بهم بحيث تُستخدم بهذه الطّريقة: bmw = Car() bmw.move() bmw.slow_down() bmw.stop() خاتمة تعرّفنا في هذا الدّرس على بعض من أهم أساسيات البرمجة الكائنيّة التوجه في لغة بايثون وهذا الموضوع أطول من أن أشرحه في درس واحد لذلك سيكون الدّرس التّالي تكملة لما تعلّمناه في هذا الدّرس حول تعلم بايثون وسيغطي مفاهيم أخرى حول البرمجة كائنية التوجّه.
-
الصفوف Tuple الصّفوف نوع من البيانات التسلسليّة تماما مثل القوائم، لكنّ الصفوف غير قابلة للتغيير، يتألّف صفّ من مجموعة من القيّم نفصل بينها بفاصلة "," ولإنشاء صفّ نقوم بإسناد مجموعة من القيّم إلى متغيّر حيث نفصل بين القيم بفاصلة كما في المثال التّالي: >>> a = (1, 2, 3) >>> a[0] 1 ويُمكن أيضاً إنشاء صفّ بدون أقواس: >>> a = 1, 2, 3 >>> a[0] 1 خاصيّة قياس عدد العناصر len وتشريح الصّف ممكن أيضا، وتُطبّق هذه الخاصيّات كما فعلنا مع القوائم في الدّرس السّابق. >>> len(a) 3 >>> a[1:] 2, 3 وبما أن الأقواس تُستعمل للجمع كذلك، فيجب أن تنشئ صفّا من قيمة واحدة مع فاصلة زائدة. >>> a = (1) >> a 1 >>> b = (1,) >>> b (1,) >>> b[0] 1 ويُمكن جمع صفّين في صفّ واحد بحيث يحتوي الصّفّ الجديد على كلّ من عناصر الصفّ الأول والثّاني، فمثلا في البرنامج التّالي قُمنا بالجمع بين الصّف a و الصف b وأسندنا قيمهما إلى الصف c: >>> a = (1,2,3) >>> a (1,2,3) >>> b = ('Hsoub Academy', 'Abdelhadi') >>> b ('Hsoub Academy', 'Abdelhadi') >>> c = a+b >>> c (1, 2, 3, 'Hsoub Academy', 'Abdelhadi') يُمكن أن تحتوي الصفوف على مُختلف أنواع البيانات كذلك (الأرقام، السّلاسل النّصيّة، القيم المنطقيّة…)، ويُمكن -كما الحال مع القوائم- للعناصر النّصيّة أن تكون بين علامتي تنصيص مزدوجتين. انظر المثال: # هذا مثال على إمكانية إسناد قيم من أنواع مختلفة >>> a = ('Hsoub Academy', 'Python', 3, 10, True) >>> a ('Hsoub Academy', 'Python', 3, 10, True) # يمكنك كذلك إنشاء قائمة تحتوي على سلاسل نصيّة بين علامتي تنصيص مُزدوجتين >>> a = ("Hsoub Academy", "Python", 3, 10, True) >>> a ('Hsoub Academy', 'Python', 3, 10, True) إذا أردت إنشاء صفّ يحتوي على قيمة مُكرّرة عدّة مرّات فيُمكنك إنشاء صف من عنصر واحد ثمّ إجراء عمليّة ضرب بعدد المرّات الذي تريده: >>> ('Academy',) * 5 ('Academy', 'Academy', 'Academy', 'Academy', 'Academy') عند كتابة عدّة قيم والفصل بينها بفاصلة دون إحاطة العناصر بأي علامات تجميع كالأقواس وعلامتي []، فإنّها تكون صفوفا بشكل افتراضي، انظر المثال: >>> print 'Hsoub academy', 5, False, 'Abdelhadi' Hsoub academy 5 False Abdelhadi >>> a, b = 1, 2; >>> print "Value of a and b : ", a,b Value of a and b : 1 2 العمليات على الصفوف تُوفّر لنا بايثون عدّة دوال للتّعامل مع الصّفوف وقد ذكرنا الدّالة len وكيفية استخدامها أعلاه. وقد حان الوقت للحديث عن بعض الدوال الأخرى المُساعدة في التّعامل مع الصّفوف: دالة cmp للمُقارنة بين صفين، إذا كان الصّفان مُتساويان فالنّتيجة تكون 0 أمّا إذا كانا مُختلفين فالنّتيجة تطبع القيمة 1 أو القيمة -1 حسب الاختلاف: >>> a = (1, 2, 3) >>> b = (1, 2, 3) >>> cmp(a, b) 0 >>> a = (1, 2, 3) >>> b = (1, 2) >>> cmp(a, b) 1 >>> a = (1, 2, 3) >>> b = (1, 2) >>> cmp(b, a) -1 دالة max لإرجاع أكبر قيمة في صفّ: >>> a = ('Hsoub Academy', 'Abdelhadi') >>> max(a) 'Hsoub Academy' >>> b = (1, 2, 3) >>> max(b) 3 دالة min لإرجاع أصغر قيمة في صفّ: >>> a = ('Hsoub Academy', 'Abdelhadi') >>> min(a) 'Abdelhadi' >>> b = (1,2, 3) >>> min(b) 1 المجموعات Sets المجموعات عبارة عن جمع غير منظّم لقيّم فريدة، بحيث لا تُكرّر قيمة أكثر من مرّة. يُمكن إنشاء مجموعة فارغة وإضافة العناصر لها بالتّابع add، مع مُلاحظة أنّ التّابع add لا يقبل سوى عنصر واحد في كلّ مرة: >>> x = set() >>> x.add(1) >>> x set([1]) >>> x.add(2) >>> x set([1, 2]) >>> x.add("Hsoub Academy") >>> x set(['Hsoub Academy', 1, 2]) ولإضافة عدّة عناصر مرّة واحدة فعليك الاعتماد على التّابع update مع ملاحظة أنّ العناصر المُضافة يجب أن تكون داخل علامتي []: >>> x = set() >>> x.update([1, 3, 5, "Hsoub Academy"]) >>> x set(['Hsoub Academy', 1, 3, 5]) ولحذف عنصر من مجموعة ما، فيُمكنك الاستعانة بالتّابع remove بحيث تُمرّر العنصر الذي ترغب بحذفه: >>> x = set(['Hsoub Academy', 1, 3, 5]) >>> x.remove("Hsoub Academy") >>> x set([1, 3, 5]) أمّا إذا كنت ترغب بحذف جميع عناصر مجموعة ما، فالتّابع clear سيتكفّل بالأمر: >>> x = set(['Hsoub Academy', 1, 3, 5]) >>> x set(['Hsoub Academy', 1, 3, 5]) >>> x.clear() >>> x set([]) ويُمكنك نسخ مجموعة وإسناد المنسوخ إلى مجموعة أخرى بالتّابع copy، في المثال التّالي قمنا بنسخ المجموعة x وأسندنا المنسوخ إلى المجموعة y : >>> x = set(['Hsoub Academy', 1, 3, 5]) >>> x set(['Hsoub Academy', 1, 3, 5]) >>> y = x.copy() >>> y set(['Hsoub Academy', 1, 3, 5]) ويُمكن إنشاء مجموعة بقيّم مُتعدّدة، لاحظ في المثال التّالي أنّ النّاتج مجموعة تحتوي على عناصر فريدة (حُذِف العنصر 1 لأنّه مُكرّر): >>> x = set([3, 1, 2, 1]) set([1, 2, 3]) وهناك طريقة جديدة لإنشاء المجموعات في بايثون 2.7: >>> x = {3, 1, 2, 1} set([1, 2, 3]) ويُمكن أن تُضيف قيمة إلى مجموعة، وذلك بالدّالة add. >>> x = set([1, 2, 3]) >>> x.add(4) >>> x set([1, 2, 3, 4]) يُمكن الجمع بين مجموعتين بالمُعامل | بحيث تكون المجموعة الجديدة مُحتويّة على كلّ من عناصر المجموعتين، في المثال التّالي ننشئ أولا المجموعة x ثمّ ننشئ المجموعة y وبعد ذلك نقوم بتوحيد المجموعتين ونُسند النّتيجة إلى المجموعة x_y : >>> x = set(['Hsoub Academy', 1, 3, 5]) >>> x set(['Hsoub Academy', 1, 3, 5]) >>> y = set(["Dyouri", "Abdelhadi"]) >>> y set(['Dyouri', 'Abdelhadi']) >>> x_y = x | y >>> x_y set([1, 3, 5, 'Abdelhadi', 'Hsoub Academy', 'Dyouri']) وكما في القوائم، يُمكنك أن تتحقّق من وجود قيمة من عدمه بالعامل in، وهذه العمليّة تكون أسرع في المجموعات من القوائم ولكنك لن تستطيع أن ترى فرقا كبيرا إلّا إذا كان عدد العناصر كبيرًا. >>> x = set([1, 2, 3]) >>> 1 in x True >>> 5 in x False القواميس القواميس تُشبه القوائم، الفرق أنّك تستطيع فهرسة العناصر داخل القواميس بأي نوع من القيم، ففي القوائم يُمكنك الوصول إلى القيم فقط عبر الأعداد الصّحيحة مثل []x أما في القواميس فتستطيع الوصول إلى قيّم عبر المفاتيح كالتّالي: أولا ننشئ قاموسا، بحيث تملك كلّ قيمة مفتاحا معيّنا، كمثال المفتاح x يحمل القيمة 1: >>> a = {'x': 1, 'y': 2, 'z': 3} ويُمكنك الوصول إلى القيّم عبر المفاتيح (عوضا عن الأرقام في كما في القوائم): >>> a['x'] 1 >>> a['z'] 3 يُمكنك كذلك إنشاء قاموس فارغ وإسناد المفاتيح والقيّم بعد ذلك: >>> b = {} >>> b['x'] = 2 >>> b[2] = 'foo' >>> b[(1, 2)] = 3 >>> b {(1, 2): 3, 'x': 2, 2: 'foo'} يُمكن تعديل قيمة مفتاح بالطّريقة التّالية: >>> a = {'x': 1, 'y': 2, 'z': 3} >>> a {'y': 2, 'x': 1, 'z': 3} >>> a['y'] = 'Hsoub Academy' >>> a {'y': 'Hsoub Academy', 'x': 1, 'z': 3} في المثال أعلاه غيّرنا قيمة المفتاح y من القيمة 2 إلى القيمة Hsoub Academy. ويُمكن إضافة مفاتيح وقيم جديدة كذلك: >>> a = {'x': 1, 'y': 2, 'z': 3} >>> a {'y': 2, 'x': 1, 'z': 3} >>> a['w'] = 'Hsoub Academy' >>> a {'y': 2, 'x': 1, 'z': 3, 'w': 'Hsoub Academy'} يُمكنك حذف العناصر باستخدام del كالتّالي: >>> a = {'x': 1, 'y': 2, 'z': 3} >>> del a['x'] >>> a {'y': 2, 'z': 3} ويُمكنك حذف جميع مُكوّنات قاموس بالتّابع clear كالتّالي: >>> a = {'x': 1, 'y': 2, 'z': 3} >>> a {'y': 2, 'x': 1, 'z': 3} >>> a.clear() >>> a {} ويُمكن كذلك حذف القاموس بأكمله: >>> a = {'x': 1, 'y': 2, 'z': 3} >>> a {'y': 2, 'x': 1, 'z': 3} >>> del a >>> a Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined في المثال أعلاه، حاولنا أن نصل إلى القاموس a بعد حذفه لذلك أرجع المُفسّرُ خطأ مفاده بأنّ a غير موجود. الدّالة keys تُرجع جميع المفاتيح الموجودة في قاموس، وبالطّريقة نفسها يُمكن إرجاع جميع قيّم قاموس ما باستعمال values ، أمّا إن أردت إرجاع القيم والمفاتيح الموجودة في قاموس فيُمكنك استعمال items : >>> a.keys() ['x', 'y', 'z'] >>> a.values() [1, 2, 3] >>> a.items() [('x', 1), ('y', 2), ('z', 3)] ويُمكن استعمال حلقة for للتّقدّم في القاموس واستخراج القيّم والمفاتيح: >>> for key in a: ... print key ... x y z >>> for key, value in a.items(): ... print key, value ... x 1 y 2 z 3 يُمكن التحقق من تواجد مفتاح على قاموس باستخدام عامل in أو دالة has_key. >>> 'x' in a True >>> 'p' in a False >>> a.has_key('x') True >>> a.has_key('p') False يُمكن كذلك الاعتماد على كلّ من get و setdefault بحيث الأولى تقوم بعرض قيمة مفتاح إذا كان موجودا وإذا لم يكن موجودا فترجع القيمة الافتراضيّة والتّي توضع كعامل Parameter ثان. انظر المثال لتفهم قصدي: >>> d = {'x': 1, 'y': 2, 'z': 3} >>> d.get('x', 5) 1 لقد أرجع السّطر السّابق القيمة (1) رغم أنّنا حدّدنا قيمة افتراضيّة (5) وذلك لأن المفتاح موجود ويحمل قيمة مُسبقا. >>> d.get('p', 5) 5 في المثال أعلاه، أرجعت الدّالة get القيمة (5) وذلك لأنّ المفتاح p غير موجود أصلاً. و setdefaul تقوم بوضع قيمة افتراضيّة لمفتاح إذا لم يكن موجودا. >>> d.setdefault('x', 0) 1 >>> d {'x': 1, 'y': 2, 'z': 3} >>> d.setdefault('p', 0) 0 >>> d {'y': 2, 'x': 1, 'z': 3, 'p': 0} يُمكن استخدام القواميس لتمثيل السّلاسل النّصيّة عبر المفاتيح، حيث يُستبدَلُ المفتاح بقيمته: >>> 'hello %(name)s' % {'name': 'python'} 'hello python' >>> 'Chapter %(index)d: %(name)s' % {'index': 2, 'name': 'Data Structures'} 'Chapter 2: Data Structures' ملاحظة حول المفاتيح لا يمكن أن تُسند لمفتاح واحد أكثر من قيمة، إذا حاولت أن تُسند قيمتين لأكثر من مفتاح، فإنّ آخر قيمة تكون قيمة المفتاح في النّهاية: >>> a = {'FirstName': 'Abd', 'LastName':'Dyouri', 'Job':'Writer', 'FirstName':'Abdelhadi'} >>> a {'LastName': 'Dyouri', 'Job': 'Writer', 'FirstName': 'Abdelhadi'} >>> a['FirstName'] 'Abdelhadi' يُمكن الجمع بين قاموسين في قاموس واحد بالتّابع update، مع تمرير القاموس الثّاني، في المثال التّالي، أنشأنا قاموسا a ثمّ أنشأنا القاموس b، بعد ذلك حدّثنا القاموس a واضعين فيه مُكونات القاموس b فأصبح في الأخير يحمل جميع مكونات القاموسين : >>> a = {'FirstName': 'Abd', 'LastName':'Dyouri', 'Job':'Writer', 'FirstName':'Abdelhadi'} >>> a {'LastName': 'Dyouri', 'Job': 'Writer', 'FirstName': 'Abdelhadi'} >>> b = {'Website':'Hsoub Academy', 'Language':'Arabic'} >>> b {'Website': 'Hsoub Academy', 'Language': 'Arabic'} >>> a.update(b) >>> a {'Website': 'Hsoub Academy', 'LastName': 'Dyouri', 'Job': 'Writer', 'Language': 'Arabic', 'FirstName': 'Abdelhadi'} تطبيق حول القواميس لننشئ تطبيقا بسيطا لتحويل الأرقام إلى كلمات في لغة بايثون، بحيث يكون لكلّ رقم كلمة تُقابله، افتح ملفّا واحفظه باسم dict.py واكتب فيه الشيفرات التّالية، اقرأ التّعليقات لتفهم الشّيفرة: # -*- coding: utf-8 -*- # طباعة اسم التّطبيق print 'Dictionary Version 1.0.0' # تعريف القاموس وتعيين القيم له dict = { 1:'One', 2:'Two', 3:'Three', 4:'Four', 5:'Five' } # الدّوران حول قيم ومفاتيح القاموس وطباعتها for key in dict: print key , 'in English is :' , dict[key] مُخرجات التطبيق (بعد حفظ الملفّ وتنفيذه) ستكون كالتّالي: Dictionary Version 1.0.0 1 in English is : One 2 in English is : Two 3 in English is : Three 4 in English is : Four 5 in English is : Five يُمكنك أن تعدّل في الشّيفرة كما تشاء، ويُمكنك إضافة المزيد من القيم، الأمر يعود لك. تمارين تمرين 1 اجمع قيم الصّفين التّاليين وضعها في صفّ باسم c: a = ('One','Two','Three') b = ('Hsoub Academy', 'Abdelhadi') تمرين 2 أحذف القيمة HTML من المجموعة x في الشّيفرة التّاليّة: x = set(['Ruby', 'Python', 'HTML', 'Perl']) تمرين 3 قم بتطبيق تعلّماتك لتنشئ برنامجا يعرض كلّ دولة عربية واختصارها، مثلا دولة المغرب اختصارها MA ومصر اختصارها EGY. بحيث تكون نتيجة البرنامج شيئا يبدو كالتّالي: Morocco: MA Egypt: EGY ترجمة -وبتصرف- للكتاب Python Practice Book لصاحبه Anand Chitipothu.
-
بعد أن تعرّفنا في الدّرس السابق على أساسيات البرمجة كائنية التوجّه، سنُكمل في هذا الجزء ما بدأناه وسنتعلّم بعض المبادئ المتقدّمة حول البرمجة كائنيّة التّوجه. تغيير قيمة متغير الصنف في الدّرس السّابق تعلّمنا كيفيّة تعريف مُتغيّر داخل صنف وكيفيّة الوصول إليه، في هذا الجزء من هذا الدّرس سنتعرّف على كيفيّة استخدام هذه المُتغيّرات بشكل أكثر واقعيّة، لنقل مثلا بأنّنا نمتلك صنفًا باسم Car (سيارة)، ونريد أن ننشئ كائنات من هذا الصّنف، بحيثُ يكون لكل كائن قيم مُختلفة لمُتغيّرات الصّنف، انظر ما يلي: class Car: name = None speed = 0 brand = None def specs(self): print '{} speed is {}Km/h and it\'s brand is {}'.format(self.name, self.speed, self.brand) أنشأنا أعلاه صنفا بسيطا باسم Car مع ثلاثة مُتغيّرات name لاسم السّيارة، speed لسرعة السّيارة و brand لاسم العلامة التّجاريّة، كلمة None تُشير إلى أنّ المُتغيّر مُعرّف لكنّه لا يحمل أية قيمة. بعدها عرّفنا تابعا specs (اختصار لـ specifications) لطباعة مواصفات السّيارة. لننشئ كائنات مُتعدّدة من الصّنف الذّي كتبناه للتو. # Toyota Corolla corolla = Car() corolla.name = 'Toyota Corolla' corolla.speed = 200 corolla.brand = 'Toyota' # Ford Focus focus = Car() focus.name = 'Ford Focus' focus.speed = 220 focus.brand = 'Ford' # Honda Civic civic = Car() civic.name = 'Honda Civic' civic.speed = 210 civic.brand = 'Honda' بعد أن أنشأنا الصّنف والكائنات المندرجة تحت هذا الصّنف، وقمنا بتعيين قيم المُتغيّرات التي تُعتبر مواصفات كلّ سيارة، يُمكننا أخيرا طباعة مواصفات كل سيارة (كائن) وذلك باستدعاء التابع specs. corolla.specs() focus.specs() civic.specs() وكما تتوقّع، المُخرج سيكون كالتّالي: Toyota Corolla speed is 200Km/h and it's brand is Toyota Ford Focus speed is 220Km/h and it's brand is Ford Honda Civic speed is 210Km/h and it's brand is Honda إرجاع الصنف داخل تابع يُمكنك أن تقوم بكتابة تابع داخل صنف، بحيث يقوم التابع بتنفيذ شيفرة ما ثمّ إعادة الصّنف نفسه (ما نُشير إليه بالكلمة self) وبهذا ستتمكّن من استدعاء التابع أكثر من مرّة في سطر واحد، تأمل ما يلي: class Car: def start(self): print 'Starting engine…' return self ما فعلناه في الشّيفرة أعلاه ليس بالشيء الكثير، أولا نقوم بتعريف الصّنف ثمّ بعد ذلك نُعرّف التّابع start المسؤول عن تشغيل السّيارة، وبعدها نطبع جملة تُفيد بأنّ مُحرّك السّيارة قيد التّشغيل، بعد تنفيذ الشيفرة سيُرجع التّابع الصّنف نفسه. ما سيُمكّننا من استدعاء التّابع أكثر من مرّة في سطر واحد كما يلي: corolla = Car() corolla.start().start().start() المُخرج سيكون كالتّالي: Starting engine… Starting engine… Starting engine… كما تُلاحظ لقد نُفّذت الشّيفرة الموجودة داخل التّابع start ثلاث مرّات. قد تتساءل عن أهميّة الأمر، وأتّفق معك في أنّ الأمر يُمكن أن لا يكون مُفيدا. لكنّه يكون مُفيدا إذا أردت أن تقوم بتنفيذ تابعين بشكل تسلسلي، لنقل بأنّ لدينا تابعا آخر باسم move ولنفرض بأنّه سيكون مسؤولا عن تحريك السّيارة، سيكون من الأفضل لو استطعنا أن نستدعي تابع الحركة مُباشرة بعد استدعاء تابع التّشغيل. بحيث يبدو الاستعمال كالتّالي: corolla.start().move() يُمكننا أن نقوم بالأمر ببساطة، وفي الحقيقة لن نحتاج إلا لإضافة التابع move لما كتبناه سابقا. class Car: def start(self): print 'Starting engine…' return self def move(self): print 'The car is moving…' بهذه الطّريقة سنتمكن من تنفيذ الشيفرة دون مشاكل: Car().start().move() المُخرج: Starting engine… Starting engine… The car is moving… لكن لاحظ هذه المرّة بأنّنا لم نُرجع كلمة self في التّابع move ما يعني بأنّنا لن نتمكن من القيام باستدعاء التابع أكثر من مرّة: Car().start().move().move() إذا حاولت أن تُنفّذ الأمر السّابق ستحصل على خطأ كالتّالي: AttributeError: 'NoneType' object has no attribute 'move' وهذا راجع لكوننا لم نُرجع الصنف في آخر التّابع move. الوراثة مفهوم الوراثة في البرمجة كائنيّة التوجه لا يختلف كثيرا عن مفهوم الوراثة في العالم الواقعي، الصّنف الابن يرث جميع المتغيرات والتوابع من الصّنف الأب، يُمكن التّفكير في الأمر على أنّه نسخ. أي أنّ الصّنف الابن مُجرّد نُسخة طبق الأصل من الصّنف الأصلي، الفرق هنا هو أنّك تستطيع أن تُضيف المزيد من الخصائص والتوابع للصّنف الابن. وطريقة إنشاء صنف يرث من صنف آخر هي بوضع الصّنف الأب بين قوسين عند إنشاء الصّنف الابن. انظُر المثال التّالي: class Parent: a = 1 b = 2 class Child(Parent): c = 3 في المثال أعلاه، قُمنا بإنشاء صنف باسم Parent مع مُتغيّرين a و b، وبعدها أنشأنا صنفا Child الذي يرث خصائص الصّنف السابق، وبالتّالي فسنتمكّن من الوصول إلى مُتغيّرات الصّنف Parent من خلال الصّنف Child، ما يعني بأنّ الشيفرة التّالية ستعمل دون مشاكل: child = Child() print child.a print child.b print child.c المُخرج: 1 2 3 كما تُلاحظ فإنّنا قد استطعنا الوصول إلى المتغيّرين a و b رغم أنّهما لم يُعرّفا مُباشرة داخل الصّنف Child. يُمكن أن نجعل صنفا يرث توابع من صنف آخر بنفس الطّريقة: class Person: name = 'Person' def say_hello(self): name = self.name print 'Hello my name is {}'.format(name) class Abdelhadi(Person): name = 'Abdelhadi' استدعاء التّابع say_hello من كائن من الصّنف Abdelhadi. me = Abdelhadi() me.say_hello() المُخرج: Hello my name is Abdelhadi في الشيفرة أعلاه، قُمنا أولا بتعريف صنف "شخص" باسم Person ثمّ عرّفنا المُتغيّر name داخل الصّنف، وأعطيناه قيمة افتراضيّة، بعدها عرّفنا التّابع say_hello ليطبع جُملة التّرحيب. متغيرات الصنف المبنية مسبقا توجد مُتغيّرات مبنية مُسبقا في لغة بايثون، وتُسمى هذه المُتغيّرات بمُتغيّرات الصّنف، وما نعنيه بأنّها مبنية مُسبقا هو أنّك لا تحتاج إلى تعريفها، وتمتاز هذه المُتغيّرات بأنّها مُحاطة بتسطيرين سُفليّين Underscores وإليك بعضا من هذه المُتغيّرات: __doc__ سلسلة توثيق الصنف (Documentation string) وهو ما يُكتب مُباشرة بعد تعريف الصنف، ويحتوي في الغالب معلومات حول وظيفة الصّنف. القيمة الافتراضية لهذا المتغير هي None ألق نظرة على الصّنف التالي: class Person: ''' This class does nothing ''' pass لاحظ بأنّ سلسلة التوثيق مُحاطة بثلاث علامات تنصيص إذا أردنا الوصول إلى هذا التوثيق فكلّ ما علينا فعله هو استخدام الصّفة __doc__: print Person.__doc__ المُخرج: This class does nothing __module__ الوحدة التي عُرّفَ فيها الصّنف، وقيمتها الافتراضية هي'__main__'. print Person.__module__ المخرج: __main__ __dict__ هذا المُتغيّر عبارة عن قاموس يحمل ما سبق كقيم بدئية، كما يحمل أسماء المتغيّرات التي تُنشؤها أنت وقيمها وكذلك أسماء التوابع، لاحظ المثال التالي (نفّذه مُباشرة على مُفسّر بايثون لتُلاحظ النّتيجة): >>> class Math: ... x = 1 ... y = 2 ... def x_plus_y(self): ... return self.x + self.y ... >>> Math.__dict__ {'y': 2, 'x': 1, '__module__': '__main__', '__doc__': None, 'x_plus_y': <function x_plus_y at 0x7f186e76a6e0>} كما تُلاحظ مُخرجات القاموس تحتوي على كل من قيم المُتغيرات الخاصّة بالصّنف سواء التي عرّفناها أو المبنية مُسبقا، لاحظ كذلك العنصر الأخير من القاموس: 'x_plus_y': <function x_plus_y at 0x7f186e76a6e0>} هذا العنصر يحمل مفتاحا باسم التابع x_plus_y الذي عرّفناه، وقيمة هذه المفتاح تُشير إلى أنّه دالة. __name__ اسم الصّنف، يُمكنك تطبيقه على أي صنف للحصول على اسمه، انظر المثال التالي: >>> a = Math >>> a.__name__ 'Math' كما تُلاحظ فقد حصلنا على اسم الصنف Math. الوصول إلى الصنف الخاص بكائن ما المُتغيّرات التي ذكرناها سابقا خاصّة بالصّنف فقط ولا يُمكن الوصول إليها من كائن من هذا الصّنف. تأمّل الصّنف التالي: class Person: name = 'Abdelhadi' لننشئ الآن كائنا من هذا الصّنف: me = Person() يُمكننا الآن الوصول إلى قيمة المُتغيّر name كالتالي: >>> me.name 'Abdelhadi' لكننّا لن نستطيع الوصول إلى مُتغيّرات الصّنف من الكائن، بل من الصّنف فقط: person_class = Person person_class.__name__ # الشيفرة صحيحة person_object = Person() person_object.__name__ # الشيفرة خاطئة لأنّنا نحاول الوصول إلى مُتغيّر غير مُعرّف داخل الكائن ستحصل على خطأ من نوع AttributeError عند تنفيذ السّطر الأخير: AttributeError: Person instance has no attribute '__name__' الحل الأمثل هو أن نصل إلى الصّنف انطلاقا من الكائن، وبعدها سنتمكّن من الوصول إلى مُتغيّرات/صفات الصّنف دون مشاكل، وطريقة الوصول إلى صنف كائن هي بإلحاقه بكلمة __class__، انظر المثال التّالي (سنعتمد على الصنف الذي أنشأناه أعلاه): person_object = Person() person_object_class = person_object.__class__ # إسناد صنف الكائن لمتغيّر print person_object_class.__name__ # اسم الصّنف print person_object_class.__dict__ # قاموس يحتوي على بيانات الصّنف بدأنا بإنشاء كائن person_object ثمّ استخدام جُملة __class__ للوصول إلى الصّنف. المُخرج: Person {'__module__': '__main__', 'name': 'Abdelhadi', '__doc__': None} يُمكنك كذلك القيام بالأمر داخل تابع في الصّنف: class Person: def say_hello(self): print 'Hi I am a {}'.format(self.__class__.__name__) person_obj = Person() person_obj.say_hello() لاحظ استخدام self.__class__.__name__ للوصول إلى اسم الصّنف في التّابع say_hello. المُخرج: Hi I am a Person التوابع الخاصة يُمكن استخدام بعض التّوابع الخاصّة لتنفيذ شيفرة عند القيام بإجراء معيّن، وإليك قائمة بأهم هذه التّوابع (لاحظ بأنّها مُحاطة بتسطيرين سُفليّين Underscores). التابع init: تُنفَّذُ الشيفرة التي بداخله عند إنشاء كائن من الصّنف، ويُسمّى أيضا بتابع البناء Contractor . التابع del: تُنفّذ شيفرته عند حذف كائن أو عند استدعاء دالة الخروج exit. التابع repr: تُنفّذ الشيفرة عند استدعاء الكائن، ويُستخدم هذا التابع لإرجاع معلومات حول الكائن في الوضع التّفاعلي (من مُفسّر لغة بايثون مُباشرة) مثال: # استدعاء __init__ person_obj = Person() # استدعاء __repr__ person_obj repr(person_obj) # حذف الكائن واستدعاء __del__ del(person_obj) التابع init هذا مثال بسيط على إنشاء واستدعاء هذا التّابع: class Person: def __init__(self): print 'A new object was created' me = Person() مُخرج البرنامج سيكون جُملة تُفيد بأنّ كائنا قد أنشئ، لاحظ أنّ الجملة A new object was created قد طُبعت رغم عدم استدعاء التّابع init بشكل صريح، ويُمكن الحصول على نفس المُخرج باستدعاء التّابع كالتّالي: me.__init__() حسنا تعلّمنا الآن بأنّنا نستطيع تنفيذ الشيفرة الموجودة بداخل التّابع __init__ بمُجرّد إنشاء كائن من الصّنف، ولكن ماذا عن المُعاملات؟ يُمكن تمرير المُعاملات للتّابع __init__ عند إنشاء صنف كالتّالي: me = Person('Abdelhadi') وفي التّابع سيكون الأمر كالتّالي: def __init__(self, name): name = self.name print 'Hello My name is {}'.format(name) الشيفرة الكاملة: class Person: def __init__(self, name): self.name = name print 'Hello My name is {}'.format(name) me = Person('Abdelhadi') المُخرج: Hello My name is Abdelhadi التابع repr يُستعمل هذا التّابع لإرجاع معلومات قابلة للطّباعة، ويُستخدم كثيرا في الوضع التّفاعلي (مُفسّر بايثون)، ويجب أن تكون القيمة المُرجعَةُ عبارة عن سلسلة نصيّة. وإليك مثالا لكيفيّة استخدامه: class Math: x = 1 y = 2 def __repr__(self): x = self.x y = self.y return 'x: {}, y: {}'.format(x, y) x_y = Math() print x_y المُخرج: x: 1, y: 2 يُمكننا الاستفادة من هذا التّابع للوصول إلى اسم الصنف عند الوراثة: # تعريف الصّنف الرّئيسي class Person: def __repr__(self): return 'Hi I am a {}'.format(self.__class__.__name__) # الوراثة class Writer(Person): pass class Student(Person): pass # إنشاء الكائنات omar = Student() abdelhadi = Writer() # طباعة قيّم التّابع repr print omar print abdelhadi المُخرج: Hi I am a Student Hi I am a Writer لاحظ بأنّ الصّنفين Writer و Student لا يحتويان على أية شيفرة، ومع ذلك فقد نُفّذ التّابع repr واستجاب بطريقة مُختلفة مع كلّ كائن. التابع del تُنَفّذُ الشّيفرة الموجودة بداخل هذا التّابع عند حذف كائن باستعمال الدّالة del وهي دالة تُستعمل لإنجاز ما يُسمى بعمليّة جمع القُمامة Garbage Collecting والهدف الرئيسي من هذه العمليّة هو تحرير الذاكرة، ولحذف كائن يكفي أن تقوم باستدعاء الدّالة del مع تمرير الكائن كمُعامل: class Math: x = 1 y = 2 numbers = Math() numbers.x # ==> 1 numbers.y # ==> 2 # حذف الكائن del(numbers) # خطأ numbers.x # ==> NameError: name 'numbers' is not defined بعد أن حذفنا الكائن numbers لم يعد بإمكاننا الوصول إلى قيمة المُتغيّر x، وأسفر الأمر عن خطأ من نوع NameError. يُستدعى التابع del مُباشرة بعد حذف الكائن، ما يعني بأنّنا نستطيع أن نطبع جملة تُفيد بأنّ الكائن قد حُذف: class Math: x = 1 y = 2 def __del__(self): print 'Object deleted!' numbers = Math() numbers.x # ==> 1 del(numbers) المُخرج: Object deleted! تُنفَّذ شيفرة __del__ كذلك عند استدعاء الدالة exit للخروج من البرنامج: class Math: x = 1 y = 2 def exit_program(self): exit() def __del__(self): print 'Object deleted!' numbers = Math() numbers.exit_program() مُخرَج البرنامج أعلاه سيكون نفس الشيء رغم عدم حذف الكائن. والسبب راجع لاستخدام الدّالة exit داخل التّابع exit_program. تمارين تمرين 1 عد إلى الدّروس السّابقة وحاول تحويل برنامج تسجيل الدّخول إلى برنامج سهل القراءة والاستخدام باستعمال البرمجة كائنية التوجه، فمثلا يُمكن أن يستعمل من قبل مُبرمجين آخرين بالطّريقة التّالية: user = User() user.signup('username', 'password', 'password_confirmation') user.login('username', 'password') user.say_hello() user.logout() تمرين 2 أنشئ برنامجا يطبع جميع التوابع والمُتغيّرات الموجودة داخل الصّنف الذي أنشأته كحل للتّمرين الأول.
- 4 تعليقات
-
- 3
-
- البرمجة كائنية التوجه
- بايثون
- (و 5 أكثر)
-
بايثون (Python) لغة برمجة تتميّز بسهولة تعلّمها، وتُعدّ مثالا جيّداً لبدء تعلّم البرمجة بالنّسبة للمبتدئين. وستجد في هذه السّلسلة من الدّروس (الذي يُمثّل هذا المقال الجزء الأوّل منها) ما تحتاج إليه لتعلّم أساسيّات هذه اللّغة. ما هي بايثون؟ لغة برمجة ابتكرها “جايدو ڤان روسم”، وقد خرجت أول نسخة من بايثون في عام 1991. لغة بايثون لغة برمجة تفسيريّة. إذا سبق وأن اطّلعت على البرمجة ولو قليلا فستعرف أنّ لهذه اللغة بنية جميلة. فالمبرمجون دائما ما يبحثون عن أفضل الطّرق لكتابة الأسطر البرمجيّة. ما الغرض من لغة بايثون؟ تتميّز لغة بايثون بالقوّة والبساطة، فتُخوّل لك كتابة برمجيّات بسيطة جدّا، كما تمتلك مكتبات مُتعدّدة تسمح لك بالعمل على مشاريع أكثر تعقيداً. الويب: في أيامنا هذه تعتبر بايثون مع إطار العمل Django من أفضل الأدوات لتطوير مشاريع ضخمة على الويب تتمثّل أساسا في مواقع الأنترنت. الأنظمة: تعتبر بايثون كذلك من أحسن اللغات التي يستعملها مدراء الأنظمة لإنشاء برمجيّات للمُساعدة في إنجاز مهام مُتكرّرة وكذلك لصيّانة النظام، وإذا كنت ترغب في كتابة تطبيقات Java باستعمال بايثون فيُمكنك ذلك بفضل مشروع Jython. لماذا بايثون؟ تعدّ بايثون لغة سهلة الفهم وشيفرتها سهلة القراءة كذلك، وبالتّالي فهي أفضل خيّار للمُبتدئين الذين يريدون تعلّم البرمجة. وهي موجزة جدّا وشيفرتها قصيرة، ما يُساهم في زيادة إنتاجيّة المُبرمج ويُقلّل من نسبة الأخطاء في البرنامج كما يُساعد على إصلاح الأخطاء بسهولة وسرعة. ويمكنك التعرف عليها بتعمق أكبر من خلال الانضمام إلى تُستعمل بايثون كذلك في الميادين العلميّة، مثل ميدان المعلوماتيّة-الحيويّة. وهناك مكتبات متوفّرة لمثل هذه الأغراض كمكتبة biopython. كما هناك مكتبات خاصّة لإنشاء ألعاب 2D (وكذلك 3D)، ومكتبة PyGame مثال على ذلك. من يستعمل بايثون؟ شركة جوجل (وقد كان مؤسّس بايثون يعمل لصالح الشّركة منذ 2005 إلى 2012)،كما أنّ ياهوو، مايكروسوفت وناسا كلّها مؤسّسات تعتمد على بايثون وهذه الشركات على سبيل المثال فقط لا الحصر. الفرق بين إصداري بايثون 2 وبايثون 3 كان هناك العديد من التّغييرات عند خروج الإصدار الثّالث من بايثون، وكان أكبر تغيير يتمثّل في تغيير جملة الطباعة print من: print "مرحبا" إلى: print ("مرحبا") هذا التّغيير سيسبب مشاكل كثيرة عند مُحاولة تنفيذ ملفّات بايثون 2 على بايثون 3، وخاصّة مع كثرة استعمال هذه الجملة في التّطبيقات. لكن لا تقلق فبعد تعلّمك لأساسيّات اللغة لن تجد مشاكل كبيرة مع الإصداراين، وسنعتمد في هذه الدّروس على بايثون 2. تنصيب بايثون تنصيب بايثون على نظام Linux أو MacOS إذا كان لينكس أو ماك أو إس هو نظامك تشغيلك، فهذا أمر جيّد لأنّ بايثون مُثبّتة مُسبقا على هاذين النّظامين. تنصيب بايثون على نظام Windows يُمكنك تحميل بايثون من الموقع الرّسمي. أي نسخة أختار؟ حاول اختيّار النّسخة الأكثر حداثة واستقرارا، وسنعمل بنسخة Python 2.7 لأنّها النّسخة الأكثر استخداما. ملاحظة: يوجد بعض المشاكل المتعلّقة بالتّوافق بين النّسختين 2 و 3 وقد سبق وأن سردنا جانبا من الاختلافات بينهما أعلاه. ويُنصح بالاعتماد على النسخة الثّانية أولّا ثمّ التّعرّف على الفروقات بين النّسختين، وبهذا ستكون قادراً على فهم المشاكل التي قد تحدث عند التبديل بينهما وسيسهل عليك حلّها. مفسر بايثون لاستعمال بايثون على Ubuntu مثلا، شغّل الطرفيّة Terminal: ثمّ نفّذ الأمر python: أمّا على نظام ويندوز فيمكنك الوصول إلى المُفسّر من قائمة "ابدأ". يُمكن ملاحظة الرّمز "<<<" الذي يعني بأنّ مُفسّر لغة بايثون جاهز لاستقبال الإرشادات والأوامر. وبشكل عام في دروس بايثون يعني الرّمز السّابق إذا كان ملحقا بأيّ شيفرات، بأنّك يجب أن تُنفذ الشّيفرات على الطّرفيّة. ويُمكن القيّام بذلك عبر كتابته ثمّ الضغط على زر Enter. يُمكننا الآن أن نجرّب كتابة شيفرة بسيطة عبارة عن عمليّة حسابيّة "3+1": بهذا نكون قد فهمنا أساس مُفسّر بايثون وماهيّته. في بعض المُحرّرات (مثل المحرّر Wing IDE) يكون المُفسّر الخاصّ ببايثون مُضمّناً في البرنامج، وسنتحدّث عن الأمر في القسم التّالي من الدّرس. المحرر محرر Wing IDE يعد مُحرّر Wing IDE في نُسخته المجانيّة من أفضل المُحرّرات للمبتدئين لكتابة شيفرات بايثون خاصّة وأنّه يأتي مع مُفسّر بايثون. وهو محرّر مصمّم من مطوّري بايثون لمُطوّري بايثون، ويُعدّ من أفضل المُحرّرات لمن يرغب في تعلّم اللغة، النّسخة المجانيّة منه توفّر خيّارات أقلّ لمستخدميه مقارنة بالنّسخة المدفوعة (وتُباع بحوالي 45$). يُمكنك تحميل النّسخة المجانيّة منه عبر هذا الرّابط. إذا كنت تعمل على نظام Ubuntu فحمّل الملفّ بامتداد deb.، اضغط مرّتين على الملف ثم اضغط على "تنصيب". إذا واجهتك أي مُشكلة فحاول تنفيذ الأمر التّالي من الطّرفيّة: sudo apt-get install -f هذه بعض اللقطات من البرنامج: محرر Sublime Text الآن لننتقل إلى هذا المُحرّر الرّائع الذي يجمع بين الخفّة والقوّة. يمتلك Sublime Text العديد من الإضافات التّي ستعجب بها من النّظرة الأولى والتّي ستجعل عملك سهلا وأسرع. النّسخة الأساسيّة من المحرّر مجانيّة، يُمكن أن تستقبل بعض الرّسائل التّي تطلب منك شراء البرنامج لدعم المشروع، لكنّ ذلك لا يعدّ إجباريّاً. من المُفضل أن تُثبّت أداة packagecontrol، التّي تُمكّنك من تنصيب الإضافات المُتطلّبة لمشروعك. وإليك بعضا من اختصارات المحرّر الأكثر استخداما: Ctrl + X حذف سطر Ctrl + P تصفّح الملفّ Ctrl + R تحريك المؤشّر إلى الدّالة في الملفّ Ctrl + L تظليل السّطر الحالي Ctrl + D تظليل الكلمة الحاليّة Ctrl + Shift + D مُضاعفة السّطر الحالي Ctrl + M تحريك المؤشّر إلى نهاية الدّالة Ctrl + G تحريك المؤشّر إلى السّطر رقم X في الملف Ctrl + Shift + T إعادة فتح آخر ملف أُغلِق مؤخّراً CTRL + SHIFT + F البحث عن ملفّ في مجلّد ما CTRL + ALT + P التبديل بين المشاريع محرر VIM يعتبر محرّر VIM من أخفّ وأقوى المُحرّرات، ويعمل من الطّرفيّة مباشرة ما يتيح لك إمكانيّة التّعديل على الملفّات وتشغيلها بسرعة، كما يتميّز بعدم استهلاكه لموارد الجهاز. ويُمكنك معرفة المزيد عن هذا المُحرّر بالاطّلاع على سلسلة VIM التّي قُمت بكتابتها منذ مُدّة. تنفيذ سكريبتات بايثون بعد أن تعرّفنا على الأساسيّات، حان الوقت لبدأ التعلم، افتح ملفّا جديدا بمحرّر من اختيّارك واكتب السّطر التّالي: print "hello, world!" واحفظ الملف باسم hello.py، لا يهم اسم الملف هنا المهمّ امتداده (py.) الذي يخبر نظام التّشغيل بأنّ الملف مكتوب بلغة بايثون. يُمكنك الآن تنفيذ (أو تشغيل) الملفّ الذي قمت بإنشائه بكتابة السّطر التّالي في الطّرفيّة ثمّ الضّغط على مفتاح ENTER، فقط تأكد من أنّ الطّرفيّة والملفّ يشيران إلى نفس المجلّد: python hello.py سترجع الطّرفيّة قيمة كالتالي: hello, world! النّص الذي يكون مبدوءا برمز # لا يُنفّذ ويسمّى تعليقا (سنتطرّق للأمر لاحقاً): # هذا برنامج بايثون يقوم بطباعة جملة مرحبا بالعالم # شغّل هذا البرنامج بالأمر التّالي: # python hello.py print "hello, world!" والآن حان دورك. لكي تتعلّم البرمجة بشكل جيّد فيجب عليك أن تتمرّن باستمرار. مسألة 1: أنشئ ملفّ بايثون يقوم بطباعة hello, world أربع مرّات. مسألة2: أنشئ ملف بايثون يحتوي على السّطر التّالي: 1 + 2 قم بتنفيذه. ما هي النّتيجة التي حصلت عليها؟ إذا لم يقم البرنامج بطباعة أي شيء، فما التّغييرات التّي يجب عليك القيّام بها لطباعة النتيجة المُتوقّعة؟ كيف أحترف بايثون لتعلم لغة بايثون واحترافها، يُنصح بالانضمام إلى دورة تطوير تطبيقات باستخدام لغة بايثون التي تقدمها أكاديمية حسوب، والتي تمكّنك من تعلّم التطوير بلغة بايثون للتطبيقات ولمواقع الويب بالاعتماد على النظريات السليمة والتطبيق العملي والدعم المباشر، وذلك بالانطلاق من الصفر حتى الاحتراف فيها. ستتعلم من خلال الدورة كيفية بناء تطبيقات فعلية بالاعتماد على لغة بايثون Python نفسها، كما ستتعلم كيفية بناء التطبيقات بالاعتماد على إطار العمل جانغو Django، إضافةً إلى تطبيقٍ عملي لإنشاء واجهة برمجية API باستخدام إطار العمل فلاسك Flask، إلى جانب الحصول على المتابعة اللازمة من المدربين لمرافقتك خلال رحلة تعلمك والإجابة على كافة استفساراتك. كما يمكنك الاستعانة بتوثيق بايثون من موسوعة حسوب لإثراء معارفك بها، ولا تنسى مطالعة سلسلة paython 101. ترجمة -وبتصرف- للدرس Apprendre le langage de programmation Python لصاحبه Olivier ENGEL. اقرأ أيضا: النسخة العربية الكاملة من كتاب البرمجة بلغة بايثون 1.0.0 توثيق لغة بايثون في موسوعة حسوب تعرف على أبرز مميزات لغة بايثون
-
الوحدات Modules الوحدة مجموعة من شيفرات بايثون (دوال، أصناف…) يُمكن إعادة استخدامها من طرف المبرمج بسهولة، و يُمكن كذلك أن تسمى بالمكتبة. يُمكن استيراد وحدة في برنامجك باستخدام كلمة import مع إلحاق اسم الوحدة. في المثال التالي نستورد وحدة time المُساعدة في التعامل مع الوقت في لغة بايثون، إذ توفّر دوالًا جاهزة تُمكننا من إجراء عدّة عمليات، كالحصول على الوقت الحالي، وكذلك التاريخ وغير ذلك. import time بعد أن قمنا باستيراد وحدة الوقت، يُمكننا الآن الوصول إلى العديد من الدوال والمتغيرات المتواجدة بهذه الوحدة. يُمكننا مثلا الحصول على تاريخ اليوم والوقت باستدعاء الدالة asctime كالتالي: >>> import time >>> time.asctime() 'Fri Apr 8 19:47:35 2016' يُمكننا كذلك الوصول إلى العديد من الدوال الأخرى المتعلّقة بالوقت، وهذه قائمة ببعض هذه الدوال: time: الحصول على عدد الثواني التي مرّت منذ يوم 1 يناير 1970، الذي يُسمى توقيت يونكس أو Unix Time. >>> time.time() 1460139948.733128 sleep: الانتظار لعدد من الثواني قبل تنفيذ أمر معيّن. الأمر التالي سيوقف مُفسّر لغة بايثون عن العمل لخمس ثوان قبل استكمال العمل: >>> time.sleep(5) البرنامج التالي سيقوم بالانتظار لمدة ثانية واحدة قبل طباعة كلمة !Hello: >>> time.sleep(1); print 'Hello!' يُمكننا كذلك استيراد دالة واحدة أو مجموعة من الدوال فقط دون كامل الوحدة، وذلك باستخدام الجملة from import. مثلا يُمكننا استيراد الدالة asctime بمُفردها بالسّطر التالي: from time import asctime لاستدعاء أكثر من دالة، افصل بينها بفواصل. from time import asctime, sleep لاستعمال هذه الدوال المُستوردة يكفي استدعاؤها باسمها دون البادئة time. >>> from time import asctime, sleep >>> sleep(1) >>> asctime() 'Fri Apr 8 19:49:25 2016' الحصول على مساعدة حول الوحدة أو حول دالة من وحدة ما يُمكنك استعمال سطر الأوامر للحصول على التوثيق الخاص بالوحدة الذي يشرح كل دالة على حدة بتنفيذ الأمر التالي من برنامج الطّرفيّة Terminal: pydoc time غيّر time باسم الوحدة التي ترغب بالحصول على توثيق لها. يُمكن كذلك استخدام الدالة help على بايثون مع تمرير اسم الوحدة أو الدالة التي ترغب في معرفة المزيد عنها: help('time') # توثيق الوحدة time الكامل help('time.sleep') # التوثيق الخاص بالدالة sleep مُخرج السّطر الثاني: Help on built-in function sleep in time: time.sleep = sleep(...) sleep(seconds) Delay execution for a given number of seconds. The argument may be a floating point number for subsecond precision. إنشاء وحدة خاصة بك أشرنا من قبل بأنّ الوحدة مُجرّد دوال ومتغيّرات، ما يعني بأنّك تستطيع تحويل أي ملف مكتوب بلغة بايثون إلى وحدة ما دام به دوال وأصناف. سننشئ في هذا المثال وحدة لحساب مربّع عدد ومكعّبه، أي أنّ الوحدة ستحتوي على دالتين square لحساب مُربّع العدد، و cube لحساب مُكعّبه، أنشئ ملفا باسم num.py وضع به ما يلي: mill = 1000000 def square(x): return x * x def cube(x): return x * x * x لقد أنشأت الآن وحدة يُمكن أن يستعملها غيرك من المُبرمجين. افتح مُفسّر بايثون واستورد الوحدة num وبعدها جرّب استعمال الدالتين على عدد معيّن: >>> import num >>> num.square(3) 9 >>> num.cube(3) 27 >>> num.mill 1000000 لاحظ بأنّنا استطعنا الوصول إلى قيمة المُتغيّر mill كذلك. يُمكن كذلك استدعاء دالة واحدة فقط: >>> from num import cube >>> cube(3) 27 توثيق الوحدة يُمكنك توثيق الوحدة ليسهل على المبرمجين فهم الدوال ووظائفها، وذلك باستعمال سلسلة التوثيق Docstring تكون داخل ثلاث علامات تنصيص كالتّالي: """The num module provides utilties to work on numbers. """ mill = 1000000 def square(x): """Computes square of a number.""" return x * x def cube(x): """Computes cube of a number.""" return x * x إذا نفّذت الأمر pydoc على الوحدة، فستجد أن التوثيق قد أضيف تلقائيا. Help on module num: NAME num - The num module provides utilties to work on numbers. FILE /home/dyouri/num.py FUNCTIONS cube(x) Computes cube of a number. square(x) Computes square of a number. DATA mill = 1000000 الوحدة OS تُمكّن الوحدة os من إجراء عمليات نظام التّشغيل مثل إنشاء المجلّدات وعرض قائمة بالملفات المتواجدة بمجلّد معيّن، أو حتى حذف مُجلّد أو ملف بلغة بايثون. عرض مسار مجلد العمل الحالي يُمكنك أن تحصل على مسار المجلّد الحالي بالدّالة getcwd وهي اختصار لـ get current working direcrtory أي (احصل على مُجلّد العمل الحالي)، ويُمكن تنفيذ الدّالة كالتّالي: >>> import os >>> os.getcwd() '/home/dyouri' إذا كنت تستعمل مُفسّر بايثون في Windows، فالمُخرج سيكون مشابها لما يلي: 'C:\Python27' إنشاء مجلد جديد يُمكنك إنشاء مُجلّد بالدالة mkdir مع تمرير اسم المُجلّد كمُعامل: >>> import os >>> os.mkdir('New Folder') بعد تنفيذ الأمر ستجد بأنّ المجلّد قد أضيف إلى قائمة المُجلّدات. عرض مكونات مجلد معين يُمكنك كذلك عرض مُكونات مُجلّد بالدّالة listdir وسيكون المخرج عبارة عن قائمة بأسماء الملفات والمجلّدات الموجودة في المسار المُمرّر للدالة. في هذه الحالة سنُمرّر مسار المُجلّد الحالي. dir = os.getcwd() os.listdir(dir) يُمكنك عرض كل عنصر في سطر بحلقة for. dir = os.getcwd() list = os.listdir(dir) for item in list: print item إعادة تسمية ملف أو مجلد يُمكنك إعادة تسمية ملفّ أو مُجلّد بالدّالة rename كما يلي: os.rename('Old', 'New') حيث Old هو الاسم القديم، وNew هو الاسم الجديد. حذف ملف لحذف ملف يكفي استخدام الدالة remove، مع تمرير مسار الملف. os.remove('file.txt') حذف مجلد فارغ يُمكن حذف مُجلّد فارغ بالدّالة rmdir مع تمرير مسار المجلّد المرغوب حذفه. os.rmdir('New Folder') إذا أردت أن تحذف مجلّدا يحتوي على ملفات فيمكن استخدام وحدة Shutil. (انظر القسم التالي). تنفيذ أوامر النظام أوامر النّظام هي الأوامر التي تستطيع تنفيذها من الطّرفيّة Terminal أو من برنامج Cmd على Windows. يُمكنك تنفيذ أوامر النّظام عبر الدالة system وذلك بتمرير الأمر كمُعامل. os.system('ls') الوحدة Shutil تُمكّن الوحدة Shutil من إجراء عمليات على الملفات والمجلّدات، مثل نسخ ملف من مسار إلى مسار آخر أو نقله، أو حذف مُجلّد كامل. حذف مجلد كما أشرنا سابقا، تستطيع استخدام os.rmdir لحذف مُجلّد فارغ، لكن ماذا لو أردت حذف به ملفات؟ يُمكنك استخدام الدّالة rmtree من وحدة shutil للقيام بذلك. import shutil shutil.rmtree('Folder') نسخ ملف يُمكنك استخدام الدّالة copy لنسخ ملف من مسار إلى مسار آخر، الدالة تقبل مُعاملين، المُعامل الأول يُمثّل مسار الملف المراد نسخه، والمُعامل الثاني يُمثّل مسار الملفّ المراد النّسخ إليه. shutil.copy('file.txt', 'Folder/file.txt') نقل ملف لنقل ملفّ يُمكن استخدام الدّالة move عوضا عن الدالة copy الخاصّة بالنّسخ. shutil.move('file.txt', 'Folder/file.txt') تمرير معاملات إلى ملف بايثون من الطرفية بالوحدة Sys تُمكّننا الوحدة sys من تمرير مُعاملات عند تشغيل ملف مكتوب بلغة بايثون، فمثلا يُمكنك أن تكتب برنامجا للطّباعة دون الحاجة إلى الدّخول إلى مُفسّر بايثون. سيكون اسم الملف مثلا print.py وسنمكن من تمرير مُعامل له عند تشغيله كالتالي: python print.py 'Hello World!' يُمكن الحصول على المُعاملات الممرّرة على شكل قائمة، وهي مخزّنة في المُتغيّر argv من الوحدة sys. أنشئ ملفا باسم print.py وضع به ما يلي: import sys print sys.argv إذا قُمت بتشغيل الملفّ مع تمرير معامل أو أكثر فستُطبع قائمة تحتوي على جميع هذه المُعاملات. جرّب تنفيذ الملف مع تمرير كلمة hello كمُعامل. python print.py hello ستجد بأنّ المُخرج سيكون عبارة عن قائمة بعنصرين: ['print.py', 'hello'] العنصر الأول هو اسم الملفّ، والعنصر الثاني هو ما قُمنا بتمريره. يُمكنك بالطّبع الوصول إلى عنصر محدّد فقط بتحديد رقمه من القائمة: import sys print sys.argv[1] في الشيفرة أعلاه، قمنا بطباعة العنصر الثاني. إذا كرّرت أمر التّشغيل السّابق ستُلاحظ بأنّ المُخرج هو كلمة hello فقط. لتمرير جملة، يكفي إحاطتها بعلامتي التّنصيص. python print.py 'Hello World!' الحزم Packages الحزمة أو الرّزمة عبارة عن مُجلّد يحتوي على وحدة أو أكثر. عوضا عن ملفّ num.py يُمكن أن نقوم بوضع الملفات داخل مُجلّد الحزمة. لإنشاء حزمة عليك إنشاء مُجلّد باسم الحزمة، التي سنُسميها num_package وداخل هذا المجلّد سنضع ملفيّن square .py و cube.py. كذلك يجب أن يحتوي المُجلّد على ملف باسم init__.py__ وذلك لإخبار بايثون بأنّ هذا المُجلّد عبارة عن حزمة. لإنشاء المُجلّد والملفّات اللازمة، يُمكنك تنفيذ البرنامج التّالي: import os os.mkdir('num_package') open('num_package/__init__.py', 'w').close() open('num_package/square.py', 'w').close() open('num_package/cube.py', 'w').close() سنضع في ملفّ square.py الدالة الأولى: def square(x): return x * x وفي ملف cube.py الدالة الثانية: def cube(x): return x * x * x وسنترك الملفّ init__.py__ فارغا. استيراد الحزمة يُمكنك استيراد الحزمة كاملة كالتّالي: import num_package أو يُمكنك استيراد كل وحدة على حدة. import num_package.square import num_package.cube بعد الاستيراد، يُمكن الوصول إلى الدوال كالتالي: >>> num_package.square.square(3) 9 >>> num_package.cube.cube(3) 27 يُمكن كذلك وضع إختصار للوحدة وذلك لاختصار الوصول إلى الدوال، فقط ألحق سطر الاستيراد بكلمة as وبعدها أعطها اسما مُختصرا. import num_package.square as sqr ستستطيع الآن الوصول إلى الدالة بكتابة شيفرة أقل: sqr.square(3) يُمكن كذلك استخدام جملة from .. import. from num_package.square import square as sqr sqr(3) تمارين التمرين 1 استعمل وحدة time لإنشاء ساعة بسيطة تطبع الوقت الحالي كل ثانية. التمرين 2 أنشئ المُجلدات التّالية (10 مُجلّدات) باستخدام لغة بايثون: Folder1 Folder2 Folder3 . . Folder10 ملاحظة: استخدام حلقة تكرار لإنجاز الأمر. التمرين 3 أعد تسمية المُجلّدات التي أنشأتها في التّمرين 2 بإضافة العدد واحد لنهاية كل مُجلّد، أي أنّ المُجلّد Folder1 يتغيّر اسمه إلى Folder2 وهكذا إلى أن تصل إلى المُجلّد العاشر Folder11. التمرين 4 استعمل وحدة Sys لإنشاء آلة حاسبة بسيطة، يُمكن استخدامها كالتّالي: python calc.py 3 + 4 => 7 python calc.py 10 - 4 => 6 ما التالي؟ وصلنا أخيرا إلى نهاية هذه السّلسلة التي تشرح أساسيات اللغة، فهنيئا لك على صبرك وهنيئا لك على إضافة لغة بايثون كمهارة أخرى إلى قائمة مهاراتك، ستتمكّن الآن من برمجة برامج ذات وظائف مُتعدّدة ومُعقّدة، وتستطيع قراءة وفهم بعض الشيفرات المُتواجدة على موقع Github. إنّ ما يجعل بايثون لغة شهيرة هي مكتباتها التي تتعدّى الآلاف في شتى المجالات، لذا فالحديث عن لغة بايثون لا يمكن أن ينتهي هنا. يُمكنك اختيار مكتبة أو إطار عمل لتعلّم تطوير الويب (Flask, Bottle, Django)، تطبيقات سطح المكتب (Python Qt, Python Gtk, TkInter, Kivy)، أو حتى مُعالجة الصّور بمكتبة OpenCV، وغيرها الكثير. إذا كنت مُهتما بتطوير تطبيقات الويب فيُمكنك إلقاء نظرة على درس إنشاء موقع بسيط بإطار العمل Bottle. المصادر المعتمدة التوثيق الرّسمي للغة بايثون، فصل الوحدات كتاب Python Practice Book لكاتبه Anand Chitipothu
-
إلى الآن، تعرفنا في هذه السلسلة من الدروس على أساسيات التعامل مع أنواع البيانات، المُتغيرات، الجمل الشرطية، وحلقات التكرار for و while. وقد أصبح لديك الآن المعلومات الكافية لبرمجة برامج مُتوسطة قد تحتوي على مئات الأسطر البرمجية، وقد حان الوقت لتتعرف على الدوال لكي تجعل مُهمة إعادة استخدام أجزاء من شيفرتك أكثر سهولة ومرونة، كما ستتعرف على بعض من الدوال المُعرفة مُسبقا في لغة بايثون. للتذكير: جميع الشّيفرات التّي تبدأ بعلامة <<< يجب أن تنفّذ على مفسر بايثون. الدوال الدّالة في البرمجة كاسم المتغيّر يُمكنك استدعاؤها عند الحاجة لكنّ المتغير لا يحمل سوى قيمة واحدة، أمّا الدّالة فتحمل شيفرة مستقلة وقد تكون هذه الشيفرة جملة شرطية أو جملة طباعة أو حلقة تكراريّة أو كل ما سبق. وتُستعمل الدوال أساسا لتجنب تكرار شيفرة عدة مرات، فمثلا لنقل بأنّك كتبت شيفرة للجمع بين عددين ثم بعد ذلك أردت أن تجمع عددين آخرين وهكذا، إذا حاولت تكرار الشيفرة سيكون الأمر مُتعبا جدا خاصة إذا كانت الشيفرة التي تكررها طويلة جدا، لذلك فلغات البرمجة توفر الدوال. لنعتبر بأنّ طباعة جملة "Hello" هي الشيفرة التّي تحملها الدّالة، انظر المثال التّالي: >>> def say_hello(): ... print "Hello" ... >>> say_hello() Hello أولا قمنا بإنشاء الدّالة say_hello في السّطر: def say_hello(): النّقاط الثّلاثة التّي تظهر بعد ذلك السّطر تعني بأن مُفسر بايثون ينتظر مدخلات أخرى، لذلك ندخل شيفرة الطّباعة (تذكر بأن هذه هي الشيفرة الأساسيّة) بعد مساحة بيضاء (أربع مسافات). بعد إنشاء الدّالة سيرجع المفسّر إلى حالته الطّبيعية، بدون أي مُخرجات، وذلك لأنّنا يجب أن نستدعي الدّالة لكي تُنفّذَ الشّيفرة التّي بداخلها، والاستدعاء يكون بكتابة اسم الدّالة مع قوسين: >>> say_hello() ما رأيناه قبل قليل هو كيفية تعريف دالة، كيفية وضع شيفرة داخلها ثم كيفية استدعائها لتنفذ الشيفرة. يُمكن أن نجعل الدالة تُعيد قيمة دون تنفيذ أي شيفرة (رغم أنّها تُنفذ شيفرة الإرجاع)، انظر المثال التالي: >>> def x(): ... return 4 ... >>> x() 4 ما فعلناه هو أنّنا قُمنا بجعل الدالة قيمة عوضا عن أن تُنفذ شيفرة ما، أي أنّنا استخدمنا الدالة x كمُتغير عادي يحمل قيمة مُحدّدة. قد تسأل نفسك، ما فائدة الأمر؟. الأمر مُفيد جدا إذا كان برنامجك كبيرا، بحيث يُمكنك استعمال الدوال كقيمة مُخرجة بعد عدة عمليات. مثلا، إذا كان لديك برنامج يطلب من المُستخدم مُدخلا (كاسمه أو كلمة مروره) وتُريد التحقق من مُدخله وإجراء عمليات عليه، فاستعمال المُتغيرات هنا ليست فكرة جيدة وذلك لأنّ الشيفرة ستكون صعبة التعديل. عوضا عن ذلك يُمكنك أن تقوم بالعمليات على المدخل داخل دالة ثم بعد ذلك تجعل الدالة تحمل القيمة التي ترغب بها في النهاية. دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن ملاحظة حول تسمية الدوال رغم أنك تستطيع تسمية الدوال بأحرف صغيرة وكبيرة معا، من المُفضل تسمية الدالة بأحرف صغيرة والفصل بين كل كلمة والأخرى بمحرف "_". المعاملات Parameters من مُميزات الدوال أنّك تستطيع أن تُعطيها مُعاملات عند تعريفها، وأن تُعطي القيم لهذه المُعاملات إما عند تعريف الدالة (المعاملات الافتراضية) أو لاحقا. لتفهم أكثر، انظر المثال التالي: >>> def say_hello(name): ... print 'Hello', name ... >>> say_hello('Abdelhadi') Hello Abdelhadi >>> say_hello('Hsoub Academy') Hello Hsoub Academy كما ترى لقد قُمنا بتعريف الدالة say_hello مع مُعامل name ووضعنا داخلها جملة طباعة لتطبع Hello متبوعا بقيمة العامل name بعدها قُمنا باستدعاء الدالة وأسندنا للعامل name قيمتين مُختلفتين، وقد كانت النتائج مُختلفة، يُمكنك أن تستدعي نفس الدالة مع معاملات مُختلفة لعدد غير محدود من المرات. يُمكنك كذلك أن تقوم بتعريف دالة مع أكثر من معامل، إليك مثالا على دالة لإعادة مجموع عددين : >>> def add_numbers(n1, n2): ... return n1 + n2 ... >>> add_numbers(3,4) 7 إذا قُمنا بتعريف دالة مع معامل فلا بد أن نقوم بتعيين قيمة العامل عند الاستدعاء وإلا فسيرجع مُفسر Python خطأ كالتّالي: >>> say_hello() TypeError: say_hello() takes exactly 1 argument (0 given) الأمر نفسه يحدث إذا عينت عددا أكثر من العوامل المُفترض، مثلا أن تعطي للدالة say_hello مُعاملين أو أكثر. يُمكنك أن تقوم بوضع قيمة افتراضية لمُعامل في سطر تعريف الدالة: >>> def num(n1, n2 = 10): ... return n1 + n2 ... >>> num(3) 13 يُمكن أن تستعمل هذه الطريقة لعرض خطأ للمُستخدم إذا نسي إدخال المُعاملات. >>> def say_hello(name = '| Error! Check the line that calls the function'): ... print 'Hello', name ... >>> say_hello() Hello | Error! Check the line that calls the function يُمكنك كذلك أن تقوم بعدة عمليات مع الدوال، وإليك قائمة ببعض هذه العمليات: تعريف دالة داخل دالة أخرى بما أن الدوال عبارة عن أجزاء من الشيفرة فتستطيع أن تقوم بإنشاء دالة أخرى أو عدد من الدوال داخل الدالة الواحدة، انظر المثال التالي: >>> def say_hello(name): ... def hello(): ... return 'Hello ' ... print hello() + name ... >>> say_hello('Abdelhadi') Hello Abdelhadi كما ترى أعلاه القيمة Hello ما هي إلا القيمة التي أرجعتها الدالة hello المعرفة بداخل الدالة say_hello. استدعاء دالة داخل دالة أخرى هذا الأمر بسيط، فقط استدع الدالة داخل دالة أخرى وستعمل كلتا الدالتان عند استدعاء الدالة الأم: >>> def say_hello(name): ... print 'Hello', name ... >>> def print_hello(): ... say_hello('Abdelhadi') ... >>> print_hello() Hello Abdelhadi في المثال أعلاه قُمنا باستدعاء الدالة say_hello من داخل الدالة print_hello. إسناد دالة لمتغير تستطيع أن تُنشئ دالة وتقوم بإسنادها لمُتغير بالطّريقة التالية: >>> def say_hello(name): ... print 'Hello', name ... >>> s = say_hello >>>> s('Abdelhadi') Hello Abdelhadi إسناد دالة كمعامل لدالة أخرى قلنا مُسبقا بأنّه يمكن للدالة أن تتصرف كمتغير وذلك عندما نجعلها ترجع قيمة بالجملة return. وهذا يعني بأنّنا نستطيع أن نسند للدالة دالة أخرى. >>> def say_hello(name): ... print 'Hello', name ... >>> def get_name(): ... return 'Abdelhadi' ... >>> say_hello(get_name()) Hello Abdelhadi إرجاع دالة داخل دالة أخرى يُمكنك أيضا أن تستعمل الجملة return لإرجاع دالة داخل دالة أخرى عوضا عن إرجاع قيمة ما، انظر المثال: >>> def get_hello(): ... return 'Hello Abdelhadi' ... >>> def say_hello(): ... return get_hello() ... >>> print say_hello() Hello Abdelhadi ستلاحظ بأنّ الدالة say_hello تحمل قيمة الدالة get_hello، وذلك لأنّنا أرجعنا هذه الأخيرة داخل الدالة say_hello. إسناد عدد لا نهائي من المعاملات لدالة ما لنقل بأنّك تريد أن تقوم بإنشاء دالة تطبع جميع المُحتويات (المُعاملات) التي تُدخلها دون الحاجة إلى تحديد كل معامل على حدة. يُمكنك أن تقوم بالأمر بما يُسمى مُعامل طول المُتغير أو Variable-length argument وذلك كالتالي: >>> def print_arguments(*args): ... print args ... >>> print_arguments(2, 4, 8, 'Abdelhadi', 'Hsoub Academy') (2, 4, 8, 'Abdelhadi', 'Hsoub Academy') المُتغير args عبارة عن صف (Tuple) من القيم، وبالتالي فإنك تستطيع أن تتعامل معه بحلقة For. يُمكن أن تستخدم أي اسم نريده لهذا المعامل، وعموما يعتبر الاسم args* تقليدا بين مُبرمجي بايثون. لاحظ أن الاختلاف بين المعامل العادي والمعامل في المثال أعلاه هو النجمة في البداية. تستطيع أن تجعل المُعاملات قاموسا عوضا عن صف بحيث تُرجع الدالة القاموس الذي يحتوي على اسم المعامل وقيمته، وذلك كالآتي: >>> def print_keyword_args(**kwargs): ... print kwargs ... >>> print_keyword_args(name = 'Abdelhadi', website = 'Hsoub Academy', n = 3) {'website': 'Hsoub Academy', 'name': 'Abdelhadi', 'n': 3} لاحظ بأنّ اسم المُعامل يبدأ بنجمتين هذه المرة، وهذا النوع من المُعاملات يسمى مُعاملات الكلمة المفتاحية Keyword Arguments لأنها ترجع قاموسا مفاتيحه هي أسماء المعاملات التي تختارها أنت وقيم المفاتيح هي قيم المعاملات. المتغيرات المحلية والمتغيرات العامة Local variables and Global variables المتغيرات المحلية هي المتغيرات التي نقوم بإنشائها داخل دالة، أما المتغيرات العامة فهي التي ننشئها خارج الدالة. يُمكنك أن تصل إلى المتغيرات العامة في أي مكان من برنامجك، على خلاف المُتغيرات المحلية التي ستتمكن من الوصول إليها فقط داخل الدالة، انظر المثال التالي: >>> def say_hello(): ... name = 'Abdelhadi' ... print 'Hello', name ... >>> say_hello() Hello Abdelhadi >>> print name Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'name' is not defined قُمنا بتعريف المُتغير name داخل الدالة say_hello وبعدها حاولنا الوصول إليه خارج الدالة، ما أدى إلى خطأ مفاده بأن مُفسر بايثون لم يتعرف على المُتغير. يُمكن أن نجعل المتغير name عامًا بإضافة الكلمة global قبله (عليك أن تقوم بهذا قبل إسناد قيمة للمُتغير)، انظر المثال التالي: >>> def say_hello(): ... global name ... name = 'Abdelhadi' ... >>> say_hello() >>> print name Abdelhadi نُلاحظ بأنّنا استطعنا الوصول إلى المُتغيّر name خارج الدالة التي عُرّفَ بها. تطبيق سنضرب مثالا بالبرنامج الذي أنشأناه في درس التعابير الشرطية والإزاحات. print 'Hello User, this is a basic sign up/login Program' username = raw_input('Enter your username please: ') password = raw_input('Enter the your password please: ') password_verification = raw_input('Verify password: ') if password == password_verification: print 'You have Successfully Signed up! \n' username_sign_in = raw_input('Enter your username please: ') password_sign_in = raw_input('Enter your password please: ') if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' else: print 'The password and the password verification do not match! Please try again' سنركز على شيفرة التحقق من المُستخدم وكلمة المرور: if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' إذا أردنا أن نستخدمها لأكثر من مرة في برنامجنا فعلينا أن نضعها داخل دالة. def user_logged_in?(username_sign_in, username, password_sign_in, password): if username_sign_in == username and password_sign_in == password: return True else: return False يُمكنك استخدام الدالة في أي مكان من الشيفرة: def is_user_logged_in(username_sign_in, username, password_sign_in, password): if username_sign_in == username and password_sign_in == password: return True else: return False new_password = raw_input('Enter new username: ') new_username = raw_input('Enter new password: ') print 'Ok!' password = raw_input('Hello again, Enter your username: ') username = raw_input('Enter username\'s password: ') print is_user_logged_in(username, new_username, password, new_password) الدالة is_user_logged_in تقوم بمُقارنة كلمتي المرور واسمي المُستخدم فإن كانا متطابقين فستصبح قيمة الدالة True أما إن لم تتوافق القيم فإنّ الدالة تحمل القيمة False ويُمكنك الآن استخدام الدالة مع الجمل الشرطية في أي مكان من برنامجك دون الاضطرار لإعادة كتابة شيفرة التحقق كل مرة. كما أنّ التعديل على الشيفرة بسيط جدا، فالتّعديل من مكان واحد (الدالة) يكفي يطبّق على جميع الأماكن الأخرى (أمكنة استدعاء الدالة). الدوال المعرفة مسبقا تُوفر بايثون دوالا مُعرفة مُسبقا، وقد تعاملنا مع كثير منها في الدروس السابقة، وإليك بعض الدوال المُفيدة التي توجد مُسبقا بلغة بايثون. print: دالة الطّباعة التي استخدمناها أكثر من مرة لطباعة القيم في سابق الدروس. Int: دالة تحويل القيم إلى عدد صحيح، مثال: >>> int(5.5) 5 str: دالة تحويل القيم إلى سلسلة نصيّة String: >>> str(True) 'True' وتُستعمل كثيرا لجمع سلسلة نصية بقيمة من نوع آخر بالعامل + (إذا لم تستخدم هذه الدالة فسيعرض لك مُفسر بايثون خطأ يُفيد بأنّك لا تستطيع جمع قيمتين من نوعين مُختلفين): >>> print 'ABC' + str(122) + str(False) ABC122False abs: دالة للحصول على القيمة المُطلقة Absolute Value لعدد ما (إذا كان موجبا فهو العدد نفسه، وإذا كان سالبا فمُقابله): >>> abs(3) 3 >>> abs(-3) 3 len: دالة لقياس عدد عناصر قائمة أو عدد أحرف سلسلة نصية. >>> a = ['Abdelhadi', 'Dyouri', 'Academy', 'Hsoub'] >>> b = 'Hello' >>> len(a) 4 >>> len(b) 5 min: دالة لتحديد أقل قيمة بين قيمتين أو أكثر. >>> min(4, 5, 7, 88, 3, 2) 2 max: دالة لتحديد أقل قيمة بين قيمتين أو أكثر. >>> max(4, 5, 7, 88, 3, 2) 88 range: لتوليد قائمة بأعداد بين قيمة المعامل الأول وقيمة المُعامل الثاني: >>> range(0, 11) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> range(0, 11, 3) [0, 3, 6, 9] raw_input: دالة للحصول على مُدخل نصي من المُستخدم، يُمكنك أن تسند هذا المُدخل إلى مُتغير. >>> def say_hello(name): ... print 'Hello', name ... >>> say_hello(raw_input()) Abdelhadi Hello Abdelhadi كما قُلنا سابقا، فإنك تستطيع أن تقوم بإسناد دالة كمعامل لدالة أخرى، وهذا ما فعلناه في المثال أعلاه، إذ مررنا الدالة raw_input ليكون معاملا للدالة say_hello. تمارين تمرين 1 اكتب برنامجا للحصول على قيمة من المُستخدم وتحويلها إلى قيمة عددية. تمرين 2 اكتب دالة لطباعة جملة لعدد من المرات، واترك للمُستخدم حرية اختيار عدد مرات التكرار (مُساعدة: استعمل الدالة raw_input للحصول على قيمة من المُستخدم) تمرين 3 اكتب دالة للجمع بين عددين يُدخلهما المُستخدم. تمرين 4 بَرمِجْ آلة حاسبة بسيطة تقوم بالجمع، الطّرح، الضرب والقسمة. إليك طريقة العمل: احصل على قيمة العدد الأول من المُستخدم. احصل على قيمة العدد الثاني. حول القيمتين النصيتين إلى قيمتين عدديتين. احصل على العامل الرياضي (*، /، - أو +) من المُستخدم. استخدم الجمل الشرطية لإجراء العملية المُناسبة (إذا كان المُدخل + فقم بالجمع). ترجمة -وبتصرف- من الكتاب Python Practice Book لكاتبه Anand Chitipothu.
-
بعد أن تعرّفنا في الدّرس السّابق على طريقة تنصيب بايثون وكيفيّة العمل معها، سنكمل في هذا الدّرس مشوار تعلّم هذه اللغة بتعلّم كيفيّة التّعامل مع البيانات مثل المُتغيّرات وأنواعها كالأرقام وإسناد القيم. ولكن قبل ذلك عليك أن تتعرّف على طريقة دعم اللغة العربيّة، ويجب عليك أن تفهم بعض المُصطلحات المتداولة في مجال البرمجة (والتّي اعتَمدتُ عليها في هذا الدّرس). تذكير: نقوم بتنفيذ الأسطر البرمجيّة مُباشرة من مُفسّر بايثون، لمزيد من المعلومات عن المُفسّر راجع الدّرس السّابق. وللتوسع في لغة بايثون وتعلمها أكاديميًا، ننصحك بالانضمام إلى دورة تطوير تطبيقات باستخدام لغة بايثون التي تقدمها أكاديمية حسوب. دعم اللغة العربية في بايثون قد تواجه خطأ إذا حاولت تنفيذ أمر طباعة جملة "مرحبا بالعالم" مُستخدما حروفا عربية، لذلك يجب عليك أن تكتب السّطر التّالي، قبل كتابة أي أمر يحتوي على كلمات عربية: # -*- coding: utf-8 -*- المصطلحات مخرج Output: تعني الجواب أو النّتيجة الذي يُقدّمها مُفسّر بايثون، فمثلا إذا طلبت من مُفسّر بايثون طباعة كلمة Hello، فستستخدم السّطر التّالي: >>> print "Hello" Hello هنا نُسمّي Hello المُخرج الذي يُرجعه البرنامج (أي نتيجة الأمر). مُتغيّر: وهو الاسم الذي نُطلقه على حرف أو “كلمة” تحمل قيمة مُعيّنة، مثلا: >>> name = "abdelhadi" هنا قُمنا بإنشاء مُتغيّر name وأسندنا له القيمة abdelhadi. وإذا أردنا إظهار القيمة abdelhadi فيكفي أن نكتب اسم المُتغيّر في مُفسّر بايثون: >>> print name كما يُمكن أن نضيف تحّية على الشّكل التّالي: >>> print "Hello " + name تُفسّر الشيفرة أعلاه وتكون مُخرجاتها: Hello Abdelhadi يُمكن أن يحمل المُتغيّر عدّة أنواع من القيم، كالأرقام والنّصوص والأحرف… تعيين القيم يُعتبر تعيين قيمة لاسم معيّن من أهمّ أساسيّات البرمجة، وهذا الاسم معروف في البرمجة بالمُتغيّر، وإليك مثالا على ذلك: >>> x = 4 >>> x * x 16 قمنا في المثال أعلاه بوضع القيمة 4 للمتغيّر x، بعبارة أخرى المُتغيّر x يحمل القيمة 4. بحيث يُمكننا استعمال x عوضا عن 4 في باقي الأسطر في برنامجنا. وبعدها قمنا بالعمليّة الحسابيّة x * x أي 4 * 4 وحصلنا على 16 كنتيجة. إذا حاولت أن تستخدم مُتغيّرًا لم يُعرّف من قبل في برنامجك، فستحصل على خطأ كالتّالي: >>> foo Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: name 'foo' is not defined >>> foo = 4 >>> foo 4 حاولنا أعلاه أن نقوم باستخدام المُتغيّر foo الذي لم نعرّفه أساساً، فحصلنا على رسالة من مُفسّر بايثون مفادها بأنّ المُتغيّر foo ليس موجودا. وبعد تعريفه وتعيين القيمة "4" له أصبح بإمكاننا استدعاؤه بدون أي مشكلة. إذا وضعت قيمة مُغايرة لمتغيّر يحمل مُسبقاً قيمة ما، فالقيمة القديمة تُستَبدَل بالقيمة الجديدة، بحيث يحمل المتغيّر القيمة الجديدة. >>> x = 4 >>> x 4 >>> x = 'hello' >>> x 'hello' في المثال أعلاه، قمنا بتحديد القيمة "4" للمتغيّر x ثمّ بعد ذلك قمنا بتحديد "hello" لنفس المُتغيّر فأصبح x يحمل القيمة hello في نهاية المطاف. ويُمكنك تعيين أكثر من قيمة لأكثر من مُتغيّر في آن واحد. >>> a, b = 1, 2 >>> a 1 >>> b 2 >>> a + b 3 ومُبادلة قيمتي مُتغيّرين (بحيث يحمل المُتغيّر قيمة الآخر) سهل جدّا في لغة بايثون: >>> a, b = 1, 2 >>> a, b = b, a >>> a 2 >>> b 1 عند تعيينِ قيمة في بايثون، تكون الأهميّة للجانب الأيمن قبل الأيسر، بحيث يقوم بايثون بالتّعرّف على القيّم في الجانب الأيمن ثمّ يقوم بتعيينها للمتغيّرات في الجانب الأيسر لعلامة = . إذ ما يقع على يسار علامة = هو المُتغير وما يقع على يمينها هو القيمة. التعليقات تُستعمل التّعليقات في البرمجة لشرح وظيفة سطر معين أو لإعطاء فكرة عن برنامجك لمن يقرأ شيفرته، وتكون التّعليقات مسبوقة بعلامة # إما في سطر مستقل أو في نفس سطر الشّيفرة، وتتميّز بأنّها لا تؤثّر على عمل البرنامج إذ يتجاهلها المُفسّر ولا تُنفّذ، وهي عموما اختيارية، لذا فأنت لست مُجبرا على كتابتها، وإليك مثالاً على التّعليقات: >>> # السّطر التّالي عبارة عن تعيين قيمة لمتغيّر >>> x = 'hello' # هذا السّطر عبارة عن تعيين قيمة لمتغيّر الأرقام لقد تعرّفنا من قبل حول كيفيّة التّعامل مع الأرقام بشكل بسيط. >>> 42 42 >>> 4 + 2 6 تدعم بايثون الأعداد العشريّة كذلك. >>> 4.2 4.2 >>> 4.2 + 2.3 6.5 وتدعم العمليّات المُختلفة مثل الإضافة والفرق وغيرهما من العمليّات الحسابيّة: + إضافة - الفرق * الضّرب / القسمة ** الأس (القوة) % باقي القسمة لنجرّب هذه العمليّات على الأعداد الصّحيحة: # عمليّة إضافة >>> 7 + 2 9 # عمليّة فرق >>> 7 - 2 5 # عمليّة ضرب >>> 7 * 2 14 # عمليّة قسمة >>> 7 / 2 3 # الأس >>> 7 ** 2 49 # باقي القسمة >>> 7 % 2 1 إذا تمعّنت في النّظر ستجد أنّ ناتج قسمة 7 على 2 يُساوي 3 وليس 3.5 وهذا لأنّ الرّمز / يُرجع الأرقام الصحيحة فقط عندما يعمل معها، لننظر مالذي سيحدث إذا جرّبنا نفس الأمر لكن بأعداد عشريّة هذه المرّة: >>> 7.0 / 2.0 3.5 >>> 7.0 / 2 3.5 >>> 7 / 2.0 3.5 يُمكن القيّام بالعمليّات الحسابيّة بالاعتماد على أكثر من عامل: >>> 7 + 2 + 5 - 3 11 >>> 2 * 3 + 4 10 هذا مهمّ جدّا وذلك لفهم كيفيّة تعامل لغة بايثون مع العمليّات الحسابيّة، حيث هناك أولويّات للعمليّات وذلك كالقائمة التّالية، من الأقل أولويّة إلى الأه: + - * / % ** ولفهم ذلك أكثر، إليك هذا المثال: عند تنفيذ العمليّة 2 + 3 * 4 في بايثون فالعمليّة الأولى التّي تُنفّذ هي 3 * 4 ، لأن العامل * أكثر أولويّة من عامل +، وبعد ذلك تضاف القيمة إلى 2. >>> 2 + 3 * 4 14 يُمكننا أن نعتمد على الأقواس () لتحديد أولويّات العمليّات، انظر المثال التّالي: >>> (2 + 3) * 4 20 في المثال أعلاه، قمنا بوضع العمليّة 2+3 بين قوسين لإخبار مُفسّر بايثون بأنّ لهذه العملية الأولويّة ويجب حسابها أوّلا، فإن لم نقم بوضع القوسين لقام المُفسّر بحساب العمليّة 4*3 ثم إضافة العدد 2. جميع العمليّات باستثناء ** يبدأ تطبيقها من اليسار ثمّ اليمين. 1 + 2 + 3 * 4 + 5 ↓ 3 + 3 * 4 + 5 ↓ 3 + 12 + 5 ↓ 15 + 5 ↓ 20 تمارين تمرين 1 ما هي مُخرجات (القيّم التّي سيطبعها) البرنامج التّالي: x = 4 y = x + 1 x = 2 print x, y تمرين 2 ما هي مُخرجات (نتيجة) البرنامج التّالي: x, y = 2, 6 x, y = y, x + 2 print x, y تمرين 3 ما هي مُخرجات البرنامج التّالي: a, b = 2, 3 c, b = a, c + 1 print a, b, c ترجمة -وبتصرف- للكتاب Python Practice Book لصاحبه Anand Chitipothu.
-
بعد أن تعرّفنا في الدّرس السّابق على طريقة التّعامل مع البيانات مثل المُتغيّرات وأنواعها كالأرقام وإسناد القيم، سنكمل في هذا الدّرس الثّالث مشوار تعلّم هذه اللغة بتعلّم كيفيّة التّعامل مع كل من القوائم والسّلاسل النّصيّة. تذكير: الشيفرات التّي تكون مسبوقة بعلامة "<<<" يجب أن تُنفّذ على مُفسّر بايثون. القوائم تعتبر القوائم طريقة رائعة للتّعامل مع البيانات في لغة بايثون، وتتعلّق القائمة بمتغيّر معيّن بحيث يحمل أكثر من قيمة، ويمكن الوصول إلى هذه القيم باستعمال رقم كل قيمة. لتفهم أكثر، اعتبر أنّ لك 5 أبناء، بحيث تكون قائمة الأبناء: 0، عمر 1، خالد 2، حسن 3، زيد 4، يوسف في بايثون، ننشئ القائمة بالطّريقة التاليّة: >>> children = ['Omar','Khaled','Hassan','Zaid','Youssef'] لنسمّي القائمة أعلاه باسم children، وتحتوي على خمس عناصر، ولكل عنصر رقم خاص به، بحيث يبدأ العدّ من الصّفر، فمثلا إذا أردنا مناداة الابن "عمر" فسيتوجّب علينا مناداته برقمه (أي الرقم 0)، وطريقة مناداة باقي الأبناء تكون بالشّكل التّالي: >>> print 'Come here ' + children[0] Come here Omar >>> print 'Come here ' + children[1] Come here Khaled >>> print 'Come here ' + children[2] Come here Hassan >>> print 'Come here ' + children[3] Come here Zaid >>> print 'Come here ' + children[4] Come here Youssef الآن، لننتقل إلى تطبيق مبادئ القوائم على بايثون، يُمكننا إسناد قائمة إلى متغيّر كالتّالي: >>> x = [1, 2, 3] ويُمكنك إنشاء قائمة سلاسل نصيّة عوضا عن الأرقام: >>> x = ["hello", "world"] يُمكن أن تجمع بين أنواع القيّم المُختلفة، هذا المثال يجمع بين الأرقام والسّلاسل النّصيّة: >>> x = [1, 2, "hello, "world"] ويُمكن أن تحتوي القائمة على قائمة أخرى: >>> x = [1, 2, "hello, "world", ["another", "list"]] أو بالطّريقة التّاليّة: >>> a = [1, 2] >>> b = [1.5, 2, a] >>> b [1.5, 2, [1, 2]] يُمكن أن نستخدم الدّالة len المعرّفة مُسبقا لنقيس طول قائمة ما (عدد مكونات القائمة): >>> x = [1, 2, 3] >>> len(x) 3 نصل إلى عناصر قائمة ما بكتابة اسم المُتغيّر الذي يحمل القائمة، ثمّ رقم العنصر بين رمزي []: >>> x = [1, 2, 3] >>> x[1] 2 >>> x[1] = 4 >>> x[1] 4 مع ملاحظة أنّ التّرقيم يبدأ بالصّفر، بحيث يكون العنصر الأوّل من القائمة يحمل الرّقم 0 والعنصر الثّاني يحمل رقم 1 وهكذا دواليك. يُمكن إنشاء قائمة تحتوي على أعداد صحيحة من مجال معيّن بالدّالة Range، في المثال التّالي قُمنا بإنشاء قائمة تحتوي على أربعة عناصر من 0 إلى 3، ثمّ قائمة تحتوي على ثلاثة عناصر بين العددين 3 و 6، ثمّ في السّطر الأخير قُمنا بإنشاء قائمة مُتكوّنة من 3 عناصر بين العددين 2 و 10 مع زيادة بقيمة 3 : >>> range(4) [0, 1, 2, 3] >>> range(3, 6) [3, 4, 5] >>> range(2, 10, 3) [2, 5, 8] يُمكن كذلك استخدام الدّالة len لحساب عدد عناصر قائمة ما: >>> a = [1, 2, 3, 4] >>> len(a) 4 كما يُمكنك التّعامل مع القوائم بالرموز الرّياضيّة * و + لتكرار أو الجمع بين عناصر قائمة ما: >>> a = [1, 2, 3] >>> b = [4, 5] >>> a + b [1, 2, 3, 4, 5] >>> b * 3 [4, 5, 4, 5, 4, 5] للوصول إلى عناصر قائمة مُعيّنة نستعين برقم العنصر، مع ملاحظة بأنّ التّرقيم يبدأ من الصّفر إلى ( عدد العناصر-1 ). >>> x = [1, 2] >>> x[0] 1 >>> x[1] 2 إذا استخدمت فهرسا (ترقيما) خاطئا، فسيُرجِع مفسّر بايثون خطأ: >>> x = [1, 2, 3, 4] >>> x[6] Traceback (most recent call last): File "<stdin>", line 1, in ? IndexError: list index out of range يُمكنك كذلك استخدام التّرقيم السّلبي للوصول إلى عناصر القائمة من الآخر إلى الأول ( آخر عنصر يحمل القيمة -1 والعنصر الأول يحمل الرقم السّلبي لعدد العناصر): >>> x = [1, 2, 3, 4] >>> x[-1] 4 >>> x[-2] 3 >>> x[-4] 1 يُمكننا تشريح قائمة (تقسيمها إلى أجزاء)، بالطّريقة التّاليّة: >>> x = [1, 2, 3, 4] >>> x[0:2] [1, 2] >>> x[1:4] [2, 3, 4] ويمكن استخدام الأرقام السلبيّة في التّقسيم كذلك: >>> x[0:-1] [1, 2, 3] إذا تركت مكان الرقم الأول فارغا، فالقيمة الافتراضيّة هي الصّفر، و القيمة الافتراضيّة للشّطر الثاني تكون عدد عناصر القائمة: >>> x = [1, 2, 3, 4] >>> a[:2] [1, 2] >>> a[2:] [3, 4] >>> a[:] [1, 2, 3, 4] يُمكن استخدام رقم ثالث لتحديد الخطوة (يعني المقدار الذي نضيفه في العنصر الحالي مقارنة بالعنصر السّابق)، والذي يكون الرّقم واحد افتراضيّا: >>> x = range(10) >>> x [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> x[0:6:2] [0, 2, 4] يُمكننا عكس عناصر القائمة بتحديد -1 كقيمة للزيّادة بالشّكل التّالي: >>> x = range(10) >>> x [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> x[::-1] [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] يُمكن كذلك تغيير قيم عناصر القائمة بتعيين قيمة أخرى: >>> x = [1, 2, 3, 4] >>> x[1] = 5 >>> x [1, 5, 3, 4] يُمكن استعمال العامل in للتحقق من تواجد عنصر في القائمة، فإن أرجع القيمة True فهذا يعني أن القيمة موجودة، أما إن أرجع False فهذا يعني بأنّ القيمة غير موجودة في القائمة: >>> x = [1, 2, 3, 4] >>> 2 in x True >>> 10 in x False يُمكن إضافة قيم أخرى إلى قائمة بدالّة الإلحاق append، في المثال التّالي نلحق (نضيف) القيمة 3 إلى القائمة a: >>> a = [1, 2] >>> a.append(3) >>> a [1, 2, 3] السلاسل النصية السّلاسل النّصيّة أو Strings هي التّقنيّة المُستخدمة لكتابة النّصوص في بايثون، وهي سلاسل من الحروف (والتّي بدورها تُشكل جملا فنصوصا)، فمثلا الكلمة "مرحبا" عبارة عن سلسلة نصيّة تحتوي على 5 عناصر، ويمكن الوصول إلى كلّ عنصر كالآتي: العنصر رقم 0 => م العنصر رقم 1 => ر العنصر رقم 2 => ح العنصر رقم 3 => ب العنصر رقم 4 => ا مع ملاحظة أنّ المسافات تُحسَبُ كذلك في السّلاسل النّصيّة فمثلا السّلسلة "مرحبا " تحتوي على 6 عناصر (لاحظ المسافة بعد الألف). وتكون السلاسل النّصية ضمن علامتي تنصيص مزدوجتين "" أو علامتي تنصيص مُفردتين ''. >>> x = "hello" >>> y = 'world' >>> print x, y hello world مع ملاحظة أنّ هناك فرقا بين علامات التّنصيص المزدوجة والمنفردة، ويُمكن استعمالهما بشكل تبادلي. أمّا السّلاسل النّصيّة التي تحتوي على أكثر من سطر، فيُمكن تعيينها لمُتغيّر باستعمال ثلاثة رموز إمّا ''' أو """، انظر المثال التّالي (لكي يعمل بشكل جيّد، من المُفضّل وضعه في ملفّ باسم example1.py وتنفيذه بالأمر python example1.py): x = """This is a multi-line string written in three lines.""" print x y = '''multi-line strings can be written using three single quote characters as well. The string can contain 'single quotes' or "double quotes" ''' print y في المثال أعلاه قمنا بتعيين سلسلة من ثلاثة أسطر للمُتغيّر x بحيثُ يكون المُخرج عند طباعة المُتغيّر x: This is a multi-line string written in three lines. يُمكن كذلك إنشاء سلسلة نصيّة متعدّدة الأسطر بإضافة \n إلى نهاية كلّ سطر، انظر المثال: >>> x = 'This is a multi-line string\nwritten in\nthree lines.' >>> print x مُخرجات المثال أعلاه: This is a multi-line string written in three lines. يُمكن الاستعانة بدّالة المُعرّفة مُسبقا في بايثون لقيّاس عدد أحرف سلسلة نصّية، وهذه الدّالة تُدعى len ويُمكن استخدامها على النّحو التّالي: >>> len("Abdelhadi") 9 السّلاسل النّصيّة في بايثون تتصرّف تماما كالقوائم، بحيث تكون السّلسلة بمثابة قائمة تحتوي على عدّة أحرف، ويمكن فهرسة (الوصول إلى عناصر السّلسلة) وتقطيع السّلاسل النّصيّة بتتبع نفس مبدأ القوائم، انظر المثال: >>> a = "helloworld" >>> a[1] 'e' >>> a[-2] 'l' >>> a[1:5] "ello" >>> a[:5] "hello" >>> a[5:] "world" >>> a[-2:] 'ld' >>> a[:-2] 'hellowor' >>> a[::-1] 'dlrowolleh' يُمكن استعمال العامل in للتحقق فيما إذا كانت السّلسلة النّصيّة جزءا من سلسلة أخرى، في المثال التّالي نقوم بالتحقق من أنّ كلّا من hell و full و el ضمن hello: >>> 'hell' in 'hello' True >>> 'full' in 'hello' False >>> 'el' in 'hello' True عندما يكون المخرج True (صحيح) فهذا يعني بأنّ السّلسلة الصغيرة جزء من السّلسلة النّصيّة الكبيرة. هناك العديد من العمليّات التّي يُمكن تطبيقها على السّلاسل النّصيّة، وسنتعرّف على بعض منها فيما يلي من الأسطر: split: فصل سلسلة نصّية إلى أجزاء يفصل بينها أي رمز (شرط أن يكون في السّلسلة) نقوم بتمريره إلى هذه الدّالة، إذا لم تُحدّد أي فاصل فاستعمل split على فصل السّلسلة النّصيّة اعتمادا على مسافة بيضاء (أي تقسيم الجملة إلى كلمات)، لتفهم أكثر ما الذي أقصده تمعّن في المثال التّالي فبه سيتّضح المقال: >>> "hello world".split() ['hello', 'world'] >>> "a,b,c".split(',') ['a', 'b', 'c'] join: هذه الدّالة تعكس مفعول split حيث تجمع بين عناصر القائمة وترجعها سلسلة نصّية: >>> " ".join(['hello', 'world']) 'hello world' >>> ','.join(['a', 'b', 'c']) 'a,b,c' strip: تقوم بإرجاع سلسلة نصية مع حذف المسافات الزائدة. >>> ' hello world\n'.strip() 'hello world' في المثال أعلاه، يدّل الرّمز \n على "سطر جديد" بحيث يطبع السّطر التّالي سطرين الأول hello والثّاني world: >>> print 'hello\nworld' hello world يُمكن كذلك تمرير قيمة نصيّة لـstrip بحيث تُرجع الدّالة سلسلة نصيّة بدون القيمة المُمَرّرَةِ، لاحظ بأنّها تحذف فقط العناصر الموجودة في بداية وآخر السّلسلة، انظر المثال (لاحظ بأنّ d لم تُحذف، وذلك لأنّها وسط السّلسلة): >>> 'abcdefgh'.strip('abdh') 'cdefg' replace: تقوم باستبدال جزء من السّلسلة أو كامل السّلسلة بقيمة أخرى: >>> 'Hsoub Academy'.replace('Academy', 'I/O') 'Hsoub I/O' تمارين تمرين 1 ما مُخرجات البرنامج التّالي (اُكتبه في ملفّ باسم exercise1.py ثمّ قم بتنفيذه بالأمر python exercise1.py): x = [0, 1, [2]] x[2][0] = 3 print x x[2].append(4) print x x[2] = 2 print x تمرين 2 كم عدد عناصر القائمة x في المثال التّالي (لا تقم بالأمر يدويّا، بل استعن بما تعلّمته): x = [1, 2, "hello, "world", ”Hi”, 4, 8, 3, 0, “Abdelhadi”, “Hsoub Academy”] تمرين 3 أزل القيمة "bad" من السّلسلة التاليّة: >>> 'python is awesome bad' ترجمة -وبتصرف- للكتاب Python Practice Book لصاحبه Anand Chitipothu.
-
بعد أن تعلّمنا في الدّرس السّابق كيفيّة التّعامل مع التّعابير الشّرطية، وكيفيّة استعمال الجمل الشّرطية في برامجنا وكيفّية القيّام بإزاحة مناسبة عند التّعامل مع أجزاء متعدّدة من الشّيفرة في لغة بايثون، سنكمل مشوار تعلّم هذه اللغة الجميلة. سنتعلّم في هذا الدّرس كيفيّة التّعامل مع حلقات التّكرار مثل حلقة for وحلقة while. مع التذكير بأنّ جميع الشّيفرات التّي تبدأ بعلامة <<< يجب أن تنفّذ على مفسر بايثون. تُمكّنك الحلقات من تكرار شيفرة عددا من المرّات، يُمكنك أن تحدّد عدد مرّات التّكرار حسب إرادتك. حلقة While حلقة While تقوم بتكرار شيفرة ما عندما يكون الشّرط محقّقا ولا تتوقّف إلا عندما يكون الشّرط خاطئا، ولإنشاء حلقة while يجب تحديد عدد المرّات التّي تتكرّر فيها ووضعها كشرط ثم زيادة قيمة مُتغيّر بواحد، بحيث يزداد إلى أن يصل إلى العدد المُحدّد في الشّرط فيتوقّف. بإمكانك أيضًا تحديد شرط من نوع آخر بحيث لا ترتبط الحلقة بتنفيذ الشيفرة بعدد مُعيّن من المرّات وإنما بتحقق شرط مُعيّن (أن تصبح قيمة مُتغيّر مُخالفة لقيمة نقوم بتحديدها) لنقل بأنّنا نريد طباعة "Hello" مائة مرّة، بالطّبع قد تقول أكرّر الجملة التالية مائة مرة: print "Hello" هذه الطّريقة صحيحة لكنّها تُكلّف الكثير من الوقت، والمُبرمج دائما ما يُفكّر بطريقة أذكى (افعل أكثر عدد ممكن من المهام في أقل وقت ممكن). لذلك لا يُمكننا اعتماد هذه الطّريقة. وتُقدم لنا لغات البرمجة خاصية التكرار ببساطة وبأقل عدد من الأسطر. كمثال يُمكننا طباعة "Hello" عشر مرّات بالطّريقة التّاليّة، لاحظ بأنّ الجمل التّابعة للكلمة while مُزاحةٌ بأربع مسافات بيضاء: >>> i = 0 >>> while i < 10: ... print "Hello" ... i = i +1 Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello شرح المثال أعلاه: السّطر الأول: نقوم بوضع قيمة بدئية للمتغيّر i. السّطر الثّاني: نقوم بإضافة الشّرط وهو أن تكون قيمة المتغير أصغر من العدد عشرة فإن كان يُساوي 10 يتوقّف البرنامج. السّطر الثّالث: نقوم بطباعة الكلمة السّطر الرّابع: نقوم بزيّادة قيمة المتغير في المرّة الأولى سيقرأ المفسّر قيمة المُتغيّر فيجدها تُساوي العدد 0، ثمّ يتحقّق من أنّ شرط أن تكون القيمة أصغر من 10 صحيح، وبما أنّ الشّرط مُحقّق في المرّة الأولى (بالطّبع لأنّ 0 أصغر من 10) سيُتابع البرنامج العمل، وسيطبع جملة التّرحيب "Hello" بعد ذلك يزيد المُفسّر قيمة المتغيّر i بواحد (لتكون القيمة الجديدة هي 1) يتحقّق المُفسّر من صحّة الشّرط مُجدّدا وبما أنّه مُحقّق فقد طُبعت الجملة "Hello" مرّة ثانيّة، بعدها يزيد من قيمة المُتغيّر بواحد مجدّدا لتكون القيمة الجديدة للمُتغيّر i هي العدد 2 والذي بدوره أصغر من 10 فتُطبع الجملة مرّة ثالثة. وهكذا دواليك إلى أن تصل قيمة المُتغيّر إلى العدد 10 فيُصبح الشّرط خاطئا (لأنّ العدد 10 ليس أصغر من 10 بل مُساو له)، وبالتّالي يتوقّف التّكرار. لتستوضح الأمر بشكل أفضل، يُمكنك أن تطبع قيمة المُتغيّر i عند كلّ تكرار، انظر المثال: >>> i = 0 >>> while i < 10: ... print "Hello", i ... i = i +1 ... Hello 0 Hello 1 Hello 2 Hello 3 Hello 4 Hello 5 Hello 6 Hello 7 Hello 8 Hello 9 أمثلة تطبيقية لاستعمال حلقة While مثال 1: الوصول إلى عناصر قائمة، مجموعة أو صف هناك عدّة أمثلة تطبيقيّة لاستعمال حلقة While، وعلى سبيل المثال يُمكن أن تُستخدم حلقة التّكرار هذه للدّوران على قائمة وطباعة عناصرها، انظر المثال التّالي: >>> I = 0 >>> children = ['Omar','Khaled','Hassan','Zaid','Youssef'] >>> while i < len(children): ... print children[i] ... i = i + 1 ... Omar Khaled Hassan Zaid Youssef في المثال أعلاه، قُمنا بإنشاء قائمة باسم children تحتوي على خمسة عناصر، ثمّ قُمنا بطباعة كلّ عنصر عند كلّ تكرار، وقد وضعنا وجوب أن تكون قيمة المُتغيّر i أصغر من عدد عناصر القائمة والتّي حدّدناها بمُساعدة الدّالة len، وذلك ليتوقّف البرنامج عند وصول قيمة المتغير إلى العدد 5. مُلاحظة: هذا مجرّد مثال لكيفيّة استخدام حلقة While. وعادة ما تُستخدم الحلقة for لمثل هذه التّطبيقات (الدّوران على القوائم، المجموعات والصفوف…) وذلك لأنّها أكثر مرونة، وفي النّهاية يعود الاختيار لك (ويُمكنك استخدام الطّريقة التّي تُناسبك). دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن مثال 2: عمل البرنامج إلى أن يجيب المستخدم بجواب معين لنقل بأنّك سألت المُستخدم سؤالا رياضيا (مثلا: "ما جمع 4 زائد 3" )، وتريد تهنأته عند إدخال الجواب الصحيح، الأمر بسيط، ولا يتعدى بضعة أسطر، افتح ملفّا وسمّه Answer.py، وضع فيه الأسطر التّالية: number = raw_input('Enter the Result of 3+4: ') if int(number) == 7: print 'Congratulation' نستخدم الدّالة int هنا لتحويل القيمة المُدخلة من طرف المُستخدم إلى قيمة من نوع integer أي عدد صحيح، وهذا مُفيد لأنّ القيمة التّي تُستقبل في الدّالة raw_input تكون عبارة عن سلسلة نصيّة. بعد أن قُمنا بجزء من المطلوب لنفترض بأنّ المُستخدم قد أدخل إجابة خاطئة، الأمر الذي قد يخطر في بالك الآن هو طباعة جملة تُفيد المُستخدم بأنّ إجابته خاطئة والخروج من البرنامج، الأمر جيّد ، ولكن ماذا لو أردنا أن نوفّر للمُستخدم حقّ المُحاولة من جديد، بحيث يطبع البرنامج جملة تفيد بأنّ الإجابة المُدخلة خاطئة ثمّ يطلب من المُستخدم أن يُحاول مجدّدا مع توفير إمكانيّة إدخال قيمة جديدة، يُمكن أن نقوم بذلك بالاستعانة بجملة else انظر المثال التّالي: number = raw_input('Enter the Result of 3+4: ') if int(number) == 7: print 'Congratulation!' else: print 'Sorry, Your Answer is not correct, please try again:' number = raw_input('Enter the Result of 3+4: ') if int(number) == 7: print 'Congratulation!' هذه الشّيفرة جيّدة لكنّها غير عمليّة بتاتا، إذ تستخدم الكثير من التّكرار الذي لا فائدة منه، كما أنّها لا توفّر للمُستخدم سوى محاولة واحدة أخرى. فماذا لو أردنا أن نوفّر للمُستخدم عددا أكبر من المُحاولات؟ قد تقول ننسخ الشّيفرة أعلاه ونكرّرها عددا من المرّات في برنامجنا، هذا الحلّ سيء جدّا وذلك لأنّه لا يلبّي رغبتنا في توفير عدد لا نهائي من المحاولات للمُستخدم (بحيث لا يتوقّف البرنامج إلا عندما يجد المُستخدم الإجابة الصّحيحة)، كما أنّ نسخ الشّيفرة وتكرارها عدّة مرّات سيجعل من البرنامج طويلا وصعب القراءة. لحلّ هذه المُسألة، يُمكننا ببساطة أن نكرّر الشّيفرة التّي تتحقّق من الإجابة كلّ مرّة تُخالف فيه الإجابة التّي أدخلها المُستخدم، يعني يُمكننا أن نُخبر البرنامج بالتّحقّق من الإجابة إذا كانت صحيحة فكل شيء جيّد ونطبع رسالة تهنئة، إذا كانت الإجابة خاطئة، فسنعيد الشّيفرة مُجدّدا، ونعيد السّؤال إلى أن يصل المُستخدم إلى الإجابة الصحيحة، والتّالي مثال على الشيفرة التي تؤدي الغرض: number = raw_input('Enter the Result of 3+4: ') while int(number) != 7: number = raw_input('Wrong answer please try again, enter the Result of 3+4: ') print 'Congratulation' السّطر الأول: يقوم البرنامج بطلب الإجابة من المُستخدم. السّطر الثاني: تتحقّق حلقة While من كون الإجابة خاطئة، إذا تحقّق الشّرط، ينتقل البرنامج إلى السّطر الثالث، إذا لم يتحقّق (أي قيمة المتغير تساوي 7)، ينتقل البرنامج إلى السّطر الرابع. السّطر الثالث: يقوم البرنامج بإخبار المُستخدم بأنّ الإجابة خاطئة ويطلب منه إعادة المُحاولة. السّطر الرابع: يطبع البرنامج جملة التهنئة. حلقة التكرار For حلقة For جملة برمجية أخرى تُمكّن من التكرار، وهي من الأساليب المُستعملة للدوران حول قيم القوائم كذلك، وتتميّز بتعريف مُتغيّر العدّ في بداية الحلقة، أي أنّك على خلاف حلقة While لا تحتاج إلى تعريف المُتغيّر قبل البدء بكتابة الحلقة، كما أنّ حلقة for لا تحتاج إلى شرط معيّن بل تُحدّد عدد مرّات التّكرار حسب عدد عناصر القائمة المُسندة. انظر المثال التّالي، لاحظ بأنّ الجمل التّابعة للسّطر (for counter in range(1, 11 مُزاحةٌ بأربع مسافات بيضاء (انظر درس الإزاحات والمساحات البيضاء). >>> for counter in range(1, 11): ... print counter, 'Hello World!' ... 1 Hello World! 2 Hello World! 3 Hello World! 4 Hello World! 5 Hello World! 6 Hello World! 7 Hello World! 8 Hello World! 9 Hello World! 10 Hello World! في المثال أعلاه أنشأنا حلقة تكرار تدور على قائمة أنشأناها باستخدام الدّالة range، وأسندنا قيم التّكرار إلى المتغيّر counter الاختلاف هنا عن حلقة while هو أنّ المُتغيّر counter يعتبر جزءا من قائمة وليس مُتغيّرا يحمل قيمة في كلّ تكرار. مُلاحظة: لدّالة range تقوم بإنشاء قائمة أعداد مرتّبة من الأصغر إلى الأكبر حسب عاملين الأول رقم البداية والثّاني يُمثّل النّهاية مع ملاحظة بأنّ الرّقم النّهائي في السّلسلة لا يحتسب (في المثال التّالي 1 هو العدد الأول والعدد النّهائي هو العدد 11 ). >>> range(1,11) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] يُمكن إنشاء قائمة معكوسة بتمرير معامل ثالث بقيمة 1- وقلب المعاملات: >>> range(10, 0, -1) [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] تُمكّنُ حلقة for من الدّوران على عناصر مجموعة ما (القوائم الصفوف، السّلاسل النّصيّة…) عن طريق تمرير اسم المُتغيّر بعد كلمة in في الشيفرة، لاحظ بأنّ الجمل التّابعة للسّطر for lettre in v مُزاحةٌ بأربع مسافات بيضاء (انظر الدّرس السّابق). >>> v = "Hello" >>> for lettre in v: ... print lettre ... H e l l o في المثال أعلاه، قمنا بتعيين القيمة "Hello" للمتغير v وبعدها استخدمنا حلقة for لكي نطبع كل حرف من هذه الكلمة والذي عيّناه للمتغير lettre. كما رأينا من قبل يُمكن كذلك استخدام for لتكرار شيفرة ما عددا من المرّات، كما فعلنا مع حلقة while بمُساعدة الدّالة range: for i in range(0,100): print i يُمكن كذلك أن نستعمل حلقة for لنقوم بالمرور على مفاتيح قاموس ما لنحصل على كل مفتاح على حدة، انظر المثال التالي: >>> a = {'x': 1, 'y': 2, 'z': 3} >>> for key in a: ... print key ... x y z وكما قلنا سابقا في الدّرس الرابع، يُمكنك الحصول على كل من مفاتيح وقيم وعناصر قاموس على شكل قائمة: >>> a = {'x': 1, 'y': 2, 'z': 3} >>> a.keys() ['x', 'y', 'z'] >>> a.values() [1, 2, 3] >>> a.items() [('x', 1), ('y', 2), ('z', 3)] ومما سبق نستنتج بأنّنا نستطيع الحصول على كل واحدة من قيم القاموس: >>> a = {'x': 1, 'y': 2, 'z': 3} >>> for value in a.values(): ... print value ... 1 2 3 وبالتّالي يُمكنك أن تستنتج بأنّنا نستطيع المرور على كل من مفاتيح القواميس وقيمها معا في نفس الوقت: >>> a = {'x': 1, 'y': 2, 'z': 3} >>> for key, value in a.items(): ... print key, value ... x 1 y 2 z 3 أمثلة تطبيقية لاستعمال حلقة For مثال 1: طباعة مفاتيح وقيم قاموس معين يُمكننا أن نستعمل حلقة for لطباعة كل مفتاح وقيمته في قاموس ما. لنقل مثلا بأنّنا نمتلك قاموسا يحتوي على أسماء الألوان وشيفرة كلّ لون بنظام hex (نظام يستخدمه مطورو الويب لإسناد لون مُعيّن لعنصر ما، فعوضا عن كتابة اسم اللون تُستخدم شيفرته)، ونُريد أن نطبع كل لون متبوعا بشيفرته، القاموس الذي نمتلكه هو كالتّالي: colors = { "red":"#f00", "green":"#0f0", "blue":"#00f", "cyan":"#0ff", "magenta":"#f0f", "yellow":"#ff0", "black":"#000" } ونريد أن نعرض هذه المفاتيح مع قيمها بشكل لطيف، هل يُمكنك أن تُفكّر في طريقة لإنجاز مرادنا؟ الحل يكون باستخدام حلقة for للمرور على كل مفتاح وقيمته ومن ثمَّ طباعتها، يُمكننا القيام بذلك بسطرين فقط من شيفرة بايثون، وذلك كالتّالي (ضعها في ملف بامتداد py ونفّذ الملف). colors = { "red":"#f00", "green":"#0f0", "blue":"#00f", "cyan":"#0ff", "magenta":"#f0f", "yellow":"#ff0", "black":"#000" } for color_name, hex_value in colors.items(): print color_name + ': ' + hex_value مُخرجات البرنامج ستكون كالتّالي: blue: #00f yellow: #ff0 green: #0f0 cyan: #0ff magenta: #f0f red: #f00 black: #000 هذا مُجرّد مثال بسيط على استخدام كل من حلقة for والقواميس على أرض الواقع، ولا يجب عليك أن تضع حدّا لإبداعك، إذ يُمكنك استخدام ما تعلّمته بطرق مُختلفة وبرمجة برمجيات تقوم بوظائف لا محدودة، لذا لا تربط علمك بهذه الأمثلة، بل فكّر في طريقة للاستفادة مما تعلّمته لإنتاج برامج أكثر تعقيدا وذات وظائف مُتعدّدة، وسيُسعدني إن شاركت برامجك معنا. إيقاف حلقة بجملة :break يُمكن أن توقف حلقة تكراريّة من نوع while عند نقطة معيّنة بالجملة break ويُمكن تحديد نقطة التوقف باستخدام جملة if الشّرطيّة، انظر المثال: >>> i = 0 >>> while i < 30: ... if i > 15: ... print "Stop the loop" ... break ... print i ... i = i + 1 ... 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Stop the loop في المثال أعلاه، كان من المُفترض أن تُكمل الحلقة التنفيذ إلى أن يصل المُتغيّر iإلى القيمة 30، ولكنّه توقّف بمُجرّد أن وصلت قيمة المُتغيّر إلى 15 وهذا لأنّنا وضعنا شرطا لإيقاف التكرار عندما تُصبح قيمة i أكبر من 15 وبما أنّ الشّرط أصبح صحيحا فقد توقّف البرنامج لأنّنا أمرناه بالجملة break. ويُمكن كذلك أن توقف حلقة تكراريّة من نوع for عند نقطة معيّنة بالجملة break ويُمكن تحديد نقطة التوقف باستخدام جملة if الشّرطيّة: >>> list = [1,5,10,15,20,25] >>> for i in list: ... if i > 15: ... print "Stop the loop" ... break ... print i ... 1 5 10 15 Stop the loop في المثال أعلاه، توقّف الدوران على القائمة list بعد أن وصل المتغيّر إلى القيمة 15، وهذا هو الشرط الذي وضعناه في جملة if. تجاهل تنفيذ الشيفرة في حلقة بجملة :continue يُمكن أن توقف حلقة تكراريّة من نوع for عند نقطة معيّنة ثمّ تُكمل التكرار في الخطوة التّاليّة، أي قفز خطوة عند التّكرار، وذلك بالاستعانة بالجملة continue ويُمكن تحديد نقطة التوقف باستخدام جملة if الشّرطيّة، يعني أنّك تستطيع إخبار البرنامج بالانتقال إلى التنفيذ التّالي إذا ما تحقّق هذا الشّرط، انظر المثال: >>> list = range(1, 31) >>> for i in list: ... if i == 15: ... print "Continue the loop" ... continue ... print i ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Continue the loop 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 في المثال أعلاه، كان من المُفترض أن تُكمل الحلقة التنفيذ إلى أن يصل المُتغيّر iإلى القيمة 30، ولكنّه توقّف بمُجرّد أن وصلت قيمة المُتغيّر إلى 15 وتابعت عندما وصلت القيمة إلى العدد 16 وهذا لأنّنا وضعنا شرطا لإيقاف التكرار عندما تُساوي قيمة i العدد 15 وبما أنّ الشّرط قد تحقّق فقد توقّف البرنامج عند تلك النّقطة وطبع جملة Continue the loop لأنّنا أمرناه بالجملة continue. تمارين صديقي القارئ، يجب أن تعرف بأنّ التّعلم لا يكتمل إلا بتطبيق المُكتسبات، لذلك فالتّفكير في حلول هذه التّمارين أمر فعال جدا ومُفيد لك، لذلك لا تكن كسولا، ولا تكتف بالقراءة فقط، بل عليك تطبيق ما تعلّمته وإنشاء برامجك الخاصّة، خاصّة وأنّك إلى الآن قد تعرّفت على جزء كبير من تقنيات البرمجة التي تسمح لك بإنشاء برامج مُبهرة، تُؤدي أغراضا عديدة. يُمكنك أن تنشر حلول التّمارين في صندوق التعليقات إذا كنت ترغب في ذلك، ومن المفضل أن تُحاول حل التّمارين بنفسك قبل أن تنظر إلى أجوبة زملائك. تمرين 1 اكتب برنامجين يقومان بطباعة جملة: Hello World! 1000 مرة. البرنامج الأول باستخدام حلقة While والثاني بحلقة For. تمرين 2 اكتب برنامجا يقوم بأخذ قيمة من المُستخدم ثمّ يطبعها 10 مرات. تمرين 3 ما مُخرجات البرنامج التّالي: number = 3 list = range(1, 31) for i in list: if i == number: continue if 15 < i < 21: continue print i تمرين 4 اكتب برنامجا يقوم بطباعة عناصر القائمة التّالية مع جملة ترحيب. list = ['Ahmed', 'Abdelhadi', 'Dyouri', 'Hossam', 'Mohammed', 'Khaled', 'Ibrahim', 'Othman'] يجب أن تكون مُخرجات البرنامج كالتّالي: Hello, Ahmed Hello, Abdelhadi Hello, Dyouri Hello, Hossam Hello, Mohammed Hello, Khaled Hello, Ibrahim Hello, Othman تمرين 5 عد إلى الدّرس السّابق وعدّل برنامج تسجيل الدخول لكي يقبل مُحاولة المُستخدم من جديد إذا كانت كلمة السّر خاطئة. ولا تنس أن تنشر برنامجك في قسم التّعليقات على هذا المقال إذا أردت ذلك. ترجمة -وبتصرف- من الكتاب Python Practice Book لصاحبه Anand Chitipothu.
-
تعلمنا إلى الآن مُعظم أساسيات لغة بايثون، تعلمنا كيفية التعامل مع أنواع البيانات المُختلفة، الحصول على مُدخلات من المُستخدم، التعابير الشرطية، حلقات التكرار واستعمال الدوال في برنامجنا لمرونة أكثر. وسنتعلم اليوم كيفيّة التعامل مع الملفات النّصية في لغة بايثون، كيفية الكتابة على ملف، وكيفية قراءة مُحتويات ملف مُعيّن. ما معنى Files I/O؟ ترجمة File هي "ملف" أما I/O فهو اختصار لـكلمتي Input و Output اللتان تعنيان المُدخل والمُخرج على التوالي. تعرفنا إلى الآن على دالتين للقيام بهاتين العمليتين الأولى هي الدالة print للإخراج والدالة raw_input للإدخال. لكنّ هذه الدوال لا تعمل إلا أثناء تشغيل البرنامج، فبعد انتهاء تنفيذه سيعود كل شيء إلى طبيعته وستفقد البيانات التي طبعتها أو التي حصلت عليها من المُستخدم. ماذا لو أردت أن تحتفظ بالبيانات في ملف ما؟ هذا بالضبط ما سنتعلمه اليوم. وإليك مُخطّطا لهذا الدرس: فتح ملف في لغة بايثون. أنماط الوصول Access modes. الكتابة على الملف. قراءة الملف. الدوال المُساعدة عند فتح ملف. إغلاق الملف. الجملة format سأستعمل في هذا الدّرس جملة جديدة لم يسبق لنا أن تحدّثنا عنها في الدروس السابقة وهي جملة format التي تُعتبر بمثابة مُحوّل لأنواع القيم المُختلفة إلى قيمة نصيّة، وتُساعد على دمج أي نوع داخل سلسلة نصّية دون الحاجة إلى تحويله بالدالة str. انظر المثال التالي: >>> '{0}, {1}, {2}'.format('a', 'b', 'c') 'a, b, c' يُمكن تبسيط الشيفرة أعلاه لتكون كالتّالي: >>> '{}, {}, {}'.format('a', 'b', 'c') إليك مثالا لطريقة الاستفادة منها في الواقع: >>> print 'Hello {} : {} : {} : {}'.format('Abdelhadi', 4, 22.4, True) Hello Abdelhadi : 4 : 22.4 : True لاحظ أنّ المُعاملات المُمرّرة للدالة قد أخذت مكان العلامات {} رغم أنّ كلّ قيمة ذات نوع مُختلف عن الأخرى. الطّريقة أعلاه أفضل بكثير من الطّريقة التّقليدية: >>> print 'Hello', 'Abdelhadi', ':', str(4), ':', str(22.4), ':', str(True) Hello Abdelhadi : 4 : 22.4 : True ويُمكنك أيضا أن تؤدي أغراضا أخرى بهذه الجملة، مثلا يُمكنك أن توزع سلسلة نصيّة على أماكن مُعيّنة في السّلسلة كالتالي: >>> '{0}, {1}, {2}'.format(*'abc') 'a, b, c' تستطيع تغيير ترتيب العناصر ببساطة: >>> '{2}, {1}, {0}'.format(*'abc') 'c, b, a' ويُمكنك أيضا أن تدمج عناصر القواميس في السلاسل النّصيّة بسهولة وذلك بالطّريقة التالية: >>> table = {'Abdelhadi': 1929, 'Ahmed': 1222, 'Omar': 1320} >>> print 'Ahmed: {Ahmed:d}; Abdelhadi: {Abdelhadi:d}; Omar: {Omar:d}'.format(**table) Ahmed: 1222; Abdelhadi: 1929; Omar: 1320 لاحظ النّجمتين ** قبل الاسم table. فتح ملف في لغة بايثون قبل أن نتعامل مع أي ملف يجب علينا أولا أن نفتحه، تماما كما تفتح أي ملف نصي للتعديل عليه بمُحرّر النّصوص. لكننا في هذا الدرس سنستعمل لغة بايثون للقيام بذلك. وتوفر لغة بايثون دالة open لفتح الملفات، والتي يُمكنك أن تستخدمها بالشكل التالي: open('filename.txt', 'Access mode') المعامل الأول المُعامل الأول هو اسم الملف، لاحظ أنّك تستطيع استبدال filename بأي اسم تريده ويُمكنك حتى أن تستبدل الامتداد، فمثلا يُمكنك أن تستعمل امتداد ملفات بايثون py بحيث تُصبح الدالة كالتالي: open('python_file.py', 'Access mode') الملف يجب أن يكون في مُجلّد العمل، إذا كنت تستعمل نظام GNU/Linux أو نظام Mac وفتحت مُفسر بايثون أو نفّذت ملفا بامتداد py فالملف يجب أن يكون في المجلد الذي قمت بالعملية منه (في الغالب يكون مجلّد المنزل home). أما إذا كنت تستخدم مُفسر لغة بايثون على نظام Windows فسيكون الملف داخل مجلّد تنصيب حزمة Python والذي غالبا ما يكون في القرص C ومجلد باسم PythonNN مع استبدال NN برقم الإصدار الخاص بلغة بايثون، فمثلا لو قمت بتنصيب الإصدار 2.7 فسيكون مسار المُجلد التالي: C:\Python27 إذا واجهت مشاكل في إيجاد مجلّد العمل يُمكنك تنفيذ الشيفرة التالية للحصول على مسار المُجلّد: >>> import os >>> os.getcwd() المُخرجات ستكون كالتالي (حسب نظام التّشغيل واسم المُستخدم لديك): '/home/dyouri' يُمكنك حفظ المُخرج في مُتغير إذا أردت ذلك. ولا تقلق إذا لم تفهم الأسطر السابقة، إذ سنتحدّث عنها في درس لاحق. المعامل الثاني بالنّسبة للمعامل الثاني (Access mode ) فهو نمط الوصول الذي ترغب بفتح الملف به وهو إما للكتابة أو للقراءة أو كليهما. انظر الفقرة التالية. أنماط الوصول Access modes عند فتح ملف في لغة بايثون، تكون مطالبا بتوفير معاملين للدالة open المُعامل الأول هو اسم الملف، والمعامل الثاني هو نمط الوصول، أي السبب الذي فتحت الملف من أجله، وهناك العديد من الخيارات لذلك، وإليك أهم الخيارات التي يجب عليك أخذها بعين الاعتبار حسب هدفك من فتح الملف: فتح الملف للقراءة r: هذا هو النمط الافتراضي إذا لم تحدد المُعامل الثاني في دالة open ويُمكنك من قراءة ملف بأحد الدوال المُتاحة لذلك (انظر فصل قراءة الملف). مثال: open('file.txt', 'r') r+: يُفتح الملف في هذا النمط للقراءة والكتابة معا، مع وضع مؤشّر الفأرة في بداية الملف. مثال: open('file.txt', 'r+') فتح الملف للكتابة w: يُفتح الملف فقط للكتابة، إذا كان الملف موجودا فإنّه يكتب عليه (Overwrite) أي أنّك ستفقد البيانات الأصلية. إذا لم يكن الملف موجودا فإنّ الدالة تنشئ ملفا جديدا للكتابة. مثال: open('file.txt', 'w') w+: فتح الملف لكل من الكتابة والقراءة، إذا كان الملف موجودا فستتم الكتابة عليه (Overwrite). إذا لم يكن الملف موجودا فإنّ الدالة تنشئ ملفا جديدا للكتابة والقراءة. مثال: open('file.txt', 'w+') a: إذا كان الملف موجودا أصلا، فسيُفتح للإلحاق Appending، أي أنّ مُكونات الملف تبقى كما هي، إذا أضفت أي نصّ فسيُضاف في آخر الملف. إذا لم يكن الملف موجودا فسيتم إنشاء ملف جديد. مثال: open('file.txt', 'a') a+: إذا كان الملف موجودا فإنّه يُفتح لكل من الإلحاق والقراءة، إذا لم يكن موجودا فسيتم إنشاء ملف جديد. مثال: open('file.txt', 'a+') الكتابة على الملف بعد فتح الملف سواء أكان موجودا من قبل أو أنّك أنشأته بالدالة نفسها، ستستطيع الكتابة على الملف وإضافة نصوصك الخاصّة، وذلك بالدالة write مع مُعامل عبارة عن سلسلة نصية، انظر المثال التالي: >>> file = open('file.txt', 'w') # فتح الملف وإسناده إلى مُتغير >>> file.write('Hello World!') # الكتابة بالملف >>> file.close() # إغلاق الملف ملاحظة: إذا كنت تستعمل المُفسّر، فلحفظ التعديلات عليك الخروج من المفسّر أو إغلاق الملف والذي يُمكنك القيام به بالدالة close، مع ملاحظة أنّك لن تتمكن من تعديل الملف بعد إغلاقه، أي أنّك ستحتاج إلى فتحه من جديد بالدالة open. لن تُلاحظ أي مُخرجات عند تنفيذك لأي أمر أعلاه، ولكن رغم ذلك فإنّك إذا فتحت الملف file.txt بأي مُحرّر للنّصوص (Notepad مثلا)، فإنّك ستُلاحظ الجملة !Hello World في بداية الملف. لاحظ بأنّنا فتحنا الملف بنمط الكتابة فقط (w)، إذا فتحت الملف بنفس النّمط مُجدّدا فإنّ التغييرات التي ستكتبها ستُغطّي محتويات الملف. أي أنّك إذا نفّذت الأوامر التاليّة فإنّ مُحتويات الملف ستُصبح الجملة !Hello Python عوضا عن جملة !Hello World # -*- coding: utf-8 -*- >>> file = open('file.txt', 'w') # فتح الملف وإسناده إلى مُتغير >>> file.write('Hello Python!') # الكتابة بالملف >>> file.close() # إغلاق الملف يُمكنك إضافة أكثر من مُدخل في كلّ مرّة، المهم أن تكتب على الملف قبل إغلاقه: >>> file = open('file.txt', 'w') >>> file.write('Abdelhadi Dyouri!') >>> file.write('Hsoub Academy!') >>> file.close() بعد تنفيذ الشيفرة أعلاه، ستكون مُحتويات الملف كالتالي: Abdelhadi Dyouri!Hsoub Academy! لاحظ بأنّ لغة بايثون لا يعود إلى سطر جديد في كل مرة، ولكي تحلّ هذه المسألة فيُمكنك ببساطة إضافة الرّمز n\ بين كل سطر، انظر المثال التّالي: >>> file = open('file.txt', 'w') >>> file.write('Abdelhadi Dyouri!\nHsoub Academy!') >>> file.close() مُحتويات الملفّ بعد تقسيم الأسطر بالرّمز n\ هي كالتالي: Abdelhadi Dyouri! Hsoub Academy! لاحظ بأنّ الشيفرة أعلاه لها نفس تأثير ما يلي: >>> file = open('file.txt', 'w') >>> file.write('Abdelhadi Dyouri!\n') >>> file.write('Hsoub Academy!') >>> file.close() كلّ ما تعلمناه إلى الآن هو كيفية إعادة كتابة الملف، ولكن ماذا لو أردت أن تُبقي على محتويات الملف وترغب بإضافة نصوص له؟ يُمكنك ذلك عن طريق تغيير نمط الوصول إلى نمط الإلحاق عوضا عن نمط الكتابة، لنضف المزيد من النّصوص إلى الملف السابق، إلى الآن مُحتوياته هي كالتالي: Abdelhadi Dyouri! Hsoub Academy! لنضف أقسام الأكاديمية إلى آخر الملف، انظر المثال التالي: >>> file = open('file.txt', 'a') >>> file.write('\nFreelance\nEntrepreneurship\nDesign\nApps\nCertificates\nDevops\nMarketing') >>> file.close() لاحظ تغيير المُعامل الثاني في دالة open من w إلى a. بعد تنفيذ الشيفرة أعلاه ستكون مُحتويات الملفّ كالتالي: Abdelhadi Dyouri! Hsoub Academy! Freelance Entrepreneurship Design Apps Certificates Devops Marketing لنُطبّق ما تعلمناه في الدّروس السابقة ولنضع لكلّ قسم عنوان Url الخاص به: افتح ملفا باسم links.py وضع فيه ما يلي: links = [] list = '\nFreelance\nEntrepreneurship\nDesign\nApps\nCertificates\nDevops\nMarketing' list = list.lower().split('\n') for item in list: list = item.replace(item , 'https://academy.hsoub.com/{}'.format(item)) links.append(list) file = open('file.txt', 'w') file.write('Academy: {}'.format(links[0])) file.write('\nFreelance: {}'.format(links[1])) file.write('\nEntrepreneurship: {}'.format(links[2])) file.write('\nDesign: {}'.format(links[3])) file.write('\nApps: {}'.format(links[4])) file.write('\nCertificates: {}'.format(links[5])) file.write('\nDevops: {}'.format(links[6])) file.write('\nMarketing: {}'.format(links[7])) file.close() أولا عرّفنا قائمة روابط فارغة باسم links بعدها أسندنا الأقسام إلى مُتغيّر باسم list ثمّ حولنا الأحرف إلى أحرف صغيرة و قسّمنا السّلسلة النّصية، بعدها استعملنا الحلقة for للدوران على عناصر القائمة، وفي كلّ مرّة نستبدل قيمة القسم برابطه ونُلحق العنصر النّاتج إلى القائمة links وبعدها فتحنا الملف ووضعنا لكل قسم رابطه الخاص وأخيرا أغلقنا الملف. بعد تنفيذ الشيفرة أعلاه ستكون مُحتويات الملف file.txt كالتالي: Academy: https://academy.hsoub.com/ Freelance: https://academy.hsoub.com/freelance Entrepreneurship: https://academy.hsoub.com/entrepreneurship Design: https://academy.hsoub.com/design Apps: https://academy.hsoub.com/apps Certificates: https://academy.hsoub.com/certificates Devops: https://academy.hsoub.com/devops Marketing: https://academy.hsoub.com/marketing يُمكنك أن تجعل البرنامج أكثر ذكاء وذلك باستبدال قائمة الأقسام بمُدخل من المُستخدم وتُضيف رابط القسم إلى الملف، على سبيل المثال سيعمل البرنامج كالتالي: Enter the name of the category: مثلا لنُدخل programming للحصول على رابط قسم البرمجة، يجب أن تكون المُخرجات شيئا كالتالي: Enter the name of the category: programming Ok! Added https://academy.hsoub.com/programming to file.txt هل رأيت حلاوة البرمجة؟ تذكّر بأنّ خيالك هو حدود ما تستطيع القيام به. قراءة الملف الدالة read بعد الكتابة على الملف سيتوجّب علينا قراءته، كما الكتابة تُوفّر لنا لغة بايثون دالة خاصة بالقراءة وهي الدالة read التي يُمكننا أن نستعملها كالتالي: file = open('file.txt', 'r') file.read() لاحظ أنّنا غيّرنا المُعامل الثاني من w إلى r وذلك لأنّنا نرغب بفتح الملفّ للقراءة. بعد تنفيذ الشيفرة أعلاه ستكون المُخرجات كالتالي: 'Academy: https://academy.hsoub.com/\nFreelance: https://academy.hsoub.com/freelance\nEntrepreneurship: https://academy.hsoub.com/entrepreneurship\nDesign: https://academy.hsoub.com/design\nApps: https://academy.hsoub.com/apps\nCertificates: https://academy.hsoub.com/certificates\nDevops: https://academy.hsoub.com/devops\nMarketing: https://academy.hsoub.com/marketing\n' إذا عاودت تنفيذ الدالة read من جديد فإنّ المُخرج سيكون سلسلة نصيّة فارغة'' وهذا يدلّ على أنّنا وصلنا إلى نهاية الملفّ، ولكي تعود إلى بداية الملف من جديد فعليك فتحه مُجدّدا بالدالة open. كما تُلاحظ فإنّ المُخرجات لا تبدو جميلة أبدا، يُمكنك أن تقرأ أسطر الملف باستخدام جملة for عوضا عن الدالة read وستكون المُخرجات نظيفة هذه المرّة. file = open('file.txt', 'r') for line in file: print line ستكون المُخرجات كالتالي: Academy: https://academy.hsoub.com/ Freelance: https://academy.hsoub.com/freelance Entrepreneurship: https://academy.hsoub.com/entrepreneurship Design: https://academy.hsoub.com/design Apps: https://academy.hsoub.com/apps Certificates: https://academy.hsoub.com/certificates Devops: https://academy.hsoub.com/devops Marketing: https://academy.hsoub.com/marketing يُمكنك أيضا تحديد كم من بايت Byte ترغب بقراءته من بداية الملف. فمثلا إذا كنت ترغب بقراءة أول 8 بايت من مُحتويات الملف، فيُمكنك تمرير العدد 8 إلى الدالة read كمُعامل: >>> file = open('file.txt', 'r') >>> file.read(8) 'Academy:' >>> file.close() المُخرجات ستكون كالتالي (أول 8 أحرف من الملف): 'Academy:' لاحظ بأنّ البايت الواحد لا يعني دائما الحرف الواحد إذ أنّ هناك استثناءات عديدة، فمثلا في اللغة العربية الحرف الواحد يشغل حوالي 2 بايت أما الأحرف الصينية فتشغل حوالي 3 بايت. في الأحرف الإنجليزية عادة ما يُساوي الحرف الواحد 1 بايت فقط. الدالة readline يُمكنك أن تقرأ سطرا واحدا من الملف في كلّ مرّة، وذلك بالاعتماد على جُملة readline عوضا عن جملة read. >>> file = open('file.txt', 'r') >>> file.readline() 'Academy: https://academy.hsoub.com/\n' >>> file.readline() 'Freelance: https://academy.hsoub.com/freelance\n' >>> file.readline() 'Entrepreneurship: https://academy.hsoub.com/entrepreneurship\n' لاحظ بأنّ المُخرج يكون مُختلفا في كلّ مرّة تُستَدعَى فيها الدالة readline إذ أنّ المُخرج يكون سطرا واحدا في كل مرة، وفي المرّة التالية تكون النّتيجة السّطر التالي إلى نهاية الملفّ. في النّهاية سيكون المخرج سلسلة نصيّة فارغة: >>> file.readline() 'Marketing: https://academy.hsoub.com/marketing\n' >>> file.readline() '' إذا أردت العودة إلى بداية الملفّ من جديد فيُمكنك ذلك إما بإغلاق الملف وفتحه من جديد أو باستعمال الدالةّ seek مع تمرير عدد البايتات الذي ترغب بتخطّيه، (أي صفرا للعودة إلى بداية الملف). >>> file.readline() '' >>> file.seek(0) >>> file.readline() 'Academy: https://academy.hsoub.com/\n' يُمكن مثلا العودة إلى أول 8 بايت من الملف بالطّريقة التالية: >>> file.seek(8) >>> file.readline() ' https://academy.hsoub.com/\n' يُمكنك أن تعتمد على الدالة tell لتعرف مركز القراءة الحالي. >>> file.seek(66) >>> file.tell() 66 تقبل الدّالة readline مُعاملا لتحديد عدد البايتات المرغوب قراءتها (تماما مثل شقيقتها read). >>> file.seek(0) # للعودة إلى بداية الملف >>> file.readline(8) 'Academy:' الدالة readlines تُعتبر الدالة readlines طريقة أخرى لقراءة الملف، وتُرجع قائمة بجميع الأسطر التي يحتويها الملف: >>> file = open('file.txt', 'r') >>> file.readlines() ['Academy: https://academy.hsoub.com/\n', 'Freelance: https://academy.hsoub.com/freelance\n', 'Entrepreneurship: https://academy.hsoub.com/entrepreneurship\n', 'Design: https://academy.hsoub.com/design\n', 'Apps: https://academy.hsoub.com/apps\n', 'Certificates: https://academy.hsoub.com/certificates\n', 'Devops: https://academy.hsoub.com/devops\n', 'Marketing: https://academy.hsoub.com/marketing'] يُمكنك مثلا حساب عدد أسطر ملفّ ما بحساب عدد عناصر القائمة بالدالة len: >>> file = open('file.txt', 'r') >>> len(file.readlines()) 8 إغلاق الملف رغم أنّ عمليّة إغلاق الملف ليست ضرورية لحفظ التّغييرات، إلّا أنّ القيام بالأمر منصوح به بشدّة، لذلك يجب عليك أن تتأكّد من أنّ الملفّ قد أُغلق بعد انتهائك من إجراء العمليّات على الملف. لقد تعرّفنا من قبل على كيفيّة إغلاق الملف: >>> file = open('file.txt') >>> file.close() للتحقق من أنّ الملف مُغلق يُمكن أن تستعين بالجملة closed والتي تُرجع قيمة منطقية (إما True أو False). إذا كان الملف مُغلقا فسترجع الجملة True أما إذا لم يكن مغلقا فستُرجع الجملة False. >>> file = open('file.txt') # فتح الملف >>> file.closed # التحقق من أنّ الملف مُغلق False >>> file.close() # إغلاق الملف >>> file.closed # التحقق من جديد True يُمكن كذلك الاستعانة بالجملة with as لفتح ملف والقيام بعمليات ثم إغلاقه آليا. with open('file.txt', 'r') as file: file.read() الملف يُغلق ذاتيا بعد انتهاء الجزء المُزاحِ (ذو الإزاحة) من الشيفرة، ويُمكنك التأكّد من الأمر بالجملة closed. الدوال المساعدة بعد فتح الملف يُمكنك الحصول على معلومات حول الملف ببعض الدوال المبنية مُسبقا Built-in functions وهي كالتالي: closed: التحقق من ما إذا كان الملف مُغلقا أو لا (انظر الفصل السابق). name: الحصول على اسم الملفّ. >>> file = open('file.txt') >>> file.name 'file.txt' mode: الحصول على نمط الوصول. >>> file = open('file.txt', 'w+') >>> file.mode 'w+' تمارين تمرين 1 اكتب برنامجا للحصول على قيم من المُستخدم وأدخلها إلى ملف نصي. تمرين 2 صحّح الخطأ في ما يلي: file = open('file.txt', 'r') file.write('Hello World!') تمرين 3 صحّح الخطأ في ما يلي: file = open('file.txt', 'w') file.write('Hello World!') file.close() file.write('Hello!') تمرين 4 اكتب برنامج تسجيل الدخول في الدروس السابقة ليقبل ملفّا كقاعدة بيانات. (احفظ اسم المُستخدم وكلمة المرور في الملف عوضا عن الذاكرة.) المصادر المعتمدة التوثيق الرّسمي للغة بايثون، فصل الدوال المبنية مُسبقا، الدالة open كتاب Python Practice Book لكاتبه Anand Chitipothu التوثيق الرّسمي للغة بايثون، فصل السلاسل النّصيّة
-
المُزخرفات من أعظم مميزات لغة بايثون، إذ تساعدك على بناء برنامجك باحترافية أكثر موفرة طريقة بسيطة لإضافة خاصيات جديدة للدالة. وهي ببساطة دوال تستطيع أن تعدل على دوال أخرى. تذكير ببعض المفاهيم الأساسية إذا لم تكن تعرف شيئا عن الدوال في لغة بايثون فيجب عليك العودة للدرس السابق الدوال في بايثون قبل أن تكمل قراءة هذا الدرس. تُعتبر الدوال في لغة بايثون كائنات من نوع الفئة الأولى أو First class objects. ما يعني أنّنا نستطيع القيام بالعديد من العمليات، وهي كالتالي: يُمكنك تعريف دالة داخل دالة أخرى يُمكنك أن تستدعي دالة داخل أخرى يُمكنك أن تقوم بتمرير دالة كمُعامل لدالة أخرى يُمكنك أن تُسند دالة لمُتغير يُمكنك إرجاع دالة داخل دالة أخرى بما أنّ المُزخرفات مُجرّد دوال فعلينا أن نبدأ من الأساس، لاحظ الدالة التالية: def say_hello(): print 'Hello!' عند استدعاء الدالة ستُطبع القيمة Hello على الشاشة، هذا ليس بالأمر المُعقد، الآن ماذا لو أردنا أن نعدل الدالة في جزء آخر من البرنامج لكي تطبع أشياء أخرى وتؤدي أغراضا أخرى قبل استدعاء الدالة أو بعد ذلك؟ يُمكن أن نعدّل الدالة مُباشرة، لكن هذا الأمر سيغير من طريقة سير البرنامج، إذ نريد أن نعدل الدالة في منطقة واحدة فقط من البرنامج وليس في كامل البرنامج، هذه المسألة تُحل بالمُزخرفات، وكما يدل اسمها فهي دوال تُزيّن وتُزخرف الدالة الأصلية، أي تُضيف عليها مهاما أخرى. سننشئ لهذه الدالة الآن مُزخرفا Decorator يقوم بطباعة Before قبل تنفيذ الدالة و After بعد تنفيذ الدالة، وذلك دون تعديل الدالة مُباشرة. انظر المثال التالي: def decorator(function): def function_decorator(): print 'Before' function() print 'After' return function_decorator الشيفرة أعلاه عبارة عن دالة تقبل دالة أخرى (الدالة التي نرغب بزَخرَفَتِها أو تزيينها) كمُعامل وبعدها نقوم بإنشاء دالة داخل هذه الدالة لطباعة القيمة Before ثم استدعاء الدالة الأصلية (المُعامل) بعدها طباعة After وأخيرا إرجاع الدالة الجديدة (وهي نُسخة مزخرفة من الدالة الأصلية). بعدها يُمكننا أن نستخدم هذا المُزخرف لزخرفة أي دالة مهما كانت، انظر المثال التالي: # -*- coding: utf-8 -*- def decorator(function): # إنشاء الدالة المسؤولة عن الزخرفة def function_decorator(): # إنشاء الدالة التي ستكون نسخة مزخرفة من الدالة المُمرّرة في كمُعامل print 'Before' # طباعة جملة قبل تنفيذ الدالة function() # استدعاء الدالة print 'After' return function_decorator # إرجاع الدالة مُزَخْرَفَةً def say_hello(): # إنشاء دالة عادية print 'Hello!' say_hello = decorator(say_hello) # زخرفة الدالة say_hello() # استدعاء النُسخة المُزخرفة من الدالة توفر لنا لغة بايثون طريقة أكثر مرونة لزخرفة الدوال، وهي بوضع اسم المُزخرف مسبوقا بالحرف @ قبل تعريف الدالة. أي أنّ السّطر التالي: def say_hello(): print 'Hello!' say_hello = decorator(say_hello) # زخرفة الدالة يُمكن أن يكون كالتالي: @decorator def say_hello(): # إنشاء دالة عادية print 'Hello!' وبالتالي سنتمكن من زخرفة أي دالة نرغب بزخرفتها كالتالي: @decorator def say_hello(): print 'Hello!' @decorator def say_hi(): print 'Hi!' @decorator def say_name(): print 'Abdelhadi!' say_hello() say_hi() say_name() عند تنفيذ الشيفرة أعلاه ستكون المخرجات كالتالي: Before Hello! After Before Hi! After Before Abdelhadi! After مُلاحظة: إذا كانت للدالة معاملات فما عليك إلا استخدام args* التي سبق وتحدثنا عنها في الدرس السابق. # -*- coding: utf-8 -*- def decorator(function): # إنشاء الدالة المسؤولة عن الزخرفة def function_decorator(*args): # إنشاء الدالة التي ستكون نسخة مزخرفة من الدالة المُمرّرة كمُعامل print 'Before' # طباعة جملة قبل تنفيذ الدالة function(*args) # استدعاء الدالة print 'After' return function_decorator # إرجاع الدالة مُزَخْرَفَةً لاحظ الدالتين function_decorator و function. أمثلة على المزخرفات في لغة بايثون إذا فهمت مبدأ المزخرفات فستستطيع أن تتعامل مع الدوال بمرونة عالية، وإليك بعض الأمثلة لاستخدام المُزخرفات لتأدية بعض المهام البسيطة: حساب مدة تنفيذ دالة إذا فهمت جيدا مبدأ المُزخرفات فستلاحظ بأنّك تستطيع تنفيذ مهام قبل تنفيذ الدالة ومهام بعد تنفيذها، ومما سبق نستنتج بأنّنا نستطيع أن نقوم بحفظ الوقت الحالي في مُتغير ثم تنفيذ الدالة وبعدها نقوم بحساب الفرق بين الوقت السابق والوقت الحالي، ما سيُرجع المُدة المُستغرقة لتنفيذ الدالة. البرنامج التالي مثال على مُزخرف لحساب مُدة دالة تطبع الجملة !Hello World مليون مرّة. # -*- coding: utf-8 -*- import time # جلب مكتبة الوقت لاستعمال دوال الوقت def function_time(function): def function_decorator(*args): start_time = time.time() # الحصول على وقت البداية function(*args) end_time = time.time() # الحصول على الوقت بعد نهاية التنفيذ # طباعة اسم الدالة والفرق بين وقت البداية ووقت النهاية print '%s function took %0.3f s' % (function.func_name, (end_time - start_time)) return function_decorator # إرجاع الدالة مُزَخْرَفَةً # زخرفة الدالة المسؤولة عن الطباعة مليون مرة @function_time def print_million_times(): for i in range(0, 1000000): print 'Hello World! 1,000,000 times!' print_million_times() البرنامج أعلاه سيطبع الجملة مليون مرة ثم يعرض الوقت المُستغرق لإنجاز العملية. الجملة الأخيرة ستكون شيئا كالتّالي: print_million_times function took 69.584 s ملاحظات: نستعمل التابع func_name للحصول على اسم الدالة المُمررة كمعامل، ويكون على شكل سلسلة نصية. نستعمل الجملة time.time للحصول على الوقت بالثواني، عدد الثواني الذي تنتجه الجملة هو عدد الثواني الذي مرّ منذ سنة 1970. يُمكنك استعمال هذا المُزخرف مع أي دالة تريد فقط اكتب اسم المُزخرف مسبوقا بالحرف @ ثم عرف الدالة بعده، وستحصل على الوقت المُستغرق لتنفيذ الدالة. حساب عدد مرات استدعاء دالة يُمكننا أن نستخدم المُزخرفات للحصول على عدد المرات التي استدعيت فيها دالة ما في برنامج مُعيّن، بحيث يحمل متغير قيمة العدد صفر، وفي كل مرة تستدعى فيها الدالة، فإن المُتغير يحمل القيمة مع زيادة بالعدد واحد، انظر المثال التالي. # -*- coding: utf-8 -*- # متغير العد n = 0 # المُزخرف def call_times(function): def decorated(): function() # استدعاء الدالة global n # جعل مُتغير العدّ عالميا n += 1 # زيادة قيمة المُتغير print 'Function was called', n, 'times' # طباعة قيمة المُتغير return decorated @call_times # زخرفة الدالة def func(): # إنشاء الدالة print 'Hello!' # استدعاء الدالة func() func() func() func() مُخرجات البرنامج أعلاه ستكون كالتالي: Hello! Function was called 1 times Hello! Function was called 2 times Hello! Function was called 3 times Hello! Function was called 4 times يُمكنك إصلاح الجمل من الناحية اللغوية بإضافة بعض العبارات الشرطية للبرنامج. إنشاء مزخرف لتنفيذ دالة عند تحقق شرط معين فقط يُمكنك أن تستعمل دالة تسجيل الدخول التي قُمنا بإنشائها كمُزخرف للدوال التي تحتاج لأن يكون المُستخدم مُسجلا دخوله. مثلا لنقل بأنّنا نريد أن نعرض على المُستخدم عدة خيارات بعضها يحتاج إلى تسجيل دخول المُستخدم وبعضها لا. الخيارات كالتّالي: تسجيل مُستخدم جديد (تسجيل الدخول غير مطلوب) طباعة جملة عشر مرات ( تسجيل الدخول غير مطلوب) الحصول على الوقت الحالي ( تسجيل الدخول غير مطلوب) طباعة اسم المُستخدم (تسجيل الدخول مطلوب) رؤية معلومات الحساب (تسجيل الدخول مطلوب) تعديل كلمة المرور (تسجيل الدخول مطلوب) مبدأ عمل البرنامج سيكون كالتالي: إنشاء الدوال المسؤولة عن الخيارات عرض الخيارات على المُستخدم زخرفة الدوال التي تطلب تسجيل المُستخدم بمُزخرف تسجيل الدخول المُزخرف سيتحقق من أنّ المُستخدم قد سجل دخوله، إذا كان الأمر كذلك، تنفّذ الدالة وإذا لم يتحقق الشرط فلا تنفذ. لنقل بأنّ اسم مُزخرف التحقق من تسجيل الدخول هو is_user_logged_in، ستكون الدوال التي تطلب تسجيل الدخول مُزَخْرَفَةً كالتالي: @if_user_logged_in def account_info(): print 'Username:', username, 'Password:', password تمارين تمرين 1 أنشئ دالة للجمع بين عددين، وبعدها أنشئ مُزخرفا يقوم بمُضاعفة النتيجة. تمرين 2 أنشئ دالة للحصول على قيم من المُستخدم وقم بزخرفة لطباعة جملة ترحيب قبل استدعاء الدالة وجملة توديع بعد استدعاءها. تمرين 3 أكمل البرنامج الخاص بالمثال الثالث (إنشاء مُزخرف لتنفيذ دالة عند تحقق شرط مُعين فقط). تفاصيل التمرين موجودة بالمثال.
- 4 تعليقات
-
- 5
-
- decorators
- مزخرفات
- (و 4 أكثر)
-
بعد أن تعلّمنا في الدّرس السّابق كيفيّة التعامل مع كل من الصفوف، المجموعات والقواميس في لغة بايثون ، سنكمل مشوار تعلّم هذه اللغة الجميلة. سنتعلّم في هذا الدّرس كيفيّة التّعامل مع التّعابير الشّرطية، و كيفيّة استعمال الجمل الشّرطية في برامجنا وكيفّية القيّام بإزاحة مناسبة عند التّعامل مع أجزاء متعدّدة من الشّيفرة، وسنكمل هذا الدّرس بمثال تطبيقي يتجلى في برنامج تسجيل حساب والولوج إليه. مع التذكير بأنّ جميع الشّيفرات التّي تبدأ بعلامة <<< يجب أن تنفّذ على مفسر بايثون. التعابير الشرطية Conditional Expressions توفّر لنا لغة بايثون عدّة مُعاملات لمُقارنة القيّم، ونتيجة المُقارنة تكون قيمة منطقيّة Boolean إمّا True أو False. >>> 2 < 3 False >>> 2 > 3 True إليك قائمة بالمُعاملات المُتوفّرة في لغة بايثون. == يُساوي =! لا يُساوي > أصغر من < أكبر من => أصغر من أو تُساوي =< أكبر من أو تُساوي ويُمكن استعمال هذه المُعاملات أكثر من مرّة في السّطر الواحد: >>> x = 5 >>> 2 < x < 10 True >>> 2 < 3 < 4 < 5 < 6 True وتعمل المعاملات على السّلاسل النّصية كذلك (التّرتيب يكون بشكل معجمي، أي حسب ترتيب الكلمات في المُعجم). >>> "python" > "perl" True >>> "python" > "java" True يُمكن الجمع بين القيّم المنطقيّة بمعاملات منطقيّة: a and b: صحيح فقط إذا كان كل من a و b يحملان القيمة True. a or b: صحيح إذا كانت إحدى القيمتين صحيحة. not a: صحيح فقط إذا كان a يحمل القيمة False. وإليك مثالا على المُعاملات المنطقيّة: >>> True and True True >>> True and False False >>> 2 < 3 and 5 < 4 False >>> 2 < 3 or 5 < 4 True الجملة الشرطية If تُستعمل الجملة الشّرطيّة If (إذا كان) لتنفيذ جزء من الشّيفرة إذا كان الشّرط مُحقّقا: >>> if x % 2 == 0: ... print 'even' ... even >>> في المثال أعلاه طُبعَت الكلمة even لأنّ باقي قسمة 42 على 2 يُساوي صفرا (x % 2 == 0)، وبالتّالي فقد تحقّق الشّرط، فلو أنّ الشّرط لم يتحقّق لما أرجع المُفسّر أي نتيجة. يُمكن استخدام If كشرط لتنفيذ جزء منفصل من الشيفرة بالإزاحة (انظر فصل الإزاحة والمساحات أسفله)، ويكون هذا الأمر مُفيدا عندما يحتوي برنامجك على الكثير من الجمل. لاحظ بأنّ الجمل التّابعة للسّطر if x % 2 == 0 مُزاحةٌ بأربع مسافات بيضاء. الجملة else يُمكن أن تزيد على جملة If بند else وترجمته (وإلّا / إذا لم يكن ذلك صحيحًا)، والتي تنفّذ الشيفرة التّي من بعدها إذا كان الشّرط الأول خاطئا. >>> x = 3 >>> if x % 2 == 0: ... print 'even' ... else: ... print 'odd' ... odd >>> في المثال أعلاه، كان الشّرط الأول خاطئا لأن باقي قسمة 3 على 2 لا يُساوي صفرًا، ولذلك انتقل البرنامج لتنفيذ الشّيفرة بعد جملة else وقام بطباعة كلمة odd. الجملة elif يُمكن كذلك أن تزيد جملة elif وهي اختصار لـ else if والتّي تعني "إذا لم يتحقّق الشرط فانظر الشّرط التّالي": >>> x = 42 >>> if x < 10: ... print 'one digit number' ... elif x < 100: ... print 'two digit number' ... else: ... print 'big number' ... two digit number >>> في المثال أعلاه، هناك شرطان مختلفان، أولا عند تحقّق شرط كون قيمة المتغيّر x أصغر من العدد 10 فسيطبع البرنامج الجملة التي تقول بأنّ قيمة المتغير x عبارة عن رقم واحد، إذا لم يتحقّق الشّرط السّابق فسينتقل البرنامج إلى الشّرط الذي يليه وهو ما يتبع الجملة elif أي إذا كانت قيمة المتغيّر x أصغر من 100 فسيطبع البرنامج الجملة التي تفيد بأنّ قيمة المتغير x عبارة عن رقمين والجملة else تنفَّذُ إذا لم يتحقّق أي شرط وتفيد بأنّ قيمة المتغيّر x عبارة عن عدد كبير (لأنّه يتكون من 3 أرقام فأكثر). المساحة والمسافات والإزاحة المساحات التّي تسبق الشّيفرات في بايثون مُهمّة جدّا لترتيب شيفرة البرنامج ولتسهيل قراءته، كما أنّها تكون ضروريّة في بايثون، فإن لم تتّبع قوانين الإزاحة فلن يعمل البرنامج، وتُستعمل هذه الطّريقة لفصل الشّيفرات التّابعة لجزء معيّن من البرنامج، والإزاحة تكون بكتابة الشّيفرة بعد عدد معيّن من المسافات، ومن المُفضّل أن تكون أربع مسافات بيضاء، انظر المثال: هل الشّرط محقّق؟ .... نعم الشّرط محقّق .... لا الشرط غير محقق انتهى البرنامج في المثال أعلاه، الجملتان "نعم الشّرط محقّق" و "لا الشّرط غير محقّق" تابعتان للجملة "هل الشّرط محقّق؟" أمّا الجملة "انتهى البرنامج" فتابعة للبرنامج عامّة. وقد اعتمدت على النّقاط لتوضيح فكرة الإزاحة فقط وعليك أن تستبدل النّقاط بالمسافات في ملفّات بايثون. يُمكن كذلك أن تكون الشّيفرة تابعة لجملة ما، والتّي بدورها تابعة لجملة أخرى، لتتّضحك الأمور أكثر، فكّر في شجرة عائلة تتكوّن من الآباء والأولاد: جدّ ....أب 1 ........ابن 1.1 ........ابن 1.2 ....أب 2 ........ابن 2.1 ........ابن 2.2 للجد ابنان، ولكل ابن ابنان، نستنتج من هذا أنّ كلّ ابن تابع لأبيه بإزاحة أربع مسافات، أمّا الحفيد فتابع للجدّ بثماني مسافات. وإلى الآن تعرّفنا على موضع واحد تكون فيه الإزاحة إجباريّة وهي الجمل الشّرطيّة، فمثلا البرنامج التّالي: x = 42 if x % 2 == 0: print 'even' print 'Hello World' في المثال أعلاه جميع السّطور المزاحة بأربع مسافات (أي الجملة التي تطبع كلمة even) تُنفّذ عند تحقّق الشّرط فقط، أي أنّها جزء مرتبط بالشّرط في البرنامج، أمّا الشيفرة التي لم تُسبق بمسافات فتنفّذ بشكل طبيعي وتعتبر ضمن البرنامج عامّة. أمّا إذا أردنا أن نطبع جملة بعد التّحقّق من شرطين فسيكون البرنامج كالتّالي: الشّرط الأول محقّق، إذن انتقل إلى الشّرط الثّاني. الشّرط الأول غير محقّق، إذن لا تنتقل إلى الشّرط الثّاني. إليك تطبيقا للأمر في لغة بايثون: # البرنامج x = 42 if x % 2 == 0: print 'even' if x / 2 == 21: print '42/2 = 21 Is true' print 'Hello World' # المُخرج even 42/2 = 21 Is true Hello World في المثال أعلاه، قمنا بالتّحقّق من أنّ باقي قسمة العدد 42/2 يساوي 0، وبما أنّ الشّرط مُحقّق فقد طبعت الكلمة even وانتقل المُفسّر إلى الشّرط التّالي وهو التّحقّق من أن 42/2 يُساوي 21 وبما أنّه بدوره شرط مُحقّق أيضا فقد قام البرنامج طباعة الجملة 42/2 = 21 Is true وبعدها قام بطباعة الجملة Hello World لأنّها غير مُرتبطة بأي شرط. وبطبيعة الحال إذا لم يكن الشّرط الأول محقّقا، فلن ينتقل المُفسّر للشّرط التّالي ولن يقوم بأي شيء حتّى ولو كان الشّرط مُحقّقا. الحصول على قيم من مستخدم البرنامج يُمكن أن تطلب من المُستخدم أن يُدخل قيمة معيّنة، ثمّ تسند هذه القيمة إلى مُتغيّر في البرنامج، فمثلا لنقل بأنّك ترغب بالتّرحيب بالمُستخدم، أولا يجب أن تطلب منه أن يُدخل اسمه، بعدها تقوم بطباعة الجملة "Hello, Person"، بحيث تستبدل Person بالقيمة التّي أدخلها المُستخدم، انظر المثال: >>> person = raw_input('Enter your name: ') >>> 'Hello ', person إذا نفّذت البرنامج فسيكون المُخرج كالتّالي: Enter your name: وبعد إدخال اسمي والضّغط على مفتاح ENTER، فإنّ المُخرج سيكون كالتّالي: Hello Abdelhadi ما يحدث هو أن البرنامج يأخذ القيمة المُدخلة ويُسندها للمُتغيّر person وبعدها تستطيع أنت أن تطبع المُتغيّر للمُستخدم. تطبيق لنطبّق ما تعلّمناه ولننشئ برنامجا بسيطًا لجدولة مُقابلات العمل: سنطلب من المُستخدم توفير المعلومات التّاليّة: اسم المُتقدّم اسم المسؤول عن المُقابلة وقتُ المُقابلة وبعدها سنطبع جملة تحتوي على جميع المعلومات التّي قدّمها المُستخدم، افتح ملفّا باسم interview.py واكتب فيه التّالي: applicant = raw_input('Enter the applicant name: ') interviewer = raw_input('Enter the interviewer name: ') time = raw_input('Enter the appointment time: ') print interviewer, "will interview", applicant, "at", time في المثال أعلاه نطلب أولا من مُستخدم البرنامج أن يُدخل اسم المُتقدّم ثمّ تُسندُ القيمة إلى المتغيّر applicant، بعد ذلك يُطلب اسم المسؤول عن المُقابلة وتُسند قيمته إلى المُتغيّر interviewer وبعد ذلك نحصل على وقتُ المُقابلة من المُستخدم ونُسند القيمة إلى المُتغيّر time، وفي النّهاية نطبع الجملة الجامعة لكل المعلومات وتقديمها بشكل أسهل. جرّب الأمر بنفسك، وأسند القيّم التّي تريد، وانظر إلى النّتيجة، العب بالشّيفرة، أضف مميّزات أخرى كالتّحقّق من أن عُمر المُتقدّم أكبر من 18 عاما مثلا، وتذكّر بأنّ التعلّم بالتّطبيق أفضل من أي طريقة أخرى. تطبيق عملي: إنشاء برنامج تسجيل دخول بسيط الآن حان الوقت لنطبّق ما تعلّمناه، ولنقم بكتابة برنامج تسجيل دخول بسيط، ومبدأه كالتّالي: يُرحب البرنامج بالمُستخدم. يطلبُ منه معلومات التّسجيل. يفيد البرنامج المُستخدم بأنّ التّسجيل قد تم بنجاح أو بعكس ذلك. يطلب البرنامج معلومات الدّخول. يتحقّق البرنامج من أنّ المعلومات التّي أدخلها صحيحة. إذا كانت صحيحة، يطبع البرنامج رسالة نجاح. إذا كانت خاطئة، يطبع البرنامج رسالة فشل. المُتغيّرات التّي سنعتمد عليها: username: اسم المُستخدم password: كلمة المرور password_verification: تأكيد كلمة المرور (فقط للتّأكد من أنّ المُستخدم أدخل نفس كلمة المرور وأنّه يتذكّرها دون مشاكل). أولا جملة التّرحيب: print 'Hello User, this is a basic sign up/login Program' ثانيّا لنطلب من المُستخدم توفير قيّم المتغيرّات (username: اسم المُستخدم، password: كلمة المرور، password_verification: تأكيد كلمة المرور): username = raw_input('Enter your username please: ') password = raw_input('Enter the your password please: ') password_verification = raw_input('Verify password: ') الآن لنتحقق من أنّ كلمة المرور التّي أدخلها المستخدم في البداية هي نفسها التّي أدخلها عند تأكيد كلمة المرور وذلك بمقارنة المتغيّرين password و password_verification فإذا كانا يحملان نفس القيمة فهذا يعني بأنّ التّسجيل ناجح وسنطبع للمُستخدم جملة تفيد بأنّ عملية التّسجيل قد نجحت. أما إذا لم تكن القيم متساوية سنطبع جملة تفيد المستخدم بأنّ كلمة المرور وتأكيدها لا يتوافقان، ويمكن القيام بالأمر بالأسطر الآتية: if password == password_verification: print 'You have been successfully signed up!' else: print 'The password and the password verification don't match! Please try again' لقد انتهينا الآن من برمجة نظام التّسجيل، ويجب علينا الانتقال إلى الخطوة التّالية وهي مرحلة تسجيل الدّخول. بعد طباعة الجملة التّي تفيد بأنّ المستخدم قام بالتّسجيل بنجاح (انظر الشّيفرة أعلاه) سنطلب منه معلومات الولوج وذلك بإدخال اسم مُستخدمه وكلمة المرور، سنعيّن هذه القيم المدخلة حديثا إلى متغيّرين جديدين، وذلك لمقارنتهما مع قيم المتغيّرين القديمين، إذا كانت القيم توافق ما أدخله قبل قليل فسنطبع جملة تفيد بأنّ عمليّة الولوج قد نجحت، إذا لم يكن الأمر كذلك سنطبع جملة تفيد المستخدم بأنّ القيم التّي أدخلها خاطئة ثمّ يتوقّف البرنامج. الآن، لنطوّر الشّيفرة أعلاه وندخل عليها التّعديلات المطلوبة لإجراء عمليّة الولوج: if password == password_verification: print 'You have Successfully Signed up! \n' username_sign_in = raw_input('Enter your username please: ') password_sign_in = raw_input('Enter your password please: ') if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' else: print 'The password and the password verification do not match! Please try again' لاحظ استخدام المعامل المنطقي and عند التّحقّق من أنّ اسم المستخدم وكلمة المرور المدخلتان (المخزّنة في المتغيّرين username_sign_in و password_sign_in) توافقان ما تم إدخاله من قبل. العامل and يحرص على أنّ كلا الشّرطين محققان. وبهذا نكون قد انتهينا من البرمجية الصغيرة والبسيطة، وهذه هي الشّيفرة الكاملة: print 'Hello User, this is a basic sign up/login Program' username = raw_input('Enter your username please: ') password = raw_input('Enter the your password please: ') password_verification = raw_input('Verify password: ') if password == password_verification: print 'You have Successfully Signed up! \n' username_sign_in = raw_input('Enter your username please: ') password_sign_in = raw_input('Enter your password please: ') if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' else: print 'The password and the password verification do not match! Please try again' تمارين تمرين 1 ما مُخرجات البرنامج التّالي: print 2 < 3 and 3 > 1 print 2 < 3 or 3 > 1 print 2 < 3 or not 3 > 1 print 2 < 3 and not 3 > 1 تمرين 2 ما مُخرجات البرنامج التّالي: x = 4 y = 5 p = x < y or x < z print p تمرين 3 ما مُخرجات البرنامج التّالي: x = 4 y = 5 p = x < y or x < z print p تمرين 4 ماذا سيحدث بعد تنفيذ الشّيفرة التّالية، هل ستحدث أي أخطاء؟ علّل جوابك. x = 2 if x == 2: print x else: print y تمرين 5 ماذا سيحدث بعد تنفيذ الشّيفرة التّالية، هل ستحدث أي أخطاء؟ علّل جوابك. x = 2 if x == 2: print x else: x + تمرين 6 هل الإزاحة في البرنامج التّالي صحيحة؟ إذا لم يكن الأمر كذلك، فأصلح الخطأ. x = 2 if x == 2: print x if x+1 == 3: print 'x+1 = 3' else: print x + 2 مصادر درس Input and Output للكاتب Dr. Andrew N. Harrington. كتاب Python Practice Book لكاتبه Anand Chitipothu.