Uploaded by Omar Zakaria

python in arabic

advertisement
‫بايثون للجميع‬
‫التعامل مع البيانات باستخدام لغة بايثون ‪3‬‬
‫تأليف‪ :‬د‪ .‬تشارلز سيفيرنس‬
‫ترجمة‪ :‬منصة الكترونكس غو‬
‫منصة ‪ © Electronics Go‬النسخة األولى ‪2023‬‬
‫َ‬
‫هذا العمل مرخص بموجب رخصة املشاع اإلبداعي‪ :‬عزو العمل األصلي إلى املؤلف ‪ -‬غيرتجاري ‪-‬‬
‫إصدار العمل الجديد بموجب ترخيص مطابق للترخيص األصلي‬
‫مقدمة النسخة العربية‬
‫ً‬
‫انتشارا؛ وذلك لكونها‬
‫برزت لغة بايثون في السنوات األخيرة كإحدى أهم لغات البرمجة وأكثرها‬
‫ً َ‬
‫حاليا الخيار األنسب للمبتدئين لالنطالق في عالم البرمجة‪ ،‬باإلضافة لذلك‬
‫لغة سهلة التعلم‪ ،‬وتعد‬
‫فهي مناسبة لالستخدام في مختلف املجاالت ومنها تعلم اآللة وتحليل البيانات وتطوير الويب‪ .‬ومما‬
‫يساهم في تبني بايثون من قبل الكثيرين هو توفر دعم هائل ًّ‬
‫جدا في مجتمعات املبرمجين وامتالكها‬
‫مجموعة واسعة من املكتبات التي تختصر الكثير من التحديات وتسهل عمل املبرمجين‪.‬‬
‫إيمانا َّ‬
‫منا بأهمية تعلم بايثون َ‬
‫سعت منصة ‪ Electronics Go‬إلى إزالة حاجز اللغة من أمام العديد‬
‫ُ‬
‫اختيارنا على‬
‫من املهتمين العرب عبر ترجمة كتاب "‪ "Python for Everybody‬إلى العربية‪ ،‬وقد وقع‬
‫هذا الكتاب ‪-‬وهو من تأليف الدكتور تشارلز سيفيرنس من جامعة ميشيغان ‪ -‬لكونه من أهم الكتب‪،‬‬
‫ُّ‬
‫ويعد لبنة أساسية لكل باحث عن تعلم البرمجة بلغة بايثون مهما كان اختصاصه أو خلفيته العلمية‪.‬‬
‫ُترجم الكتاب إلى عدة لغات منها األملانية واإلسبانية‪ُ ،‬‬
‫واعتمد في عدة جامعات ومنصات تعليم كمرجع‬
‫َّ‬
‫أساس ي‪ .‬يتميز الكتاب بأسلوبه َّ‬
‫املبسط السلس‪ ،‬فلم يقدم الكاتب إال كل مختصر مفيد‪ ،‬وركز على‬
‫مفاهيم البرمجة تركيزا ً‬
‫َ‬
‫الكتاب لن تجد صعوبة في تعلم أية لغة برمجية أخرى‪.‬‬
‫عميقا؛ فبعد قراءتك‬
‫َ‬
‫مفاهيم أساسية كبنية الحاسوب ثم مفاهيم املتغيرات‪ ،‬يليها الشروط‬
‫الفصول العشر األولى تغطي‬
‫فالحلقات فالتعامل مع السالسل النصية‪ ،‬ثم ُبنى املعطيات كالقوائم والقواميس والصفوف‪ ،‬ثم‬
‫َّ‬
‫يشرح التوابع ودورها في البرنامج‪ .‬يتخلل كل فصل مجموعة كبيرة من التمارين العملية التي يمكنك‬
‫ً‬
‫تجربتها‪ ،‬ومع ُّ‬
‫تتدرج التمارين واألمثلة من البسيط َّ‬
‫تقدمك من فصل إلى فصل َّ‬
‫السهل إلى األكثر شموال‬
‫ُّ‬
‫وتقد ًما‪.‬‬
‫َّ‬
‫تركز الفصول‬
‫املتبقية على مفاهيم ذات أهمية في مجال علوم البيانات‪ ،‬كالتعابير النمطية والتعامل‬
‫مع تطبيقات عبر الشبكة‪ ،‬واستكشاف الويب‪ ،‬واستخدام الواجهات البرمجية لتطبيقات مختلفة‪،‬‬
‫ً‬
‫ويعرفك بالبرمجية الكائنية الت ُّ‬
‫وجه‪ ،‬ثم يخصص الكاتب فصال عن استخدام قواعد البيانات في‬
‫بايثون ً‬
‫وأخرا لتمثيل البيانات وعرضها‪.‬‬
‫ُ‬
‫هدفنا أن تكون هذه النسخة العربية نقطة انطالق للشباب َّ‬
‫الشغوف بالتعلم‪ ،‬وتكون َّ‬
‫مجرد بداية‬
‫ً‬
‫الطريق ملبرمجين سيحدثون فرقا في مجتمعاتهم والعالم‪.‬‬
‫حول منصة ‪Electronics Go‬‬
‫منصة تقنية تعليمية‪ ،‬انطلقت عام ‪ ،2016‬تعمل على تعزيز وتطوير املجتمع التقني الناطق بالعربية‬
‫من خالل تغطية أبرز ما توصل إليه العلم في مجاالت‪ :‬التحكم الصناعي‪ ،‬واألنظمة َ‬
‫املدمجة‪ ،‬وإنترنت‬
‫األشياء‪ ،‬باإلضافة إلى تقديم تدريبات مهنية تساهم في تطوير وتعزيز مهارات املهتمين في هذه املجاالت‪.‬‬
‫خدماتها‪:‬‬
‫• نشر محتوى علمي تخصص ي باللغة العربية‪.‬‬
‫• التنظيم واملشاركة في الفعاليات واملسابقات العلمية‪.‬‬
‫• تقديم التدريبات املهنية للمهتمين في هذه املجاالت‪.‬‬
‫• تقديم استشارات ودعم للمشاريع التقنية والصناعية‪.‬‬
‫• تجهيز املخابر التدريبية للمعاهد والجامعات‪.‬‬
‫يعمل في ‪ Electronics Go‬فريق من عدة دول عربية‪ ،‬ويمكن معرفة املزيد عن َّ‬
‫املنصة والخدمات التي‬
‫تقدمها عبر زيارة الرابط‪www.electronics-go.com :‬‬
‫املساهمون في النسخة العربية‪:‬‬
‫ الترجمة‪ :‬آالء محمد أغا‪ ،‬حنين غالية‪ ،‬سها أديب‪ ،‬قاهر اليتيم‪ ،‬قحطان غانم‪ ،‬لؤي ديب‪.‬‬‫ املراجعة‪ :‬سلمى الحافي‪ ،‬عبد الرحمن صابر‪ ،‬عدي ناصر‪ ،‬علي العلي‪.‬‬‫ التدقيق اللغوي‪ :‬حنين غالية‪ ،‬رنيم العلي‪ ،‬سالم أحمد‪ ،‬محمد بابكر‪.‬‬‫ التدقيق العلمي‪ :‬هزار غانم‪.‬‬‫ تصميم الغالف‪ :‬رؤى غانم‪.‬‬‫‪ -‬التحريرواإلشراف العام‪ :‬علي العلي‪.‬‬
‫اإلسهامات‬
‫التحرير‪ :‬إيليوت هوزير (‪ ،)Elliott Hauser‬وسو بلومينبيرغ (‪)Sue Blumenberg‬‬
‫تصميم الغالف‪ :‬إيمي أندريون (‪)Aimee Andrion‬‬
‫الطبعات‬
‫ الطبعة األولى الكاملة لإلصدار الثالث من لغة بايثون في ‪ 05‬تموز ‪ /‬يوليو ‪.2016‬‬‫‪ -‬الطبعة األولية للتحول إلى اإلصدار الثالث من لغة بايثون في ‪ 20‬كانون األول ‪ /‬ديسمبر ‪.2015‬‬
‫حقوق النشر‬
‫الحقوق محفوظة للدكتور تشارلز سيفيرنس ‪2009‬‬
‫العمل مرخص وفق رخصة املشاع اإلبداعي من النمط )استخدام غير تجاري ‪ -‬إصدار العمل الجديد‬
‫بموجب ترخيص مطابق للترخيص األصلي( اإلصدار الثالث‪.‬‬
‫ملعلومات حول الرخصة‪http://creativecommons.org/licenses/by-nc-sa/3.0/ :‬‬
‫استخداما ً‬
‫ً‬
‫تجاريا وغيره من االستثناءات في الرخصة‪ ،‬اطلع على امللحق ب‬
‫ملزيد حول ما يعتبره الكاتب‬
‫املعنون "حقوق النشر"‪.‬‬
‫املقدمة‬
‫يسعى املتخصصون األكاديميون ً‬
‫دوما لكتابة ونشر مؤلفات جديدة باملطلق‪ ،‬حيث يخضعون‬
‫لضغط‬
‫ٍ‬
‫َ‬
‫ً‬
‫اعتمادا على مؤلفات‬
‫ف‬
‫مستمر لنشر املؤلفات‪ .‬على عكس ذلك‪ ،‬كان هذا الكتاب تجربة كتابة ٌمؤل ٍ‬
‫أخرى‪ ،‬حيث عملنا على إعادة ترتيب كتاب "فكر بطريقة بايثون‪ :‬كيف تفكر كعالم حاسوب" ( ‪Think‬‬
‫كل من آلن دوني (‪)Allen B. Downey‬‬
‫‪ )Python: How to Think Like a Computer Scientist‬تأليف ٍ‬
‫وجيف أيلكنر (‪ ،)Jeff Elkner‬وآخرون‪.‬‬
‫في كانون األول‪/‬ديسمبر عام ‪ 2009‬كنت أجهز لتدريس مقرر برمجة الشبكات في جامعة ميشيغان‬
‫للفصل الخامس على التوالي‪ ،‬وقررت وقتها أنه حان الوقت املناسب لكتابة كتاب للغة بايثون والذي‬
‫ً‬
‫يركز على استكشاف البيانات بدال من فهم الخوارزميات واألفكار املجردة‪ ،‬وهدفي في املقرر هو‬
‫إكساب الطلبة مهارات التعامل مع البيانات باستخدام لغة بايثون مدى الحياة‪.‬‬
‫ً‬
‫لم يخطط العديد من طالبي ليصبحوا مبرمجين محترفين‪ ،‬بدال من ذلك خططوا ليصبحوا أمناء‬
‫مكتبات ومدراء ومحاميين وعلماء أحياء واقتصاديين‪ ،‬لكنهم رغبوا أن يستخدموا التكنولوجيا بمهارة‬
‫في مجال عملهم‪.‬‬
‫ٌ‬
‫لم يقع بين يدي ٌ‬
‫مخصص لتعليم التعامل مع البيانات باستخدام بايثون العتمده كمرجع‬
‫كتاب مثالي‬
‫في مقرري الدراس ي‪ ،‬لذلك شرعت في كتابة هذا الكتاب‪ ،‬ومن حسن الحظ أنه في إحدى اجتماعات‬
‫الكلية‪ ،‬وقبل ثالثة أسابيع من بدئي في تأليف الكتاب من الصفر في عطلة األعياد‪ ،‬عرض لي د‪.‬آتول‬
‫براكاش (‪ )Dr. Atul Prakash‬كتاب "فكر بطريقة بايثون" والذي اعتاد أن يدرس به طالبه خالل ذلك‬
‫الفصل‪ ،‬وهو كتاب صيغ بطريقة مناسبة لطالب علوم الحاسوب ليقدم املختصر املفيد الواضح‬
‫ويركز على تبسيط التعليم‪.‬‬
‫غيرنا ترتيب الكتاب بحيث يتعلم الطالب حل مشكالت تحليل البيانات بأسرع وسيلة ممكنة‪ ،‬فهو‬
‫يحوي على سلسلة من األمثلة العملية وعلى تمارين حول تحليل البيانات من الفصول األولى‪.‬‬
‫الفصول من ‪ 2‬إلى ‪ 10‬متشابهة مع كتاب "فكر بطريقة بايثون" مع إضافة تغيرات‪ ،‬حيث استبدلت‬
‫كل من األمثلة والتمارين املتعلقة بالحساب بتمارين متعلقة بالبيانات‪ ،‬واملحاور مرتبة بشكل مناسب‬
‫ً‬
‫لبناء حلول ملسائل تحليل البيانات األكثر تعقيدا‪.‬‬
‫نقلت بعض املحاور مثل بنية ‪ try/except‬إلى الفصل املتعلق بالبنى الشرطية‪ ،‬وطرحت التوابع بشكل‬
‫ً‬
‫مبسط في البداية إلى حين ظهرت الحاجة عند التعامل مع البرامج املعقدة بدال من طرحها كمحور‬
‫منفصل‪ .‬كما حذفنا أغلب التوابع املعرفة من قبل املستخدم من األمثلة والتمارين خارج نطاق‬
‫الفصل الرابع‪ ،‬ولم نتعامل مع االستدعاء الذاتي أو العودية (‪ )recursion‬في هذا الكتاب ً‬
‫مطلقا‪.‬‬
‫ٌ ُ‬
‫جديد ك ًليا ويركز على استخدامات واقعية وأمثلة‬
‫املحتوى في الفصل ‪ 1‬والفصول من ‪ 11‬إلى ‪16‬‬
‫بسيطة للغة بايثون في تحليل البيانات مثل التعابير النمطية في عمليات البحث والتحليل‪ ،‬وأتمتة‬
‫املهام على الحاسوب‪ ،‬واسترجاع البيانات عبر الشبكة‪ ،‬وتعقب صفحات الويب‪ ،‬والبرمجة كائنية‬
‫التوجه‪ ،‬واستخدام خدمات الويب‪ ،‬وتفسير بيانات ‪ XML‬و ‪ ،JSON‬وإنشاء واستخدام قواعد بيانات‬
‫باستخدام لغة االستعالمات البنيوية ‪ ،SQL‬وتمثيل البيانات (‪.)Visualization Data‬‬
‫ً‬
‫الهدف األساس ي من هذه التغييرات هو التحول من تعلم علم الحاسوب ً‬
‫مجردا إلى التركيز على‬
‫تعلما‬
‫التطبيقات املعلوماتية ولتضمين فقط املواضيع التي تفيد الطالب حتى إن لم يختر الفرد منهم أن‬
‫ً‬
‫ً‬
‫مبرمجا محترفا‪.‬‬
‫يصبح‬
‫أنصح الطالب الذين يستمتعون بقراءة هذا الكتاب ويريدون تعلم املزيد أن يقرؤوا كتاب "فكر‬
‫ً‬
‫بطريقة بايثون" ملؤلفه آلن دوني نظرا للتشابه بين الكتابين‪ ،‬فبذلك سيتعلم الطالب املهارات في نواحي‬
‫إضافية تم التطرق لها في ذلك الكتاب منها البرمجة التقنية والخوارزميات‪ ،‬وبما أن الكتابين متشابهين‬
‫من حيث األسلوب‪ ،‬سيتمكن الطالب من االطالع بسرعة وسالسة على األفكار في كتاب "فكر بطريقة‬
‫بايثون"‪.‬‬
‫منحني مؤلف الكتاب وصاحب حقوق النشر آلن اإلذن لتغيير رخصة الجزء املشابه لكتابه من‬
‫رخصة جي إن يو ‪ GNU‬إلى رخصة املشاع اإلبداعي األكثر حداثة وهي رخصة من النمط "إصدار العمل‬
‫الجديد بموجب ترخيص مطابق للترخيص األصلي "‪.‬‬
‫وهذا يتبع التحول العام في الرخص املفتوحة أي التحول من ‪ GFDL‬إلى ‪ CC-BY-SA‬مثل "ويكيبيديا"‪،‬‬
‫حيث يحافظ استخدام رخصة ‪ CC-BY-SA‬على ُعرف حقوق امللكية للكتاب ً‬
‫وأيضا يجعله مناسب‬
‫ُ‬
‫أكثر للكتاب الجدد إلعادة استخدام املادة كما يرغبون‪.‬‬
‫ً‬
‫أعتقد أن هذا الكتاب هو خير مثال على األهمية الكبيرة للمواد املشاعة في التعليم مستقبال‪ ،‬أود أن‬
‫أشكر آلن دوني ودار جامعة كامبريدج للنشر لقرارهم ذي النظرة البعيدة لجعل هذا الكتاب ً‬
‫متاحا‬
‫تحت حقوق ملكية مفتوحة‪ ،‬وأتمنى أن يكونوا راضيين عن ثمرة جهودي‪ .‬كما أتمنى لك‪ ،‬عزيزي‬
‫ً‬
‫اض عن هذه الجهود مجتمعة‪.‬‬
‫القارئ‪ ،‬أن تكون ر ٍ‬
‫أود أن أشكر آلن دوني ولورين كوليس (‪ (Lauren Cowles‬على مساعدتهم وصبرهم وإرشادهم في حل‬
‫أمور حقوق نشر هذا الكتاب‪.‬‬
‫تشارلز سيفيرنس (‪)Charles Severance‬‬
‫‪www.dr-chuck.com‬‬
‫مدينة أن أربور في والية ميشيغان في الواليات املتحدة األميركية‬
‫‪ 9‬أيلول‪ /‬سبتمبر ‪2013‬‬
‫األستاذ تشارلز سيفيرانس أستاذ في جامعة ميشيغان في كلية املعلوماتية‪.‬‬
‫الفهرس‬
‫ّ‬
‫البمجة؟ ‪2 .................................................................................................................‬‬
‫لماذا نتعلم ر‬
‫‪1‬‬
‫‪1.1‬‬
‫اإلبداع والحافز ‪3..........................................................................................................................‬‬
‫‪2.1‬‬
‫بنية الحاسوب ‪4...........................................................................................................................‬‬
‫‪3.1‬‬
‫البمجة ‪6.............................................................................................................................‬‬
‫فهم ر‬
‫ُ‬
‫مفردات بايثون وجملها ‪6................................................................................................................‬‬
‫‪5.1‬‬
‫مخاطبة بايثون ‪7..........................................................................................................................‬‬
‫ر‬
‫ِ‬
‫والمب ِجم ‪10.....................................................................................................................‬‬
‫المفّس‬
‫‪7.1‬‬
‫كتابة برنامج ‪12...........................................................................................................................‬‬
‫‪8.1‬‬
‫البنامج؟ ‪12.......................................................................................................................‬‬
‫ما هو ر‬
‫ّ‬
‫ّ‬
‫للبامج ‪14.........................................................................................................‬‬
‫المكونات األساسية ر‬
‫ما األخطاء ر‬
‫الت يمكن أن نواجهها؟ ‪15.................................................................................................‬‬
‫‪4.1‬‬
‫‪6.1‬‬
‫‪9.1‬‬
‫‪10.1‬‬
‫‪11.1‬‬
‫التنقيح ‪16..................................................................................................................................‬‬
‫ّ‬
‫رحلة التعلم ‪18............................................................................................................................‬‬
‫‪13.1‬‬
‫فهرس المصطلحات‪18..................................................................................................................‬‬
‫‪14.1‬‬
‫تمارين ‪20...................................................................................................................................‬‬
‫‪12.1‬‬
‫ر‬
‫والتعابب والتعليمات ‪23 ...................................................................................................‬‬
‫المتغبات‬
‫ّ‬
‫ّ‬
‫‪2‬‬
‫‪1.2‬‬
‫القيم وأنواع البيانات ‪23.................................................................................................................‬‬
‫ّ‬
‫المتغبات ‪24..............................................................................................................................‬‬
‫ّ‬
‫ّ‬
‫ّ‬
‫المتغبات والكلمات المفتاحية ‪25.............................................................................................‬‬
‫أسماء‬
‫ّ‬
‫‪4.2‬‬
‫التعليمات ‪26..............................................................................................................................‬‬
‫‪5.2‬‬
‫العوامل والمعامالت ‪27.................................................................................................................‬‬
‫‪6.2‬‬
‫التعابب ‪28..................................................................................................................................‬‬
‫ّ‬
‫ّ‬
‫تر ّ‬
‫العمليات ‪28.......................................................................................................................‬‬
‫اتبية‬
‫‪8.2‬‬
‫عامل ر‬
‫باق القسمة ‪29.....................................................................................................................‬‬
‫العمليات عىل السالسل ّ‬
‫ّ‬
‫النص ّية ‪30....................................................................................................‬‬
‫‪10.2‬‬
‫إدخال البيانات من المستخدم ‪30.....................................................................................................‬‬
‫‪11.2‬‬
‫التعليقات ‪31..............................................................................................................................‬‬
‫ّ‬
‫اختيار أسماء ّ‬
‫متغبات سهلة التذكر ‪32...............................................................................................‬‬
‫ّ‬
‫‪13.2‬‬
‫التنقيح ‪34..................................................................................................................................‬‬
‫‪14.2‬‬
‫فهرس المصطلحات‪35..................................................................................................................‬‬
‫‪15.2‬‬
‫تمارين ‪37...................................................................................................................................‬‬
‫‪2.2‬‬
‫‪3.2‬‬
‫‪7.2‬‬
‫‪9.2‬‬
‫‪12.2‬‬
‫ّر‬
‫ر‬
‫الش ر‬
‫ط ‪39 ......................................................................................................................‬‬
‫التنفيذ‬
‫‪3‬‬
‫‪1.3‬‬
‫ّ‬
‫ّ‬
‫المنطقية ‪39.....................................................................................................................‬‬
‫عابب‬
‫الت ّ‬
‫‪2.3‬‬
‫ّ‬
‫المنطقية ‪40.....................................................................................................................‬‬
‫العوامل‬
‫ّ‬
‫ر‬
‫التنفيذ المّسوط ‪40.....................................................................................................................‬‬
‫ّ‬
‫التنفيذ البديل ‪42.........................................................................................................................‬‬
‫رّ‬
‫الّسوط المتسلسلة ‪43..................................................................................................................‬‬
‫رّ‬
‫الّسوط المتداخلة‪45....................................................................................................................‬‬
‫ّ‬
‫التعامل مع االستثناء باستخدام بنية ‪ TRY‬و‪46............................................................................ EXCEPT‬‬
‫ّ ُّ‬
‫ّ‬
‫ّ‬
‫المنطقية ‪49..............................................................................................‬‬
‫عابب‬
‫تجاوز التحقق من الت ّ‬
‫ّ‬
‫التنقيح ‪51..................................................................................................................................‬‬
‫‪10.3‬‬
‫فهرس المصطلحات‪51..................................................................................................................‬‬
‫‪11.3‬‬
‫تمارين ‪53...................................................................................................................................‬‬
‫‪3.3‬‬
‫‪4.3‬‬
‫‪5.3‬‬
‫‪6.3‬‬
‫‪7.3‬‬
‫‪8.3‬‬
‫‪9.3‬‬
‫التوابع ‪56 .................................................................................................................................‬‬
‫‪4‬‬
‫‪1.4‬‬
‫استدعاء التوابع ‪56.......................................................................................................................‬‬
‫‪2.4‬‬
‫التوابع الجاهزة ‪56........................................................................................................................‬‬
‫‪3.4‬‬
‫توابع تحويل النوع ‪57....................................................................................................................‬‬
‫ّ‬
‫الرياضية ‪58.......................................................................................................................‬‬
‫التوابع‬
‫‪5.4‬‬
‫ّ‬
‫العشوائية ‪59.....................................................................................................................‬‬
‫األعداد‬
‫‪6.4‬‬
‫إضافة توابع جديدة ‪61..................................................................................................................‬‬
‫‪7.4‬‬
‫التعاريف واستخداماتها ‪63..............................................................................................................‬‬
‫‪8.4‬‬
‫تسلسل التنفيذ ‪64........................................................................................................................‬‬
‫ُ‬
‫المعامالت والوسائط ‪64................................................................................................................‬‬
‫‪10.4‬‬
‫التوابع ُ‬
‫المنتجة والتوابع الخالية ‪66....................................................................................................‬‬
‫‪11.4‬‬
‫لماذا نستخدم التوابع ‪67................................................................................................................‬‬
‫ّ‬
‫التنقيح ‪68..................................................................................................................................‬‬
‫‪13.4‬‬
‫فهرس المصطلحات‪69..................................................................................................................‬‬
‫‪14.4‬‬
‫تمارين ‪70...................................................................................................................................‬‬
‫‪4.4‬‬
‫‪9.4‬‬
‫‪12.4‬‬
‫التكرار ‪74 .................................................................................................................................‬‬
‫‪5‬‬
‫‪1.5‬‬
‫المتغبات‪74...............................................................................................................‬‬
‫تحديث قيم‬
‫ّ‬
‫‪2.5‬‬
‫حلقة ‪74........................................................................................................................... WHILE‬‬
‫‪3.5‬‬
‫الحلقات الالنهائية ‪75....................................................................................................................‬‬
‫‪4.5‬‬
‫إنهاء التكرار باستخدام تعليمة ‪77....................................................................................... CONTINUE‬‬
‫‪5.5‬‬
‫الحلقات المحددة باستخدام ‪78.................................................................................................FOR‬‬
‫‪6.5‬‬
‫أنماط كتابة الحلقات ‪79................................................................................................................‬‬
‫‪1.6.5‬‬
‫حلقات العد والجمع ‪80...........................................................................................................‬‬
‫‪2.6.5‬‬
‫الكبى والصغرى ‪81.......................................................................................‬‬
‫حلقات إيجاد القيم ر‬
‫‪7.5‬‬
‫التنقيح ‪83..................................................................................................................................‬‬
‫‪8.5‬‬
‫فهرس المصطلحات‪83..................................................................................................................‬‬
‫‪9.5‬‬
‫تمارين ‪84...................................................................................................................................‬‬
‫السالسل النصية ‪86 ....................................................................................................................‬‬
‫‪6‬‬
‫‪1.6‬‬
‫السلسلة النصية ه سلسلة من المحارف ‪86........................................................................................‬‬
‫‪2.6‬‬
‫الحصول عىل طول السلسلة النصية باستخدام التابع ‪87.................................................................... LEN‬‬
‫‪3.6‬‬
‫التعامل مع محارف السلسة النصية باستخدام الحلقات ‪88......................................................................‬‬
‫‪4.6‬‬
‫تجزئة السالسل النصية ‪89..............................................................................................................‬‬
‫‪5.6‬‬
‫غب قابلة للتعديل ‪90...............................................................................................‬‬
‫السالسل النصية ّ‬
‫ّ‬
‫استخدام الحلقات والعد ‪90............................................................................................................‬‬
‫‪7.6‬‬
‫العامل ‪91............................................................................................................................... IN‬‬
‫‪8.6‬‬
‫مقارنة السالسل النصية ‪91.............................................................................................................‬‬
‫‪9.6‬‬
‫توابع السالسل النصية ‪92...............................................................................................................‬‬
‫‪10.6‬‬
‫تحليل السالسل النصية ‪95.............................................................................................................‬‬
‫‪11.6‬‬
‫عامل التنسيق ‪96.........................................................................................................................‬‬
‫‪12.6‬‬
‫التنقيح ‪97..................................................................................................................................‬‬
‫‪13.6‬‬
‫فهرس المصطلحات‪99..................................................................................................................‬‬
‫‪14.6‬‬
‫تمارين ‪100.................................................................................................................................‬‬
‫‪6.6‬‬
‫الملفات ‪102 .............................................................................................................................‬‬
‫ِ‬
‫‪7‬‬
‫‪1.7‬‬
‫اإلرصار عىل التعلم ‪102..................................................................................................................‬‬
‫‪2.7‬‬
‫الملفات ‪103.........................................................................................................................‬‬
‫فتح ِ‬
‫‪3.7‬‬
‫ِملفات النصوص واألسطر ‪104........................................................................................................‬‬
‫‪4.7‬‬
‫الملفات ‪105........................................................................................................................‬‬
‫قراءة ِ‬
‫‪5.7‬‬
‫البحث خالل ِملف ‪107.................................................................................................................‬‬
‫‪6.7‬‬
‫الملف ‪110..............................................................................................‬‬
‫السماح للمستخدم باختيار ِ‬
‫‪7.7‬‬
‫استخدام ‪ TRY‬و‪ EXCEPT‬و‪111.................................................................................................. OPEN‬‬
‫‪8.7‬‬
‫الملفات ‪113.......................................................................................................................‬‬
‫كتابة ِ‬
‫‪9.7‬‬
‫التنقيح ‪114................................................................................................................................‬‬
‫‪10.7‬‬
‫فهرس المصطلحات‪115................................................................................................................‬‬
‫‪11.7‬‬
‫تمارين ‪116.................................................................................................................................‬‬
‫القوائم ‪119 ..............................................................................................................................‬‬
‫‪8‬‬
‫‪1.8‬‬
‫القائمة ه سلسلة ‪119..................................................................................................................‬‬
‫‪2.8‬‬
‫القوائم قابلة للتعديل ‪119..............................................................................................................‬‬
‫‪3.8‬‬
‫المرور عىل عنارص قائمة ‪121..........................................................................................................‬‬
‫ّ‬
‫العمليات عىل القوائم ‪122..............................................................................................................‬‬
‫‪5.8‬‬
‫تجزئة القوائم ‪122........................................................................................................................‬‬
‫توابع ّ‬
‫خاصة بالقوائم ‪123...............................................................................................................‬‬
‫‪7.8‬‬
‫حذف العنارص ‪124......................................................................................................................‬‬
‫‪8.8‬‬
‫القوائم والتوابع‪125......................................................................................................................‬‬
‫‪4.8‬‬
‫‪6.8‬‬
‫‪9.8‬‬
‫القوائم والسالسل ّ‬
‫النص ّية ‪127.........................................................................................................‬‬
‫‪10.8‬‬
‫التعامل مع األسطر ق الملفات ‪128..................................................................................................‬‬
‫َ‬
‫والقيم ‪129......................................................................................................................‬‬
‫الكائنات‬
‫‪12.8‬‬
‫التسمية البديلة ‪131.....................................................................................................................‬‬
‫‪13.8‬‬
‫وسائط القائمة ‪131......................................................................................................................‬‬
‫‪14.8‬‬
‫التنقيح ‪133................................................................................................................................‬‬
‫‪15.8‬‬
‫فهرس المصطلحات‪138................................................................................................................‬‬
‫‪16.8‬‬
‫تمارين ‪139.................................................................................................................................‬‬
‫‪11.8‬‬
‫القواميس ‪143 ...........................................................................................................................‬‬
‫‪9‬‬
‫‪1.9‬‬
‫استخدام القواميس ق العد ‪145.......................................................................................................‬‬
‫‪2.9‬‬
‫القواميس والملفات ‪147................................................................................................................‬‬
‫‪3.9‬‬
‫الحلقات والقواميس ‪149...............................................................................................................‬‬
‫‪4.9‬‬
‫التعامل مع النصوص ‪150...............................................................................................................‬‬
‫‪5.9‬‬
‫التنقيح ‪152................................................................................................................................‬‬
‫‪6.9‬‬
‫فهرس المصطلحات‪153................................................................................................................‬‬
‫‪7.9‬‬
‫تمارين‪154................................................................................................................................ :‬‬
‫الصفوف ‪157 ............................................................................................................................‬‬
‫‪10‬‬
‫‪1.10‬‬
‫غب قابلة للتعديل ‪157......................................................................................................‬‬
‫الصفوف ّ‬
‫‪2.10‬‬
‫مقارنة الصفوف ‪159.....................................................................................................................‬‬
‫‪3.10‬‬
‫إسناد الصفوف ‪160......................................................................................................................‬‬
‫‪4.10‬‬
‫القواميس والصفوف ‪162...............................................................................................................‬‬
‫‪5.10‬‬
‫اإلسناد المتعدد مع القواميس ‪163....................................................................................................‬‬
‫الكلمات األكب تكر ًارا ‪164...............................................................................................................‬‬
‫‪7.10‬‬
‫استخدام الصفوف كمفاتيح ضمن القواميس ‪166..................................................................................‬‬
‫‪8.10‬‬
‫السالسل‪ :‬النصوص والقوائم والصفوف ‪166.......................................................................................‬‬
‫‪9.10‬‬
‫التنقيح ‪167................................................................................................................................‬‬
‫‪10.10‬‬
‫فهرس المصطلحات‪167................................................................................................................‬‬
‫‪11.10‬‬
‫تمارين ‪168.................................................................................................................................‬‬
‫‪6.10‬‬
‫التعابب النمطية ‪172 ...................................................................................................................‬‬
‫ّ‬
‫‪11‬‬
‫‪1.11‬‬
‫التعابب النمطية ‪173............................................................................................‬‬
‫مطابقة المحارف ق‬
‫ّ‬
‫‪2.11‬‬
‫التعابب النمطية ‪175.................................................................................‬‬
‫استخراج البيانات باستخدام‬
‫ّ‬
‫‪3.11‬‬
‫ر‬
‫عمليت البحث واالستخراج معا ‪178..........................................................................................‬‬
‫تنفيذ‬
‫‪4.11‬‬
‫محرف الهروب ‪183......................................................................................................................‬‬
‫‪5.11‬‬
‫ملخص ‪184...............................................................................................................................‬‬
‫‪6.11‬‬
‫معلومات إضافية لمستخدم نظام ‪ UNIX‬و ‪185......................................................................... LINUX‬‬
‫‪7.11‬‬
‫التنقيح ‪186................................................................................................................................‬‬
‫‪8.11‬‬
‫فهرس المصطلحات‪187................................................................................................................‬‬
‫‪9.11‬‬
‫تمارين ‪187.................................................................................................................................‬‬
‫البامج المرتبطة بالشبكات ‪190 ......................................................................................................‬‬
‫ر‬
‫‪12‬‬
‫‪1.12‬‬
‫ّ‬
‫التشع رت ‪190............................................................................................. HTTP‬‬
‫برتوكول نقل النص‬
‫ّ‬
‫ُمتصفح الويب األبسط ق العالم ‪191.................................................................................................‬‬
‫‪3.12‬‬
‫استعادة صورة عن طريق بروتوكول ‪194.................................................................................... HTTP‬‬
‫‪4.12‬‬
‫استعادة صفحات الويب باستخدام مكتبة ‪198........................................................................... URLLIB‬‬
‫ُ ّ‬
‫شفرة ً‬
‫ثنائيا باستخدام ‪199............................................................................... URLLIB‬‬
‫قراءة الملفات الم‬
‫‪6.12‬‬
‫تحليل واستخراج البيانات من صفحات ‪201.............................................................................. HTML‬‬
‫‪7.12‬‬
‫التعابب النمطية ‪201.........................................................................‬‬
‫تحليل صفحات ‪ HTML‬باستخدام‬
‫ّ‬
‫‪8.12‬‬
‫تحليل صفحات ‪ HTML‬باستخدام مكتبة ‪204.............................................................. BEAUTIFULSOUP‬‬
‫ُ‬
‫مبات خاصة ُ‬
‫لمستخدم أنظمة لينكس أو يونيكس‪209..........................................................................‬‬
‫ّ‬
‫‪10.12‬‬
‫فهرس المصطلحات‪209................................................................................................................‬‬
‫‪11.12‬‬
‫تمارين ‪210.................................................................................................................................‬‬
‫‪2.12‬‬
‫‪5.12‬‬
‫‪9.12‬‬
‫استخدام خدمات الويب‪213 .........................................................................................................‬‬
‫‪13‬‬
‫‪1.13‬‬
‫لغة التوصيف الموسعة ‪213.................................................................................................... XML‬‬
‫‪2.13‬‬
‫تحليل نصوص ‪214.............................................................................................................. XML‬‬
‫‪3.13‬‬
‫استخدام الحلقات للمرور عىل العقد ‪215...........................................................................................‬‬
‫‪4.13‬‬
‫‪217................................................................................................................................ JSON‬‬
‫‪5.13‬‬
‫تحليل نصوص ‪218............................................................................................................. JSON‬‬
‫‪6.13‬‬
‫واجهات برمجة التطبيقات‪219........................................................................................................‬‬
‫‪7.13‬‬
‫األمان واستخدام واجهات برمجة التطبيقات ‪221..................................................................................‬‬
‫‪8.13‬‬
‫فهرس المصطلحات‪221................................................................................................................‬‬
‫ر‬
‫مب الجغراق من غوغل‪222............................................................................ :‬‬
‫التطبيق األول‪ :‬خدمة الب ّ‬
‫التطبيق الثان‪ :‬ر‬
‫تويب ‪227................................................................................................................‬‬
‫‪9.13‬‬
‫‪10.13‬‬
‫البمجة الكائنية التوجه ‪235 ..........................................................................................................‬‬
‫ر‬
‫‪14‬‬
‫‪1.14‬‬
‫الكببة ‪235.................................................................................................................‬‬
‫البامج ّ‬
‫إدارة ر‬
‫‪2.14‬‬
‫مقدمة ‪235................................................................................................................................‬‬
‫‪3.14‬‬
‫استخدام الكائنات ‪236..................................................................................................................‬‬
‫‪4.14‬‬
‫البامج ‪237.....................................................................................................................‬‬
‫البدء مع ر‬
‫‪5.14‬‬
‫تقسيم المشكلة ‪239.....................................................................................................................‬‬
‫‪6.14‬‬
‫إنشاء كائن ق لغة بايثون ‪240...........................................................................................................‬‬
‫‪7.14‬‬
‫الصنف كنوع بيانات ‪243...............................................................................................................‬‬
‫‪8.14‬‬
‫دورة حياة الكائن‪244.....................................................................................................................‬‬
‫‪9.14‬‬
‫تعدد الكائنات ‪245.......................................................................................................................‬‬
‫‪10.14‬‬
‫الوراثة ‪247.................................................................................................................................‬‬
‫‪11.14‬‬
‫ملخص ‪248...............................................................................................................................‬‬
‫‪12.14‬‬
‫فهرس المصطلحات‪249................................................................................................................‬‬
‫استخدام قواعد البيانات ولغة ‪252 ........................................................................................... SQL‬‬
‫‪15‬‬
‫‪1.15‬‬
‫ما ه قاعدة البيانات؟ ‪252.............................................................................................................‬‬
‫‪2.15‬‬
‫مفاهيم ق قواعد البيانات ‪252.........................................................................................................‬‬
‫‪3.15‬‬
‫متصفح قاعدة البيانات ق‪253.............................................................................................. SQLITE‬‬
‫‪4.15‬‬
‫إنشاء جدول قاعدة بيانات ‪253........................................................................................................‬‬
‫ّ‬
‫البنيوية ‪257........................................................................................SQL‬‬
‫ملخص عن لغة االستعالم‬
‫‪6.15‬‬
‫استكشاف ر‬
‫تويب باستخدام قواعد البيانات ‪258....................................................................................‬‬
‫‪7.15‬‬
‫نمذجة البيانات ‪266.....................................................................................................................‬‬
‫‪8.15‬‬
‫برمجة قاعدة البيانات ذات الجداول المتعددة ‪268................................................................................‬‬
‫‪5.15‬‬
‫‪1.8.15‬‬
‫القيود ق قواعد البيانات‪273.....................................................................................................‬‬
‫‪2.8.15‬‬
‫استعادة أو إضافة سجل ق قاعدة البيانات ‪274..............................................................................‬‬
‫تخزين عالقة الصداقة ّبي مستخدم ر‬
‫تويب ‪275.............................................................................‬‬
‫‪3.8.15‬‬
‫‪9.15‬‬
‫أنواع المفاتيح الثالثة ‪277...............................................................................................................‬‬
‫‪10.15‬‬
‫استخدام عبارة ‪ JOIN‬الستعادة البيانات ‪277.......................................................................................‬‬
‫‪11.15‬‬
‫الملخص ‪281..............................................................................................................................‬‬
‫‪12.15‬‬
‫التنقيح ‪281................................................................................................................................‬‬
‫‪13.15‬‬
‫فهرس المصطلحات‪282................................................................................................................‬‬
‫ر‬
‫المرئ للبيانات ‪285 ...........................................................................................................‬‬
‫العرض‬
‫‪16‬‬
‫‪1.16‬‬
‫عرض خريطة باستخدام بيانات جغر ّ‬
‫افية من غوغل ‪285..........................................................................‬‬
‫‪2.16‬‬
‫ّ‬
‫المرن للشبكات واالرتباطات‪288............................................................................................‬‬
‫العرض‬
‫ر‬
‫البيد اإللكب ّ‬
‫ون ‪293............................................................................‬‬
‫تحليل وعرض البيانات الواردة ق ر‬
‫‪3.16‬‬
‫الفصل األول‬
‫ملاذا نتعلم البرمجة؟‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪2‬‬
‫ّ‬
‫‪ 1‬ملاذا نتعلم البرمجة؟‬
‫ُّ‬
‫البرمجة نشاط ممتع‪ ،‬وعملية إبداعية مذهلة‪ .‬تختلف األسباب التي تدفع الناس لتعلم البرمجة‪،‬‬
‫فمنهم من يتعلمها لكسب الرزق‪ ،‬أو لتحليل البيانات املعقدة‪ ،‬أو للتطوع لحل مشكالت اآلخرين‪ ،‬أو‬
‫حتى للتسلية‪.‬‬
‫بحاجة إلى تعلم البرمجة حتى إن لم ندرك الغاية منها في البداية‪ ،‬فنحن نعيش اليوم في‬
‫أن الجميع‬
‫ٍ‬
‫عالم مليء باألجهزة الحاسوبية‪ ،‬مثل الحواسيب املحمولة والهواتف الذكية‪ ،‬وهي رهن إشارتنا‪ ،‬وكأن‬
‫ُ‬
‫هذا العتاد الصلب قد ُ‬
‫صم َم خص ً‬
‫يصا ليقول لنا‪" :‬رغباتك أوامر"‪.‬‬
‫ما األمر‬
‫التالي؟‬
‫ما األمر‬
‫التالي؟‬
‫ما األمر‬
‫التالي؟‬
‫ما األمر‬
‫التالي؟‬
‫ما األمر‬
‫التالي؟‬
‫ما األمر‬
‫التالي؟‬
‫الشكل ‪ :1‬املساعد الشخص ي الرقمي‬
‫مساعد‬
‫يزود املبرمجون هذا العتاد بنظام تشغيل ومجموعة من التطبيقات‪ ،‬فنحصل بذلك على‬
‫ٍ‬
‫قادر على مساعدتنا في تأدية مختلف املهام‪.‬‬
‫رقمي ٍ‬
‫شخص ٍي ٍ‬
‫ُ‬
‫حواسيبنا اليوم سريعة‪ ،‬ولها ذاكرة بحجم كبير‪ ،‬ويمكن أن تساعدنا في أداء مهامنا الكثيرة واملتكررة‬
‫إذا ما حدثناها بلغتها‪ ،‬فهي قادرة على إنجاز املهام التي يعتبرها البشر ممل ٍة للغاية‪ .‬على سبيل املثال‪،‬‬
‫ٌ‬
‫صحيح‬
‫اقرأ أول مقطعين من هذا الفصل‪ ،‬واستخرج الكلمة األكثر تكر ًارا‪ ،‬مع ذكر عدد مرات تكرارها‪.‬‬
‫َّ‬
‫تتمكن من قراءة وفهم هذه الكلمات بسرعة كبيرة‪ ،‬إال أن َّ‬
‫عدها مزعج لدماغك الذي لم يصمم‬
‫أنك س‬
‫ً‬
‫ُ‬
‫ً‬
‫لحل مثل هذه املسائل‪ ،‬خالفا للحواسيب التي ت َع ُّد القراءة والفهم عملية صعبة عليها‪ ،‬إال أنها تستطيع‬
‫ُ‬
‫بسهولة أن تعد مرات تكرار كلمة ما‪ ،‬وتظهر الكلمة األكثر تكر ًارا‪:‬‬
‫‪python words.py‬‬
‫‪Enter file: words.txt‬‬
‫‪to 16‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪3‬‬
‫َ‬
‫أخبرنا مساعدنا املخلص بكل سهولة أن الكلمة "‪ "to‬تكررت ست عشرة مرة في أول ثالث فقرات في‬
‫ً‬
‫حافزا لك لتعلم لغة الحاسوب‪ ،‬فهي مناسبة لتأدية‬
‫امللف ‪ .word.txt‬أتمنى أن تجد في هذا املثال‬
‫املهام الصعبة واململة بالنسبة للبشر‪ ،‬مما يوفر لك الوقت والجهد الذي تحتاجه للتفكير واإلبداع‪.‬‬
‫‪ 1.1‬اإلبداع والحافز‬
‫هذا الكتاب ليس َّ‬
‫موج ًها للمبرمجين املحترفين‪ ،‬مع العلم أن البرمجة االحترافية تعود بالنفع على‬
‫ًّ‬
‫صاحبها‪ ،‬سواء ًّ‬
‫شخصيا‪ ،‬فبناء برامج ذكية ومفيدة هو نشاط إبداعي بامتياز‪ .‬يحتوي‬
‫ماليا أو‬
‫ً‬
‫عادة‪ ،‬أو ُ‬
‫لنقل املساعد الشخص ي الرقمي )‪ ،PDA (Personal Digital Assistant‬على برامج‬
‫الحاسوب‬
‫متنوعة صممها مبرمجون مختلفون‪ ،‬وتتنافس فيما بينها للحصول على انتباهنا واهتمامنا لتلبية‬
‫ً‬
‫ً‬
‫وعادة ما َّ‬
‫يتربح هؤالء املبرمجون مباشرة عند استخدامك لبرامجهم‪.‬‬
‫احتياجاتنا وتوفير تجربة رائعة‪،‬‬
‫وإن عرفنا البرامج بأنها نتاج إبداع عدة مبرمجين‪ ،‬فيمكننا أن نتخيل مساعدنا الشخص ي كاآلتي‪:‬‬
‫اخترني‬
‫اخترني‬
‫اخترني‬
‫اشتري‬
‫خدمتي‬
‫اخترني‬
‫اخترني‬
‫الشكل ‪ :2‬كيف يخاطب املبرمجون املستخدم عبر تطبيقاتهم‬
‫فليكن دافعنا ًّ‬
‫حاليا أن نتعامل مع البيانات واملعلومات التي نواجهها في حياتنا بفاعلية أكبر‪ُ ،‬‬
‫ولنترك‬
‫فكرة كسب املال أو إرضاء املستخدمين ً‬
‫جانبا‪ ،‬ففي البداية ستكون املبرمج واملستخدم في ٍآن واحد‪،‬‬
‫ُ‬
‫وبمرور الوقت‪ ،‬ستكتسب مهارات أكثر‪ ،‬وستصبح البرمجة عملية ممتعة‪ ،‬حينها يمكنك تطوير‬
‫البرامج لآلخرين ومساعدتهم‪.‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪4‬‬
‫‪ 2.1‬بنية الحاسوب‬
‫ً‬
‫نحتاج أوال إلى معرفة مكونات الحاسوب نفسه قبل البدء بتعلم اللغة التي تسمح لنا بإعطاء األوامر‬
‫والتعليمات له‪ ،‬فإذا فككت ً‬
‫ً‬
‫حاسوبا‪ ،‬ستجد فيه العناصر اآلتية‪:‬‬
‫هاتفا أو‬
‫ما األمر التالي؟‬
‫الشبكة‬
‫البرمجيات‬
‫وحدة املعالجة املركزية‬
‫الذاكرة الثانوية‬
‫أجهزة الدخل والخرج‬
‫الذاكرة الرئيسية‬
‫الشكل ‪ :3‬بنية الحاسوب‬
‫ُ‬
‫فلنتناول ك َّل عنصر باختصار‪:‬‬
‫ّ‬
‫املركزية (أو املعالج) ‪ :CPU‬هذا الجزء مسؤول خص ً‬
‫يصا عن سؤال "ماذا‬
‫• وحدة املعالجة‬
‫ُ‬
‫أنفذ؟"‪ ،‬وإذا كانت سرعة معالج الجهاز ‪ 3‬جيجا هرتز‪ ،‬فسيتساءل ثالثة مليارات مرة في‬
‫ُّ‬
‫الثانية عن املهمة التالية‪ ،‬لذلك يجب تعلم كيفية التواصل مع وحدة املعالجة املركزية‬
‫بسرعة كبيرة‪.‬‬
‫ّ ُ‬
‫الرئيسية‪ :‬تستخدم لتخزين املعلومات التي يحتاج أن يصل إليها املعالج بسرعة‪،‬‬
‫• الذاكرة‬
‫لذا فسرعتها تقارب سرعة املعالج‪ ،‬إال أن املعلومات تزول منها عند إطفاء تشغيل الحاسب‪.‬‬
‫الثانوية‪ُ :‬تستخدم ً‬
‫ّ‬
‫أيضا لتخزين املعلومات‪ ،‬إال أنها أبطأ بكثير من الذاكرة‬
‫• الذاكرة‬
‫الرئيسية‪ ،‬وتبرز فائدتها في قدرتها على تخزين املعلومات حتى عند عدم تشغيل الحاسب‪.‬‬
‫ومنها‪ :‬أقراص التخزين أو الذاكرة الومضية )‪ (flash memory‬املوجودة في وحدات تخزين‬
‫متنقلة ‪ USB‬ومشغالت املوسيقى املحمولة‪.‬‬
‫• أجهزة اإلدخال واإلخراج‪ :‬كالشاشة‪ ،‬ولوحة املفاتيح‪ ،‬والفأرة‪ ،‬وامليكروفون‪ ،‬ومكبر‬
‫الصوت‪ ،‬ولوحة اللمس‪ ،‬وغيرها من األجهزة التي تساعدنا في التفاعل مع الحاسب‪.‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪5‬‬
‫ً‬
‫ًّ‬
‫• تملك معظم الحواسيب ًّ‬
‫شبكيا لتبادل البيانات عبر الشبكة‪ .‬يمكن اعتبار‬
‫حاليا اتصاال‬
‫مكانا ً‬
‫هذه الشبكة ً‬
‫بطيئا ًّ‬
‫جدا في تخزين وتبادل البيانات الفائضة‪ ،‬وبذلك قد تعمل الشبكة‬
‫كذاكرة ثانوية‪ ،‬ولكن بصورة أبطأ وأقل ً‬
‫أمانا من الذاكرة الثانوية‪.‬‬
‫تلك كانت نبذة عن مختلف عناصر الحاسب التي ستساعدنا عند كتابتنا للبرامج في الفصول التالية‪،‬‬
‫إال أننا لم نشغل بالنا بتفاصيل آلية عمل هذه العناصر‪ ،‬وتركنا ذلك ملصممي الحواسيب‪ ،‬فوظيفتك‬
‫كمبرمج تتمثل في استخدام أجزاء الحاسوب املختلفة‪ ،‬والتنسيق بينها لحل املشكلة املطروحة‪،‬‬
‫وتحليل البيانات الناتجة عن هذا الحل‪ً .‬‬
‫غالبا ما ستتعامل مع املعالج بإعطائه أوامر معينة لتأدية‬
‫املهام التي تريدها‪ ،‬كاستخدام الذاكرة الرئيسية‪ ،‬أو الثانوية‪ ،‬أو الشبكة‪ ،‬أو أجهزة اإلدخال واإلخراج‪.‬‬
‫ما األمر التالي؟‬
‫الشبكة‬
‫الذاكرة الثانوية‬
‫البرمجيات‬
‫وحدة املعالجة املركزية‬
‫أجهزة الدخل والخرج‬
‫الذاكرة الرئيسية‬
‫الشكل ‪ : 4‬املبرمج داخل الحاسوب!‬
‫ً‬
‫أي أنك أنت من سيأمر املعالج‪ ،‬ولكنك قد تتضايق قليال إن قلصنا حجمك إلى ‪ 5‬مليمترات‪،‬‬
‫ووضعناك داخل الحاسوب إلعطاء أوامر للمعالج بسرعة ثالث مليارات مرة في الثانية‪ ،‬لذا ستضطر‬
‫ً‬
‫مسبقا‪ ،‬وتخزينها في ذاكرة الحاسوب؛ ليستدعيها املعالج في الوقت املناسب‪ .‬تدعى‬
‫إلى كتابة أوامرك‬
‫هذه التعليمات َّ‬
‫املخزنة البرنامج‪ ،‬في حين ُت َّ‬
‫سمى كتابة تلك التعليمات والحصول على تنفيذ صحيح‬
‫لها البرمجة‪.‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪6‬‬
‫‪ 3.1‬فهم البرمجة‬
‫ً‬
‫مبرمجا في النهاية‪ .‬قد‬
‫سنحاول األخذ بيدك نحو إتقان فن البرمجة في بقية فصول الكتاب‪ ،‬وستصير‬
‫ً‬
‫ً‬
‫مبرمجا محترفا‪ ،‬إال أنك ستملك الفكر واملهارات الالزمة التي تؤهلك ملعاينة املشكلة وتحليل‬
‫ال تصبح‬
‫برمجي لها‪ .‬وفي سبيل هذا ستحتاج إلى مهارتين أساسيتين‪ ،‬وهما‪:‬‬
‫حل‬
‫بياناتها ومعلوماتها ثم إيجاد ٍ‬
‫ٍ‬
‫ً‬
‫ُّ‬
‫ُّ‬
‫للغة بشرية‪،‬‬
‫• أوال‪ ،‬تعلم لغة البرمجة (بايثون) بمصطلحاتها وقواعدها‪ ،‬وهذا أشبه بتعلمك ٍ‬
‫ً‬
‫ً‬
‫حيث تتعلم تهجئة كلماتها أوال حتى تصيغ منها جمال صحيحة‪.‬‬
‫ً‬
‫ً‬
‫• ً‬
‫ثانيا‪ ،‬اكتب قصة باستخدام البرمجة‪ ،‬فعندما تكتب قصة معينة تستخدم جمال وعبارات‬
‫إليصال فكرتك إلى القارئ‪ ،‬فالقصة مزيج من الفن واملهارة‪ ،‬وتتطور هذه املهارة بالتمرن‬
‫والحصول على آراء‪ .‬ينطبق هذا على البرمجة‪ ،‬فالقصة هنا هي البرنامج‪ ،‬والفكرة هي‬
‫ُّ‬
‫املشكلة املطلوب حلها‪.‬‬
‫ٌ‬
‫لغة واحدة‬
‫لغة برمجية أخرى‪ ،‬مثل ‪ C++‬وجافا سكربت‪ ،‬بعد تعلم ٍ‬
‫وجدير بالذكر أنه من السهل تعلم ٍ‬
‫مثل بايثون‪ ،‬فمهارة حل املسائل واملشكالت هي نفسها مهما اختلفت لغات البرمجة في تعليماتها وطرق‬
‫استخدامها‪.‬‬
‫في حين ُيعتبر تعلم لغة بايثون نفسها عملية سهلة وسريعة‪ ،‬لكن ستحتاج ً‬
‫وقتا أطول حتى تستطيع‬
‫كتابة برنامج قادر على حل مشكلة معقدة‪ .‬ستتعلم معنا البرمجة بذات الطريقة التي تعل َ‬
‫مت بها‬
‫ً‬
‫فبداية سنقرأ ونشرح بعض البرامج‪ ،‬وبعدها ننتقل إلى كتابة بر َ‬
‫امج بسيطة‪ ،‬ثم إلى كتابة‬
‫الكتابة؛‬
‫ً‬
‫تعقيدا في النهاية‪ .‬بعد فترة من التعلم‪ ،‬ستصبح البرمجة عملية ممتعة وإبداعية‪ ،‬وستبدأ‬
‫برامج أكثر‬
‫بتطوير طريقة تفكير خاصة لتفكيك املسائل التي تواجهك ومن ثم كتابة بر َ‬
‫امج لحلها‪.‬‬
‫سنبدأ أوًال بتعليمات وبنية بايثون‪َّ .‬‬
‫تحل بالصبر‪ ،‬وركز على األمثلة في البداية كما لو أنك تلميذ يتعلم‬
‫الكتابة والقراءة للمرة األولى‪.‬‬
‫ُ‬
‫‪ 4.1‬مفردات بايثون وجملها‬
‫ُ‬
‫على خالف اللغات البشرية‪ ،‬تتكون لغة بايثون من عدد قليل ًّ‬
‫جدا من املفردات‪ ،‬وتسمى هذه املفردات‬
‫ٍ ٍ‬
‫واحدا فقط بالنسبة لبايثون‪ .‬أما ً‬
‫ً‬
‫الحقا عند كتابة برامجك‪،‬‬
‫"الكلمات املحجوزة" ألن لها معنى‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪7‬‬
‫فستستطيع إنشاء مفرداتك الخاصة‪ ،‬والتي تدعى "املتغيرات"‪ ،‬ولك حرية اختيار األسماء لهذه‬
‫املتغيرات بشرط أال تكون من الكلمات املحجوزة‪.‬‬
‫لنشبه األمر بالتعامل مع الحيوانات األليفة‪ ،‬حيث نخاطبها بكلمات مثل‪" :‬اجلس" أو َ‬
‫"ابق مكانك" أو‬
‫"أحضر ً‬
‫شيئا ما"‪ ،‬ولكن إذا استخدمت كلمات غير محجوزة (أي أن الحيوان األليف غير َّ‬
‫مدرب‬
‫َ ً‬
‫مثال‪" :‬أتمنى لو أن ً‬
‫عددا‬
‫عليها)‪ ،‬فسيرمقك بنظرة متعجبة حتى تستخدم كلمة محجوزة‪ .‬فإن قلت‬
‫أكبر من الناس يمشون ليحافظوا على صحتهم العامة"‪ ،‬فكل ما سيفهمه الحيوان األليف هو‬
‫"املش ي"‪ ،‬ألنها كلمة محجوزة في لغته‪.‬‬
‫إليك ً‬
‫بعضا من الكلمات املحجوزة في لغة بايثون‪:‬‬
‫‪with‬‬
‫‪yield‬‬
‫‪not‬‬
‫‪or‬‬
‫‪pass‬‬
‫‪raise‬‬
‫‪return‬‬
‫‪try‬‬
‫‪while‬‬
‫‪global‬‬
‫‪if‬‬
‫‪import‬‬
‫‪in‬‬
‫‪is‬‬
‫‪lambda‬‬
‫‪nonlocal‬‬
‫‪del‬‬
‫‪elif‬‬
‫‪else‬‬
‫‪except‬‬
‫‪finally‬‬
‫‪for‬‬
‫‪from‬‬
‫‪and‬‬
‫‪as‬‬
‫‪assert‬‬
‫‪break‬‬
‫‪class‬‬
‫‪continue‬‬
‫‪def‬‬
‫ً‬
‫مسبقا هذه الكلمات‪ ،‬وعند كل استخدام لكلمة "‪ "try‬ستحاول بايثون تنفيذ التعليمات‬
‫بايثون تعرف‬
‫املطلوبة دون أن يتوقف البرنامج أو يفشل‪ .‬ال تشغل بالك في دالالت هذه الكلمات وسبل استخدامها‪،‬‬
‫إذ سنتعلم ذلك في وقت الحق‪ .‬أما اآلن‪ ،‬فلنبدأ بأمر بسيط‪ ،‬هذا األمر يشبه أن تقول َّ‬
‫"تحدث"‪ ،‬حيث‬
‫ٍ‬
‫بإمكاننا إخبار بايثون بما عليها أن تقوله بوضعه ضمن عالمة اقتباس‪ ،‬مثل‪:‬‬
‫)'!‪print ('Hello World‬‬
‫ً‬
‫ًّ‬
‫متبوعا بنص‬
‫قواعديا في بايثون‪ ،‬والتي بدأت بالتابع ‪print‬‬
‫وبهذا نكون قد كونا أول جملة صحيحة‬
‫من اختيارنا ضمن عالمتي االقتباس‪ ،‬مع مراعاة أن كل جمل التابع مكتوبة ضمن عالمتي اقتباس‪،‬‬
‫سواء املفردة ' ' أو املزدوجة " "‪ُ ،‬ويفضل معظم الناس اإلشارة املفردة‪ ،‬إال في حال كان املطلوب‬
‫ُ‬
‫حينئذ تستخدم اإلشارة‬
‫ظهورها نفسها في النص (كفاصلة عليا في اللغة اإلنكليزية ‪،)apostrophe‬‬
‫ٍ‬
‫املزدوجة‪.‬‬
‫‪ 5.1‬مخاطبة بايثون‬
‫سنحتاج اآلن إلى تعلم كيفية مخاطبة بايثون بعد أن تعلمنا كلمة وجملة بسيطة منها‪ ،‬ولكن قبل ذلك‬
‫ُّ‬
‫سنحتاج إلى تنصيب برنامج بايثون على الحاسوب‪ ،‬وتعلم طريقة تشغيله‪ .‬تتضمن هذه الخطوة‬
‫تفاصيل عديدة‪ ،‬لذلك نقترح عليك زيارة موقع ‪ /https://electronics-go.com/install-python‬أو‬
‫‪ ،www.py4e.com‬حيث َّ‬
‫وضحنا اإلجراءات الالزمة للتنصيب والتشغيل على أنظمة ماكنتوش‬
‫ ملاذا نتعلم البرمجة؟‬:‫الفصل األول‬
8
ً َ
command ‫ أثناء ذلك ستصل إلى مرحلة تستخدم فيها نافذة األوامر‬.‫وويندوز ُمرفقة بلقطات شاشة‬
‫ ويعرض‬،‫( بالعمل‬interpreter) ‫ ويبدأ ُمفسر بايثون‬،"python" ‫ لتكتب كلمة‬terminal ‫ أو‬window
:‫لك ما يأتي‬
Python 3.5.1 (v3.5.1:37a07cee5969, Dec 6 2015, 01:54:25)
[MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
."‫هذه الرموز >>> هي طريقة ُمفسر بايثون ليسألك "ماذا تريدني أن أفعل اآلن؟‬
‫ فلتحاول كتابة السطر الذي‬،‫لنفترض أنه ال علم لك حتى بأبسط مفردات وتعليمات لغة بايثون‬
:‫كوكب مجهول عند هبوطهم على سطحه‬
‫يستخدمه رواد الفضاء للتواصل مع سكان‬
ٍ
>>> I come in peace, please take me to your leader
File "<stdin>", line 1
I come in peace, please take me to your leader
^
SyntaxError: invalid syntax
>>>
‫ ويثبتونك‬،‫ فقد يطعنك سكان الكوكب برماحهم‬،‫ وإن لم تتصرف بسرعة‬،‫ال يبدو هذا الوضع مبش ًرا‬
َ
‫ وبإمكانك‬،‫ أنت تملك نسخة من هذا الكتاب‬،‫ ولكن لحسن الحظ‬،‫ليتناولوك على العشاء‬
‫سيخ‬
ٍ ‫على‬
:‫أن تفتح هذه الصفحة لتحاول مجد ًدا‬
>>> print )'Hello world! ')
Hello world!
:‫ لذا ستحاول التحدث معهم أكثر‬،‫يبدو هذا أفضل بكثير‬
>>> print('You must be the legendary leader that comes from the sky')
You must be the legendary leader that comes from the sky
>>> print('We have been waiting for you for a long time')
We have been waiting for you for a long time
>>> print('Our legend says you will be very tasty with mustard')
Our legend says you will be very tasty with mustard
>>> print 'We will have a feast tonight unless you say
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪9‬‬
‫‪File "<stdin>", line 1‬‬
‫‪print 'We will have a feast tonight unless you say‬‬
‫^‬
‫'‪SyntaxError: Missing parentheses in call to 'print‬‬
‫>>>‬
‫ً‬
‫ً‬
‫صغيرا في بايثون‪ ،‬مما جعل سكان الكوكب‬
‫كانت هذه املحادثة تسير على ما يرام حتى اقترفت خطا‬
‫ً‬
‫يرفعون رماحهم مرة أخرى‪ .‬ضع في الحسبان أن لغة بايثون ليست ذكية كفاية لألسف‪ ،‬فعلى الرغم‬
‫ً‬
‫تعقيدا ً‬
‫كبيرا‪ ،‬إال أنها غير مرنة عند ارتكاب األخطاء القواعدية )‪،(syntax errors‬‬
‫من أنها معقدة‬
‫فحديثك مع بايثون كحديثك مع نفسك‪ ،‬إنما باستخدام قواعد لغوية صارمة‪.‬‬
‫استخدامك لبرنامج َك َتبه سواك يشبه ً‬
‫ُ‬
‫نوعا ما أن تتحدث مع مبرمجي هذا البرنامج‪ ،‬حيث تلعب‬
‫ٍ‬
‫بايثون دور وسيط بينكم‪ ،‬أي أن بايثون هي طريقة املبرمجين للتعبير عن مجرى املحادثة‪ ،‬وبعد بضعة‬
‫فصول من هذا الكتاب ستصبح أحد أولئك املبرمجين‪ ،‬وستتواصل مع مستخدمي برامجك عن طريق‬
‫بايثون‪.‬‬
‫ً‬
‫"وداعا"‪:‬‬
‫أما اآلن‪ ،‬فلعله من غير الالئق أن نترك سكان كوكب بايثون دون أن نقول لهم‬
‫‪>>> good-bye‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫‪NameError: name 'good' is not defined‬‬
‫‪>>> if you don’t mind, I need to leave‬‬
‫‪File "<stdin>", line 1‬‬
‫‪if you don’t mind, I need to leave‬‬
‫^‬
‫‪SyntaxError: invalid syntax‬‬
‫)(‪>>> quit‬‬
‫كما تالحظ‪ ،‬فالخطأ في أول محاولة يختلف عن ثاني خطأ‪ :‬كلمة ‪ if‬من الكلمات املحجوزة‪ ،‬مما جعل‬
‫ُ َّ‬
‫ً‬
‫ً‬
‫وأخيرا نجحنا في قول‬
‫"وداعا"‬
‫املسكينة بايثون تعتقد أننا نحاول قول ش ٍيء‪ ،‬ولكننا لم نوفق في قوله‪.‬‬
‫لبايثون بكتابة )(‪ quit‬بعد شارة التلقين <<<‪ ،‬وبما أنك ما كنت ُلتخمن هذه الكلمة من تلقاء نفسك‪،‬‬
‫ُ‬
‫أمرا ً‬
‫بدليل للغة (مثل هذا الكتاب) ً‬
‫مفيدا‪.‬‬
‫تعتبر االستعانة ٍ‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪10‬‬
‫ّ‬
‫واملترجم‬
‫املفسر‬
‫‪6.1‬‬
‫ِّ‬
‫ِّ‬
‫ُت ُّ‬
‫عد بايثون لغة عالية املستوى‪ ،‬أي أنها ُ‬
‫صممت لتكون واضحة ًّ‬
‫نسبيا للبشر‪ ،‬وللحواسيب في الوقت‬
‫نفسه لتقرأها وتعالجها‪ ،‬ومن اللغات عالية املستوى ً‬
‫أيضا‪C++, PHP, Basic, Ruby, Perl, :‬‬
‫‪ JavaScript‬وغيرها الكثير‪.‬‬
‫ال تفهم وحدة املعالجة املركزية )‪ًّ (CPU‬أيا من هذه اللغات‪ ،‬بل تفهم فقط لغة واحدة ندعوها لغة‬
‫اآللة‪ ،‬وهي لغة بسيطة ًّ‬
‫جدا كاآلتي‪:‬‬
‫‪001010001110100100101010000001111‬‬
‫‪11100110000011101010010101101101‬‬
‫‪...‬‬
‫كلمة "بسيطة" هنا قد تكون خادعة‪ ،‬فهي بسيطة في بنيتها‪ ،‬إذ إنها تتألف من واحد وصفر‪ ،‬لكن‬
‫ً‬
‫ستجد أنها صعبة ومعقدة ًّ‬
‫ً‬
‫برنامجا بواسطتها‪ ،‬لذا يبرمج‬
‫جدا مقارنة مع بايثون حين تحاول أن تكتب‬
‫قلة قليلة من املبرمجين بلغة اآللة وألغراض َّ‬
‫محددة‪ .‬أنشأت العديد من املترجمات حتى نستطيع‬
‫البرمجة بلغات عالية املستوى كبايثون وجافا سكربت‪ ،‬وتحول هذه املترجمات تلك البرامج إلى لغة‬
‫اآللة‪ ،‬حيث تنفذها وحدة املعالجة )‪.(CPU‬‬
‫وباعتبار أن لغة اآللة مرتبطة بعتاد الحاسوب الصلب‪ ،‬فما من طريقة لنقلها بين مختلف أنواع‬
‫ً‬
‫تعقيدا باستخدام ُمفس ٍر مختلف آللة أخرى‪،‬‬
‫العتاد‪ ،‬بينما من املمكن نقل البرامج املكتوبة بلغة أكثر‬
‫نسخة من البرنامج بلغة اآللة من أجل آلة أخرى‪.‬‬
‫أو إعادة جمع الشيفرة إلنشاء‬
‫ٍ‬
‫وتتم هذه العملية عبر املفسرات (‪ (interpreters‬واملترجمات )‪.(compilers‬‬
‫َ‬
‫يقرأ املفسر البرنامج املصدري كما كتبه املبرمج‪ ،‬ويحلله‪ ،‬ويفسر تعليماته مباشرة لآللة‪ .‬تستخدم‬
‫برمجي لتعالجه‬
‫بايثون هذه التقنية‪ ،‬فعند تشغيلنا لبايثون بشكل تفاعلي‪ ،‬نستطيع كتابة سطر‬
‫ٍ‬
‫ً‬
‫سطر آخر‪.‬‬
‫بايثون مباشرة‪ ،‬ثم تنتظر كتابة‬
‫ٍ‬
‫قد نحتاج لتذكر قيم معينة الستخدامها ً‬
‫ً‬
‫أسماء لتلك القيم لنتمكن من‬
‫الحقا في البرنامج‪ ،‬فنختار‬
‫حفظها واسترجاعها حين نحتاجها‪ ،‬وندعو هذه األسماء "املتغيرات"‪.‬‬
‫‪>>> x = 6‬‬
‫)‪>>> print(x‬‬
‫‪6‬‬
‫‪>>> y = x * 7‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪11‬‬
‫)‪>>> print(y‬‬
‫‪42‬‬
‫>>>‬
‫في هذا املثال‪ ،‬طلبنا من بايثون تخزين القيمة ‪ ،6‬وحفظناها في متغير اسمه ‪ x‬لنتمكن من استرجاعها‬
‫ً‬
‫الحقا‪ ،‬وتأكدنا من أن بايثون قد تذكرت ذلك عندما استخدمنا تابع الطباعة ‪ .print‬بعد ذلك‪ ،‬طلبنا‬
‫من بايثون استعادة تلك القيمة لضربها بالعدد ‪ 7‬لنحفظ الناتج في املتغير ‪ ،y‬ثم طلبنا من بايثون أن‬
‫تطبع قيمة ‪.y‬‬
‫قيما َّ‬
‫تعامل بايثون هذه األوامر كسلسلة مترابطة من التعليمات‪ ،‬حيث تسترجع ً‬
‫مخزنة من تعليمات‬
‫سابقة مع أننا كتبنا كل سطر بمفرده‪ ،‬وبذلك نكون قد كتبنا برنامجنا األول البسيط‪ ،‬وهو مكون من‬
‫أربع عبارات مرتبة ً‬
‫ًّ‬
‫منطقيا‪.‬‬
‫ترتيبا‬
‫يميل املفسر إلى نمط املحادثة التفاعلية كما في املثال السابق‪ ،‬في حين يحتاج املترجم أن يستلم‬
‫ً‬
‫لينفذ ً‬
‫كامال في ملف‪ ،‬حيث يحوله إلى لغة اآللة‪ ،‬ثم يحفظ البرنامج الناتج في ملف َّ‬
‫الحقا‪.‬‬
‫البرنامج‬
‫وهذه البرامج املكتوبة بلغة اآللة‪ ،‬والقابلة للتنفيذ‪ً ،‬‬
‫غالبا ما تحمل الالحقة "‪ ".exe‬أو "‪ ".dll‬على نظام‬
‫ويندوز‪ ،‬والتي ترمز إلى "‪ "executable‬و"‪ ،"dynamic link library‬بينما ال توجد لواحق مشابهة في‬
‫بشكل غير‬
‫أنظمة لينوكس وماكنتوش‪ ،‬وإن حاولت فتح ملف تنفيذ في محرر النصوص‪ ،‬فسيظهر‬
‫ٍ‬
‫مقروء كاآلتي‪:‬‬
‫‪^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^B^@^C^@^A^@^@^@\xa0\x82^D^H‬‬
‫@^‪4^@^@^@\x90^]^@^@^@^@^@^@4‬‬
‫‪^@^G^@(^@$^@!^@^F^@^@^@4^@^@^@4\x80^D^H4\x80^D^H\xe0^@^@^@\x‬‬
‫‪e0^@^@^@^E^@^@^@^D^@^@^@^C^@^@^@^T^A^@^@^T\x81^D^H^T\x81^D‬‬
‫‪^H^S^@^@^@^S^@^@^@^D^@^@^@^A^@^@^@^A\^D^HQVhT\x83^D^H\xe8‬‬
‫‪….‬‬
‫ليس من السهل القراءة والكتابة بلغة اآللة‪ ،‬فمن حسن حظنا أننا نملك املفسرات واملترجمات‪ ،‬مما‬
‫يسمح لنا بالبرمجة بلغات عالية املستوى مثل بايثون وس ي ‪.C‬‬
‫لعلك تتساءل اآلن‪ :‬ماذا عن مفسر بايثون؟ وبأي لغة ُكتب؟ وما الذي يحدث ً‬
‫تماما عندما نكتب‬
‫"‪"Python‬؟‬
‫ُ‬
‫ٌ‬
‫مفسر بايثون‬
‫مكتوب بلغة عالية املستوى تدعى س ي "‪ ،"C‬ويمكنك رؤية الشيفرة البرمجية املصدرية‬
‫له بالبحث عنه في موقع ‪ُ .www.python.org‬ت ُّ‬
‫برنامجا َ‬
‫ً‬
‫عد لغة بايثون‬
‫يترجم بدوره إلى لغة اآللة‪ ،‬لذلك‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪12‬‬
‫فإن تنصيبك لبايثون على حاسوبك يعني أنك قد نقلت نسخة من برنامج بايثون َ‬
‫املترجم إلى لغة اآللة‬
‫ً‬
‫موجودا ً‬
‫غالبا تحت االسم التالي‪:‬‬
‫إلى نظامك‪ ،‬وفي ويندوز يكون ملف التنفيذ‬
‫‪C:\Python35\python.exe‬‬
‫ُ‬
‫قد ال تحتاج هذه املعلومات لتبرمج بلغة بايثون‪ ،‬لكن من املفيد اإلجابة عن هذه األسئلة امللحة منذ‬
‫البداية‪.‬‬
‫‪ 7.1‬كتابة برنامج‬
‫ً‬
‫ُ‬
‫تعتبر كتابة األوامر في مفسر بايثون طريقة رائعة الختبار بعض مميزات بايثون‪ ،‬ولكن ال يوص ى بها‬
‫عند محاولة حل مشكالت معقدة‪ ،‬لذلك سنستخدم محرر نصوص عند البرمجة لنكتب تعليمات‬
‫بايثون في ملف يدعى ًّ‬
‫ًّ‬
‫َ‬
‫املتعارف عليه أن تملك النصوص البرمجية في بايثون‬
‫برمجيا (‪ ،)script‬ومن‬
‫نصا‬
‫الالحقة "‪.".py‬‬
‫لتنفيذ النص البرمجي‪ ،‬يجب أن تخبر مفسر بايثون باسم امللف‪ ،‬حيث نكتب في نافذة األوامر‬
‫‪ python hello.py‬ما يأتي‪:‬‬
‫‪$ cat hello.py‬‬
‫)' !‪print ('Hello world‬‬
‫‪$ python hello.py‬‬
‫!‪Hello world‬‬
‫ُ‬
‫تعبر عالمة الدوالر ‪ $‬عن إشارة نظام التشغيل‪ ،‬ويخبرنا األمر ‪ cat hello.py‬أن امللف ‪ hello.py‬يحوي‬
‫ً‬
‫برنامجا ذا سطر واحد يطبع ًّ‬
‫نصا‪ ،‬ثم نستدعي مفسر بايثون لنطلب منه قراءة الشيفرة املصدرية‬
‫َ‬
‫ً‬
‫بدال من أن نكتبه ًّ‬
‫يدويا‪ ،‬وكما تالحظ‪ ،‬فإن بايثون تعلم أن عليها التوقف عن‬
‫من امللف ‪hello.py‬‬
‫التنفيذ عند الوصول إلى نهاية امللف الذي تقرأ منه برنامجك‪ ،‬لذلك لسنا مضطرين الستخدام‬
‫)(‪ quit‬في نهاية البرنامج في امللف‪.‬‬
‫‪ 8.1‬ما هو البرنامج؟‬
‫ُ‬
‫ُ َّ‬
‫أمر ما‪،‬‬
‫يعرف البرنامج في بايثون باختصار على أنه‪ :‬سلسلة من تعليمات بلغة بايثون‪ ،‬وضعت لتنفيذ ٍ‬
‫ً‬
‫برنامجا ذا سطر واحد‪ ،‬على الرغم من أنه غير مفيد ًّ‬
‫عمليا‪،‬‬
‫وحتى النص البرمجي ‪ُ hello.py‬يعتبر‬
‫ٍ‬
‫ُ‬
‫نطرحها للتغلب على املشكلة التي تواجهنا‪.‬‬
‫فالبرنامج هو طريقة الحل التي‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪13‬‬
‫ً‬
‫اجتماعي يتناول منشورات‬
‫ببحث‬
‫القيام‬
‫تريد‬
‫ك‬
‫أن‬
‫ولنفترض‬
‫الواقع‪،‬‬
‫أرض‬
‫من‬
‫مثاال‬
‫لنتناول اآلن‬
‫ٍ‬
‫فيسبوك‪ ،‬وتريد معرفة الكلمة األكثر تكر ًارا في مجموعة معينة من املنشورات‪ .‬يمكنك ً‬
‫طبعا طباعة‬
‫شيوعا‪ ،‬لكن هذه العملية ستستغرق ً‬
‫ً‬
‫كل تلك املنشورات وفحصها ًّ‬
‫وقتا‬
‫يدويا إليجاد الكلمة األكثر‬
‫ً‬
‫طويال‪ ،‬وقد ال تصل إلى الناتج الصحيح في النهاية‪ ،‬لكنك باستخدام بايثون ستنجز هذه العملية بدقة‬
‫وقت ممتع في عطلة نهاية األسبوع‪.‬‬
‫وسرعة‪ ،‬مما يسمح لك بقضاء ٍ‬
‫ً‬
‫انظر مثال إلى النص أدناه‪ ،‬والذي يدور حول مهرج وسيارة‪ ،‬واستخرج منه الكلمة األكثر تكر ًارا وعدد‬
‫مرات تكرارها‪:‬‬
‫‪The clown ran after the car and the car ran into the tent and the tent fell down on the‬‬
‫‪clown and the car‬‬
‫َّ‬
‫ثم تخيل أنك تستخرج الكلمة األكثر تكر ًارا من نص مؤلف من ماليين األسطر‪ .‬لعلك اقتنعت اآلن أنه‬
‫ً‬
‫برنامج ُيحص ي لك عدد مرات تكرار الكلمات‪ ،‬بدال من تنفيذ‬
‫من األسرع تعلم لغة بايثون ثم كتابة‬
‫ٍ‬
‫ً‬
‫هذا ًّ‬
‫يدويا‪ .‬أما إذا أردت َّ‬
‫برنامجا قد‬
‫حل هذه املسألة اآلن‪ ،‬فأنت محظوظ ألن هذا الكتاب يقدم لك‬
‫ُكت َب ُ‬
‫واختبر‪ُ ،‬ونقدمه لك على طبق من ذهب لترى بعينك ً‬
‫بعضا من عظمة بايثون‪:‬‬
‫)' ‪name = input ('Enter file:‬‬
‫)'‪handle = open (name, 'r‬‬
‫)(‪counts = dict‬‬
‫‪for line in handle:‬‬
‫)(‪words = line.split‬‬
‫‪for word in words:‬‬
‫‪counts[word] = counts.get(word, 0) + 1‬‬
‫‪bigcount = None‬‬
‫‪bigword = None‬‬
‫‪for word, count in list(counts.items()):‬‬
‫‪if bigcount is None or count > bigcount:‬‬
‫‪bigword = word‬‬
‫‪bigcount = count‬‬
‫)‪print(bigword, bigcount‬‬
‫‪# Code: http://www.py4e.com/code3/words.py‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪14‬‬
‫تستطيع استخدام هذا البرنامج حتى لو لم تكن تعلم لغة بايثون‪ ،‬ولكنك ستحتاج أن تصبر حتى‬
‫الفصل العاشر من هذا الكتاب لفهم طريقة عمله‪ ،‬أما اآلن فأنت مستخدم للبرنامج وحسب‪،‬‬
‫وبإمكانك أن تستخدمه وترى مدى ذكائه ومقدار الوقت الذي وفره‪ .‬كل ما عليك فعله هو أن تكتب‬
‫ً‬
‫هذا البرنامج في ملف‪ ،‬ثم أن تسميه ‪ words.py‬مثال‪ ،‬أو أن تنزل البرنامج األصلي من املوقع‪:‬‬
‫‪ /http://www.py4e.com/code3‬ثم تشغله‪.‬‬
‫وهو مثال جيد ليؤكد على دور بايثون كوسيط بينك كمستخدم‪ ،‬وبين املبرمج‪ .‬صار بوسعنا تبادل‬
‫عدة تعليمات مفيدة (أي برامج) باستخدام لغة شائعة يستطيع ُّ‬
‫شخص استخدامها بمجرد‬
‫أي‬
‫ٍ‬
‫تنصيب بايثون على حاسوبه‪ ،‬فنحن ال نكلم بايثون مباشرة‪ ،‬بل نتواصل فيما بيننا بواسطتها‪.‬‬
‫ّ‬
‫ّ‬
‫األساسية للبرامج‬
‫املكونات‬
‫‪9.1‬‬
‫في الفصول القادمة سنتعلم أكثر حول مفردات بايثون‪ ،‬وبنيتها‪ ،‬وكيف ندمج بينها لبناء برامج مفيدة‪،‬‬
‫َ‬
‫املستخدمة لكتابة البرامج‪ ،‬وهي ليست خاصة‬
‫لكن قبل ذلك‪ ،‬لنتعرف إلى بعض املفاهيم األساسية‬
‫ببايثون‪ ،‬بل هي جزء من كل لغة برمجة‪ ،‬سواء كانت عالية املستوى أم لغة آلة‪ ،‬وهي‪:‬‬
‫الدخل‪ :‬الحصول على البيانات من العالم الخارجي‪ ،‬كقراءة بيانات معينة من ملف ما‪ ،‬أو حساس‬
‫كاملايكروفون‪ ،‬أو نظام تحديد املواقع ‪ .GPS‬سيكون ُ‬
‫دخل برامجنا األولى عبر لوحة مفاتيح يتحكم بها‬
‫املستخدم‪.‬‬
‫الخرج‪ :‬ويتمثل في عرض نتائج البرنامج على شاشة ما‪ ،‬أو تخزينها في ملف‪ ،‬أو إرسالها إلى جهاز خرج‬
‫كمكبر الصوت لعرض موسيقى معينة أو قراءة نص‪.‬‬
‫التسلسلي‪ :‬تنفيذ األوامر ت ً‬
‫ّ‬
‫باعا‪.‬‬
‫التنفيذ‬
‫تفقد ُّ‬
‫الشرطي‪ُّ :‬‬
‫تحقق شروط معينة وتنفيذ أو تخطي سلسلة من التعليمات ً‬
‫ّ‬
‫بناء على تلك‬
‫التنفيذ‬
‫الشروط‪.‬‬
‫ً‬
‫التنفيذ التكرار ّي‪ :‬تنفيذ عدد معين من التعليمات بشكل متكرر‪ ،‬ويتضمن هذا عادة بعض‬
‫التغييرات‪.‬‬
‫إعادة االستخدام‪ :‬كتابة عدد معين من التعليمات‪ ،‬ثم تسميتها باسم َّ‬
‫محدد الستدعائها عند اللزوم‬
‫خالل البرنامج‪.‬‬
‫ُ‬
‫لعلك تجد هذه املفاهيم ساذجة‪ ،‬كأننا نعرف املش ي على أنه عملية وضع قدم أمام األخرى‪ ،‬لكن إليك‬
‫السر‪ :‬البرمجة فن ندمج فيه بين تلك العناصر األساسية بطريقة تجعلها مفيدة وفعالة‪.‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪15‬‬
‫‪ 10.1‬ما األخطاء التي يمكن أن نواجهها؟‬
‫يجب التزام الدقة عند التواصل مع بايثون كما أينا ً‬
‫سابقا‪ ،‬فأصغر خطأ سيدفع بايثون للتوقف عن‬
‫ر‬
‫تنفيذ البرنامج‪ ،‬لذلك يظن بعض املبرمجين املبتدئين أن هذا ٌ‬
‫دليل على أن بايثون تكرههم وتبغضهم‪،‬‬
‫في حين أنها تفضل املبرمجين اآلخرين عليهم‪ ،‬لذا فهي ترفض برامجهم املثالية‪ ،‬وتعتبرها غير صحيحة‪،‬‬
‫ً‬
‫متقصدة إحراجهم‪.‬‬
‫' !‪>>> primt 'Hello world‬‬
‫‪File "<stdin>", line 1‬‬
‫' !‪primt 'Hello world‬‬
‫^‬
‫‪SyntaxError: invalid syntax‬‬
‫)’‪>>> primt (‘Hello world‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫‪NameError: name 'primt' is not defined‬‬
‫!‪>>> I hate you Python‬‬
‫‪File "<stdin>", line 1‬‬
‫!‪I hate you Python‬‬
‫^‬
‫‪SyntaxError: invalid syntax‬‬
‫‪>>> if you come out of there, I would teach you a lesson‬‬
‫‪File "<stdin>", line 1‬‬
‫‪if you come out of there, I would teach you a lesson‬‬
‫^‬
‫‪SyntaxError: invalid syntax‬‬
‫>>>‬
‫َّ‬
‫مستعدة لخدمتك متى احتجتها‪،‬‬
‫لن يفيد الجدال مع بايثون‪ ،‬فهي مجرد أداة بال مشاعر‪ ،‬ومع ذلك هي‬
‫وإن بدت التحذيرات التي تظهرها قاسية‪ ،‬فهي في الواقع تطلب مساعدتك‪ ،‬وكل ما في األمر أنها‬
‫َّ‬
‫تفحصت ما َ‬
‫كتبته لها‪ ،‬إال أنها لم تتمكن من فهمه‪ ،‬إذ إنها أشبه بحيوان أليف مدلل يحب َك بشدة‪،‬‬
‫منتظرا إياك أن تكتب ً‬
‫ً‬
‫شيئا يفهمه‪،‬‬
‫إال أنه ال يفهم إال بضع كلمات مفتاحية‪ ،‬ويرمقك بنظرة بريئة <<<‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪16‬‬
‫وعندما تقول بايثون‪ ،SyntaxError: Invalid syntax :‬فهي ببساطة تهز ذيلها وتقول‪" :‬يبدو أنك أردت‬
‫أن تقول ً‬
‫شيئا‪ ،‬إال أني ال أفهمه‪ ،‬ولكن أرجو أن تواصل التحدث إلي <<< "‪.‬‬
‫ستواجهك ثالثة أخطاء رئيسية عند البرمجة باستخدام بايثون‪:‬‬
‫ّ‬
‫ً‬
‫إصالحا‪ ،‬وتعني أنك‬
‫القواعدية )‪ :(Syntax errors‬وهي أول األخطاء التي سترتكبها‪ ،‬وأسهلها‬
‫األخطاء‬
‫أخطأت في "القواعد اللغوية" لبايثون‪ ،‬وستحاول بايثون اإلشارة إلى السطر والحرف الذي الحظت‬
‫ُ‬
‫وجود الخطأ فيه‪ .‬قد تخدعك بايثون بأن تشير إلى وجود خطأ في موضع معين‪ ،‬في حين أن الخطأ‬
‫ً‬
‫الفعلي يقع قبل ذلك‪ ،‬لذا ابدأ من حيث أشارت بايثون‬
‫صعودا حتى تجد ذلك الخطأ‪.‬‬
‫ّ‬
‫املنطقية (‪ :)Logic errors‬وتحدث عندما ال توجد أخطاء قواعدية‪ ،‬إنما مشكلة في ترتيب‬
‫األخطاء‬
‫بعض التعليمات أو الربط بينها‪ ،‬كأن يخبرك أحدهم أنه فتح زجاجة املاء ليشرب منها‪ ،‬ثم وضعها في‬
‫حقيبته وتابع سيره‪ ،‬وبعد ذلك أغلق الزجاجة‪.‬‬
‫أخطاء ّ‬
‫داللية (‪ :)Semantic errors‬وتحدث عندما تكون قواعد برنامجك صحيحة ومرتبة ً‬
‫ترتيبا‬
‫ًّ‬
‫منطقيا دون أن يؤدي املطلوب منه‪ ،‬فلو أردت أن تعطي أحدهم التوجيهات للذهاب إلى أحد املطاعم‬
‫ً‬
‫ً‬
‫فقلت له‪" :‬اتجه ً‬
‫واحدا وستجد‬
‫يسارا عندما تصل إلى التقاطع عند محطة البنزين‪ ،‬ثم سر ميال‬
‫ً‬
‫مطعما ذا لو ٍن أحمر إلى يسارك"‪ ،‬ثم بعد فترة يتصل بك هذا الشخص ليخبرك بأنه وصل إلى مزرعة‬
‫مطعما‪ ،‬فستسأله‪" :‬هل اتجهت ً‬
‫ً‬
‫يمينا أم ً‬
‫يسارا عند محطة البنزين؟"‪ ،‬ليجيبك‪" :‬لقد اتبعت‬
‫وليس‬
‫توجيهاتك بحذافيرها‪ ،‬بل إني كتبتها على ورقة حتى ال أنساها"‪ ،‬ثم تفكر للحظة وتحك رأسك ثم تقول‪:‬‬
‫ً‬
‫"أنا آسف يا صديقي‪ ،‬فقد كانت توجيهاتي صحيحة من حيث القواعد‪ ،‬إال أن خطا في دالالتها قد‬
‫فاتني"‪.‬‬
‫فما تقوم به بايثون في كل تلك الحاالت هو تنفيذ ما تطلبه منها قدر استطاعتها‪.‬‬
‫‪ 11.1‬التنقيح‬
‫ً‬
‫عندما تعلن بايثون عن وجود خطا‪ ،‬أو حتى عندما تمنحك نتيجة مختلفة عما أردت‪ ،‬تبدأ عملية‬
‫تنقيح البرنامج‪ .‬والتنقيح هو عملية اكتشاف أسباب األخطاء في برنامجك‪.‬‬
‫ً‬
‫إليك أربعة أساليب لتستخدمها خاصة مع األخطاء صعبة املالحظة‪:‬‬
‫القراءة‪ :‬افحص برنامجك واقرأه وتأكد من أنه مكتوب كما َ‬
‫أردت ً‬
‫تماما‪.‬‬
‫التجريب‪ :‬جرب بعض التغييرات‪ ،‬ثم شغل البرنامج مرة أخرى‪ ،‬وستظهر املشكلة إذا تأكدت من أن‬
‫وقتا ً‬
‫كل ش يء في مكانه الصحيح‪ ،‬لكن قد يستغرق األمر ً‬
‫أحيانا‪.‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪17‬‬
‫ُّ‬
‫التريث‪َّ :‬‬
‫تمهل وفكر واسأل نفسك حول نوع الخطأ الذي يواجهك‪ :‬قواعدي‪ ،‬أم خطأ أثناء التشغيل‪،‬‬
‫أم داللي؟ وما هي املعلومات التي ستحصل عليها من رسائل األخطاء أو خرج البرنامج؟ وما التغيير األخير‬
‫الذي أجريته على البرنامج قبل ظهور املشكلة؟‬
‫التراجع‪ :‬عند نقطة معينة‪ ،‬سيكون أفضل ما تستطيع فعله هو التراجع وإلغاء التغييرات التي أجريتها‬
‫ً‬
‫برنامج يعمل وبإمكانك فهمه‪ ،‬ومن ثم تستطيع أن تعيد بناءه ثانية‪.‬‬
‫حتى تحصل على‬
‫ٍ‬
‫يقع املبرمجون املبتدئون في خطأ االعتماد على إحدى هذه الطرق دون غيرها‪ ،‬إال أن إيجاد خطأ صعب‬
‫ً‬
‫وأحيانا التراجع‪ ،‬فإن لم تنجح ُ‬
‫املالحظة يتطلب القراءة والتنفيذ ُّ‬
‫أحدها‪ ،‬جرب األخرى‪.‬‬
‫والتريث‪،‬‬
‫ًّ‬
‫قواعديا‪ ،‬ولكنها لن تفيد في حالة األخطاء‬
‫فعلى سبيل املثال‪ ،‬قد تنجح طريقة القراءة إن كان الخطأ‬
‫الداللية‪ ،‬فالخطأ هنا موجود داخل رأسك‪ ،‬ولن تكتشفه إن كنت ال تفهم ما يفعله برنامجك حتى ولو‬
‫قرأت البرنامج مائة مرة‪.‬‬
‫تجارب على البرنامج‪ ،‬إال أن ذلك غير ممكن دون قراءة وفهم‬
‫قد يساعد في حل املشكلة إجر ُاء‬
‫ٍ‬
‫برنامجك‪ ،‬وإال ستقع فيما نسميه في هذا الكتاب بنمط "البرمجة العشوائية"‪ ،‬وهو عملية تنفيذ‬
‫ً‬
‫تغييرات عشوائية على البرنامج حتى ينفذ املطلوب‪ ،‬وهو نمط يستلزم ً‬
‫وقتا طويال بالطبع‪.‬‬
‫ستحتاج ً‬
‫وقتا للتفكير في كل األحوال‪ ،‬فالتنقيح كالتجارب العملية‪ ،‬حيث تبدأ بوضع فرضية واحدة‬
‫على األقل حول ماهية املشكلة‪ ،‬وفي حال وجود احتمالين أو أكثر‪ ،‬تحاول وضع اختبار يستبعد أحد‬
‫تلك االحتماالت‪.‬‬
‫استرخ‪ ،‬ثم حاول مرة أخرى‪ .‬تحدث مع اآلخرين‪ ،‬أو حتى مع نفسك‪ ،‬وحاول شرح املشكلة لعلك تجد‬
‫الحل بمجرد عرض املشكلة‪.‬‬
‫ً‬
‫ً‬
‫فغالبا لن تنفع معك أفضل تقنيات التنقيح‪،‬‬
‫ضخما ومعق ًدا‪،‬‬
‫إن كان برنامجك مليء باألخطاء‪ ،‬أو‬
‫برنامج فعال تستطيع فهمه‪.‬‬
‫وعندها يكون الحل األفضل هو التراجع وتبسيط البرنامج لتحصل على‬
‫ٍ‬
‫ً‬
‫لكن عادة ما يتجنب املبرمجون املبتدئون عملية التراجع‪ ،‬حيث يعز عليهم حذف سطر من برنامجهم‬
‫ً‬
‫َ‬
‫ً‬
‫ملف آخر قبل تجزئته‪،‬‬
‫حتى وإن كان خاطئا‪ .‬إن شعرت بذلك مستقبال‪ ،‬فبإمكانك نسخ برنامجك إلى ٍ‬
‫ثم تستطيع إعادة لصق كل جزء على حدة‪.‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪18‬‬
‫ّ‬
‫‪ 12.1‬رحلة التعلم‬
‫َ‬
‫نفسك‬
‫ال تقلق إن شعرت أن املفاهيم غير مترابطة جي ًدا أثناء قراءتك األولى لهذا الكتاب‪ ،‬وتذكر‬
‫ً‬
‫َ‬
‫عندما بدأت تتعلم التحدث‪ ،‬حينما َ‬
‫استغرقت‬
‫أصواتا طفولية ظريفة في البداية‪ ،‬ثم‬
‫كنت تصدر‬
‫حوالي ستة أشهر لتعلم تكوين جمل بسيطة من املفردات القليلة التي تعرفها‪ ،‬وبعد خمس أو ست‬
‫َ‬
‫َ‬
‫واحتجت بضع سنوات أخرى لتكتب قصة قصيرة كاملة‬
‫انتقلت من الجمل إلى فقرا ٍت كاملة‪،‬‬
‫سنوات‬
‫ومثيرة لالهتمام بمفردك‪.‬‬
‫نطمح لتعليمك بايثون خالل وقت أقصر بكثير‪ ،‬لذلك سنكثف املحتوى في الفصول التالية‪ .‬وكما في‬
‫ُّ‬
‫ً‬
‫حال تعلمك لغة جديدة‪ ،‬ستحتاج بعض الوقت الستيعابها وفهمها قبل أن تعتاد عليها‪ ،‬ومن الطبيعي‬
‫أن تشعر ببعض االرتباك أثناء طرحنا ملواضيع تتعرف عليها للمرة األولى‪ ،‬حيث نحاول شرح تفاصيل‬
‫ًّ‬
‫تدريجيا‪ ،‬إال أنك غير مضطر لدراسة الكتاب بشكل منظم‪ ،‬وتستطيع التقدم‬
‫الصورة العامة‬
‫بالقراءة‪ ،‬ومن ثم العودة إلى الفصول السابقة‪ ،‬فمجرد تعرضك لتلك املواضيع املتقدمة يزيد من‬
‫استيعابك للبرمجة بشكل كبير‪ ،‬حتى وإن لم تتعمق في تفاصيلها‪ ،‬وعند مراجعتك ملا سبق وإعادة حل‬
‫ُّ‬
‫مسائله ستدرك قدرتك على التعلم‪.‬‬
‫ستمر ببعض لحظات اإلبداع التي يشعر بها فنان يطرق بمطرقته وإزميله‪ ،‬ثم يتوقف لينظر إلى‬
‫جمال صنعه وعجيب نحته‪ ،‬وإن واجهت معضلة صعبة‪ ،‬فال فائدة من التحديق بها طوال الليل‪ ،‬بل‬
‫خذ استراحة أو غفوة‪ ،‬أو تناول وجبة خفيفة‪ ،‬واشرح ألحدهم مشكلتك (أو حتى لحيوانك األليف)‪،‬‬
‫ثم بإمكانك العودة للدراسة مجد ًدا بذهن متيقظ‪ .‬نضمن لك أنك حين تعود للفصول األولى في هذا‬
‫ً‬
‫ً‬
‫الكتاب بعد أن تتمكن من البرمجة‪ ،‬ستجد أن األمر كان بسيطا وسهال‪ ،‬وكل ما كان يلزمك هو بعض‬
‫الوقت لتستوعبه‪.‬‬
‫‪ 13.1‬فهرس املصطلحات‬
‫• الخطأ (‪ :)Bug‬خطأ في البرنامج‪.‬‬
‫ّ‬
‫املركزية (‪ :)central processing unit‬قلب الحاسوب الذي يشغل‬
‫• وحدة املعالجة‬
‫البرنامج الذي كتبناه‪ ،‬كما ُيدعى "‪ "CPU‬أو "املعالج"‪.‬‬
‫• الترجمة )‪ :)compile‬ترجمة برنامج مكتوب بلغة عالية املستوى إلى لغة منخفضة املستوى‬
‫تجهيزا لتنفيذه ً‬
‫ً‬
‫الحقا‪.‬‬
‫دفعة واحدة‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪19‬‬
‫• لغة عالية املستوى (‪ :)high-level language‬لغة برمجية‪ ،‬مثل بايثون‪َّ ،‬‬
‫مصممة لتكون‬
‫سهلة القراءة والكتابة للبشر‪.‬‬
‫ّ‬
‫التفاعلي (‪ :)interactive mode‬طريقة الستخدام مفسر بايثون عبر كتابة األوامر‬
‫• النمط‬
‫والتعليمات بعد إشارة التلقين‪.‬‬
‫• التفسير(‪ :(interpret‬تنفيذ برنامج مكتوب بلغة عالية املستوى بترجمة أسطره الواحد تلو‬
‫اآلخر‪.‬‬
‫َّ‬
‫مصممة لتكون سهلة‬
‫• لغة منخفضة املستوى )‪ :(low-level language‬لغة برمجة‬
‫التنفيذ على الحاسوب‪ ،‬وتدعى ً‬
‫أيضا بلغة اآللة أو لغة التجميع‪.‬‬
‫• شيفرة اآللة )‪ :(machine code‬أقل مستوى من لغات البرمجة‪ ،‬وهي اللغة التي تنفذها‬
‫وحدة املعالجة املركزية بشكل مباشر‪.‬‬
‫الرئيسية )‪ :(main memory‬تخزن البرامج واملعلومات‪ ،‬وتفقد البيانات َّ‬
‫ّ‬
‫املخزنة‬
‫• الذاكرة‬
‫فيها عند انقطاع الطاقة عنها‪.‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫برنامج ما وتحليل بنيته القواعدية‪.‬‬
‫التحليل )‪ :)parse‬فحص‬
‫ٍ‬
‫ّ‬
‫قابلية النقل (‪ :(portability‬ميزة للبرنامج تسمح له بالعمل على عدة أنواع من الحواسيب‪.‬‬
‫ً‬
‫تابع ‪ :print‬تعليمة تجعل مفسر بايثون يعرض قيمة ما على الشاشة‪.‬‬
‫ّ‬
‫املشكلة وإيجاد حل لها والتعبير عنه‪.‬‬
‫حل املشاكل )‪ :(problem solving‬عملية تحليل‬
‫ٍ‬
‫• البرنامج )‪ :(program‬مجموعة من التعليمات تنفذ عملية حاسوبية‪.‬‬
‫ّ‬
‫ً‬
‫منتظرا املستخدم ليدخل‬
‫موجه األوامر )‪ :(prompt‬عندما يعرض برنامج ما رسالة معينة‬
‫•‬
‫ِّ‬
‫قيمة إلى البرنامج‪.‬‬
‫ّ‬
‫الثانوية )‪ :(secondary memory‬تخزن البرامج واملعلومات وتحتفظ بها حتى إن‬
‫• الذاكرة‬
‫ُ‬
‫قطعت عنها الكهرباء‪ ،‬ولكنها أبطأ من الذاكرة الرئيسية‪ ،‬مثل‪ :‬أقراص التخزين‪ ،‬والذواكر‬
‫املتنقلة ‪.USB‬‬
‫• دالالت )‪ :(semantics‬معنى وهدف البرنامج‪.‬‬
‫داللي (‪ :)semantic error‬خطأ في البرنامج يجعله ينفذ ً‬
‫ً‬
‫• خطأ ّ‬
‫مختلفا عما أراده املبرمج‪.‬‬
‫شيئا‬
‫• البرنامج املصدر ّي )‪ :)source code‬برنامج مكتوب بلغة عالية املستوى‪.‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪20‬‬
‫‪ 14.1‬تمارين‬
‫• التمرين األول‪ :‬ما وظيفة الذاكرة الثانوية في الحاسوب؟‬
‫‪ o‬تنفيذ كل العمليات الحاسوبية واملنطقية في برنامج ما‪.‬‬
‫‪ o‬استدعاء صفحات الويب عبر اإلنترنت‪.‬‬
‫‪ o‬تخزين املعلومات ملدة طويلة حتى بعد انقطاع الكهرباء‪.‬‬
‫‪o‬‬
‫استالم الدخل من املستخدم‪.‬‬
‫• التمرين الثاني‪ :‬ما تعريف البرنامج؟‬
‫• التمرين الثالث‪ :‬ما الفرق بين املفسر واملترجم؟‬
‫• التمرين الرابع‪ٌّ :‬‬
‫أي مما يأتي يتضمن شيفرة اآللة؟‬
‫‪ o‬مفسر بايثون‪.‬‬
‫‪ o‬لوحة املفاتيح‪.‬‬
‫‪ o‬امللف املصدري لبايثون‪.‬‬
‫‪ o‬ملف نص ي‪.‬‬
‫• التمرين الخامس‪ :‬ما الخطأ في البرنامج التالي‪:‬‬
‫' !‪>>> primt 'Hello world‬‬
‫‪File "<stdin>", line 1‬‬
‫' !‪primt 'Hello world‬‬
‫^‬
‫‪SyntaxError: invalid syntax‬‬
‫>>>‬
‫• التمرين السادس‪ :‬بعد تنفيذ السطر البرمجي التالي‪ ،‬أين َّ‬
‫يخزن املتغير "‪ "x‬في الحاسب؟‬
‫‪X = 123‬‬
‫‪ o‬وحدة املعالجة املركزية‪.‬‬
‫‪ o‬الذاكرة الرئيسية‪.‬‬
‫‪ o‬الذاكرة الثانوية‪.‬‬
‫‪ o‬أجهزة الدخل‪.‬‬
‫‪ o‬أجهزة الخرج‪.‬‬
‫الفصل األول‪ :‬ملاذا نتعلم البرمجة؟‬
‫‪21‬‬
‫• التمرين السابع‪ :‬ما هي نتيجة البرنامج اآلتي؟‬
‫‪x = 43‬‬
‫‪x=x+1‬‬
‫)‪print(x‬‬
‫‪43 o‬‬
‫‪44 o‬‬
‫‪x+1 o‬‬
‫ً‬
‫رياضيا‬
‫‪ o‬خطأ ألن ‪ x=x+1‬غير صحيحة‬
‫ً ً‬
‫ًّ‬
‫ذاكرا مثاال عن القدرة البشرية املكافئة‪:‬‬
‫• التمرين الثامن‪ :‬اشرح كال مما يأتي‬
‫‪ o‬وحدة املعالجة املركزية‪.‬‬
‫‪ o‬الذاكرة الرئيسية‪.‬‬
‫‪ o‬الذاكرة الثانوية‪.‬‬
‫‪ o‬أجهزة الدخل‪.‬‬
‫‪ o‬أجهزة الخرج‪.‬‬
‫على سبيل املثال‪ :‬ما هو املقابل البشري لوحدة املعالجة املركزية؟‬
‫• التمرين التاسع‪ :‬كيف تصحح الخطأ القواعدي؟‬
‫الفصل الثاني‬
‫املتغيرات والتعابير والتعليمات‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪23‬‬
‫ّ‬
‫املتغيرات والتعابيروالتعليمات‬
‫‪2‬‬
‫‪ 1.2‬القيم و أنواع البيانات‬
‫ُ‬
‫تعد القيمة )‪ (value‬واحدة من املفاهيم األساسية التي يتعامل معها البرنامج‪ ،‬فالحروف واألرقام هي‬
‫بعض األمثلة عن القيم‪ ،‬مثل ‪ 1‬و‪ 2‬و"‪ ."Hello world‬تنتمي هذه القيم إلى َ‬
‫نوعين مختلفين من أنواع‬
‫البيانات‪ ،‬فالقيمة ‪ 2‬هي عدد صحيح ‪ ،integer‬أما "‪ ،"Hello world‬فهي سلسلة نصية ‪،string‬‬
‫ً‬
‫ُ‬
‫وسميت بذلك ألنها تحوي سلسلة من املحارف‪ .‬يمكن تمييز السلسلة النصية من عالمة االقتباس‬
‫املزدوجة " "‪.‬‬
‫تتعامل تعليمة الطباعة ‪ print‬مع كل من السالسل النصية واألعداد الصحيحة‪.‬‬
‫ليبدأ املفسر بالعمل‪ ،‬علينا كتابة األمر ‪ python‬كما يلي‪:‬‬
‫‪python‬‬
‫)‪>>> print(4‬‬
‫‪4‬‬
‫إذا لم تكن متأك ًدا من نوع القيمة‪ ،‬فاملفسر سيخبرك بذلك‪:‬‬
‫)' !‪>>> type ('Hello, World‬‬
‫> '‪<class 'str‬‬
‫)‪>>> type(17‬‬
‫>'‪<class 'int‬‬
‫للتوضيح‪ ،‬فالقيمة "‪ "Hello World‬تنتمي إلى نوع السلسة النصية‪ُ ،‬وي َّ‬
‫عبر عنها برمز ‪ .str‬وباملثل‪ ،‬تنتمي‬
‫القيمة ‪ 17‬إلى األعداد الصحيحة ‪ ،int‬أما األرقام التي تحوي فاصلة عشرية‪ ،‬فهي تنتمي إلى نوع األعداد‬
‫ذات الفاصلة العشرية ‪ ،float‬وتأتي التسمية من طريقة تمثيل هذه األعداد‪ ،‬والتي تدعى ‪floating‬‬
‫‪.point‬‬
‫)‪>>> type(3.2‬‬
‫>'‪<class 'float‬‬
‫ُ‬
‫أما القيم مثل "‪ "17‬و"‪ ،"3.2‬فهي تبدو كأرقام‪ ،‬ولكن بسبب وجود عالمة االقتباس تعتبر سالسل‬
‫نصية‪.‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪24‬‬
‫)'‪>>> type('17‬‬
‫>'‪<class 'str‬‬
‫)'‪>>> type('3.2‬‬
‫>'‪<class 'str‬‬
‫قد يلجأ البعض عند كتابة عدد صحيح كبير إلى وضع فواصل بين خانة العشرات واملئات واأللوف‪...‬‬
‫ً‬
‫ً‬
‫خاطئا للعدد الصحيح‪ ،‬ولكن في نفس الوقت‬
‫إلخ‪ ،‬مثل ‪ ،1,000,000‬لكن لغة بايثون تعتبر هذا تمثيال‬
‫ستتعامل معه في تعليمة الطباعة كما يلي‪:‬‬
‫)‪>>> print(1,000,000‬‬
‫‪100‬‬
‫ٌ‬
‫َّ‬
‫نتيجة غير متوقعة‪ ،‬فلغة بايثون تفسر ‪ 1,000,000‬على أنها مجموعة أعداد صحيحة مستقلة‬
‫ُ‬
‫تفصل بينها فاصلة‪ ،‬فيظهر على الخرج األعداد املبينة وبينها فراغات‪ .‬تمثل هذه الحالة ما ُيعرف‬
‫بالخطأ الداللي (‪ ،)semantic error‬حيث َّ‬
‫تنفذ الشيفرة البرمجية دون رسالة خطأ‪ ،‬لكنها ال تعطي‬
‫َّ‬
‫الخرج أو النتيجة الصحيحة املتوقعة‪.‬‬
‫ّ‬
‫املتغيرات‬
‫‪2.2‬‬
‫ُ‬
‫تعد القدرة على التالعب باملتغيرات أحد أقوى ميزات لغة البرمجة‪ ،‬واملتغير هو اسم يشير إلى قيم‪.‬‬
‫تنش ئ تعليمة اإلسناد )‪ )assignment statement‬متغيرات جديدة‪ ،‬وتعطيها قيم‪:‬‬
‫'‪>>> message = 'And now for something completely different‬‬
‫‪>>> n = 17‬‬
‫‪>>> pi = 3.1415926535897931‬‬
‫نالحظ في املثال ثالث عمليات إسناد‪ :‬األولى إسناد سلسلة نصية إلى متغير جديد ُيسمى ‪،message‬‬
‫أما الثانية‪ ،‬فإسناد العدد الصحيح ‪ 17‬للمتغير ‪ ،n‬أما الثالثة‪ ،‬فإسناد القيمة التقريبية لـ ‪ π‬للمتغير‬
‫‪.pi‬‬
‫إلظهار قيمة املتغير بإمكانك استخدام تعليمة الطباعة ‪:print‬‬
‫)‪>>> print(n‬‬
‫‪17‬‬
‫)‪>>> print(pi‬‬
‫‪3.141592653589793‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪25‬‬
‫ُ‬
‫نوع املتغير هو نوع القيمة التي يمثلها‪:‬‬
‫)‪>>> type(message‬‬
‫>'‪<class 'str‬‬
‫)‪>>> type(n‬‬
‫>'‪<class 'int‬‬
‫)‪>>> type(pi‬‬
‫>'‪<class 'float‬‬
‫ّ‬
‫ّ‬
‫املفتاحية‬
‫املتغيرات والكلمات‬
‫‪ 3.2‬أسماء‬
‫يختار املبرمجون عادة أسماء املتغيرات )‪ (variables‬بحيث تكون ذات معنى وتعكس الهدف من‬
‫استخدامها‪.‬‬
‫ًّ‬
‫يمكن ألسماء املتغيرات أن تكون ذات أطوال مختلفة‪ ،‬وقد تتضمن كال من األحرف واألرقام‪ ،‬لكن ال‬
‫يمكن أن يبدأ اسم املتغير برقم‪ ،‬كما ُيسمح باستخدام الحروف الكبيرة‪ ،‬ولكن من األفضل أن يبدأ‬
‫اسم املتغير بحروف صغيرة (سنرى السبب ً‬
‫الحقا)‪.‬‬
‫ُيسمح بوجود رمز الشرطة السفلية _ في اسم املتغير‪ُ ،‬وتستخدم ً‬
‫غالبا في أسماء املتغيرات التي تحوي‬
‫العديد من الكلمات‪ ،‬مثل‪ ،my_name :‬أو ‪.air_speed_of_unladen_swallow‬‬
‫َ ُ‬
‫وقد تبدأ أسماء املتغيرات بالشرطة السفلية _‪ ،‬لكن بشكل عام نتجنب ذلك إن لم نكن نكتب شيفرة‬
‫ملكتبة برمجية قد يستخدمها اآلخرون‪.‬‬
‫إذا اخترت ً‬
‫اسما غير مسموج ملتغير‪ ،‬فستتلقى رسالة خطأ قواعدي )‪.(syntax error‬‬
‫'‪>>> 76trombones = 'big parade‬‬
‫‪SyntaxError: invalid syntax‬‬
‫‪>>> more@ = 1000000‬‬
‫‪SyntaxError: invalid syntax‬‬
‫'‪>>> class = 'Advanced Theoretical Zymurgy‬‬
‫‪SyntaxError: invalid syntax‬‬
‫ُ‬
‫اسم املتغير ‪ 76trobones‬غير مسموح ألنه يبدأ برقم‪ ،‬واسم املتغير @‪ more‬غير مسموح ألنه يحتوي‬
‫على رمز @ غير املسموح‪ ،‬لكن ما املشكلة في اسم املتغير ‪class‬؟‬
‫كلمة ‪ class‬هي إحدى الكلمات املفتاحية (‪ )keywords‬في لغة بايثون‪ ،‬فاملفسر يستخدم الكلمات‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪26‬‬
‫املفتاحية للتعرف على بنية البرنامج‪ ،‬وبالتالي ال يمكن استخدامها كأسماء متغيرات‪ .‬تخزن لغة بايثون‬
‫‪ 35‬كلمة مفتاحية‪:‬‬
‫‪True‬‬
‫‪None‬‬
‫‪from‬‬
‫‪del‬‬
‫‪and‬‬
‫‪try‬‬
‫‪nonlocal‬‬
‫‪global‬‬
‫‪elif‬‬
‫‪as‬‬
‫‪while‬‬
‫‪not‬‬
‫‪if‬‬
‫‪else‬‬
‫‪assert‬‬
‫‪with‬‬
‫‪or‬‬
‫‪import‬‬
‫‪except‬‬
‫‪break‬‬
‫‪yield‬‬
‫‪pass‬‬
‫‪in‬‬
‫‪False‬‬
‫‪class‬‬
‫‪async‬‬
‫‪raise‬‬
‫‪is‬‬
‫‪finally‬‬
‫‪continue‬‬
‫‪await‬‬
‫‪return‬‬
‫‪lambda‬‬
‫‪for‬‬
‫‪def‬‬
‫ُي َّ‬
‫فضل أن تحتفظ بهذه القائمة أعاله‪ ،‬وإذا أعطى املفسر تنبيه ًًا حول أحد أسماء املتغيرات ولم‬
‫تعرف السبب‪ ،‬فانظر إن كانت إحداها في تلك القائمة‪.‬‬
‫‪ 4.2‬التعليمات‬
‫التعليمة هي ٌ‬
‫جزء من الشيفرة البرمجية يستطيع مفسر بايثون تنفيذها‪.‬‬
‫رأينا ساب ًقا نوعين من التعليمات‪ :‬تعليمة ‪ print‬بوصفها تعليمة تعبير )‪،(expression statement‬‬
‫وتعليمة اإلسناد (‪.)assignment‬‬
‫ُ‬
‫عندما تكتب تعليمة في الوضع التفاعلي )‪ُ ،)interactive mode‬ينفذها املفسر ويعرض النتيجة كما‬
‫لو أن هناك تعليمة واحدة فقط‪.‬‬
‫ً‬
‫بينما يتضمن النص البرمجي عادة سلسلة من التعليمات‪ ،‬فتظهر النتائج واحدة تلو األخرى أثناء‬
‫ً‬
‫تنفيذ التعليمات‪ .‬ففي النص البرمجي التالي مثال‪:‬‬
‫)‪print(1‬‬
‫‪x=2‬‬
‫)‪print(x‬‬
‫سيظهر الخرج بالترتيب‪:‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪27‬‬
‫‪1‬‬
‫‪2‬‬
‫ُ‬
‫وال تظهر تعليمة اإلسناد أي خرج‪.‬‬
‫‪ 5.2‬العوامل واملعامالت‬
‫العوامل (‪ٌ (operators‬‬
‫موز خاصة بالعمليات الحسابية‪ ،‬مثل الجمع والضرب‪.‬‬
‫ر‬
‫ُتسمى القيم التي ُت َّ‬
‫طبق العوامل عليها باملعامالت (‪.(operands‬‬
‫ُ‬
‫العوامل ‪ ** / * - +‬تمثل الجمع والطرح والضرب والقسمة والرفع إلى قوة‪ ،‬كما في األمثلة التالية‪:‬‬
‫‪20+32‬‬
‫‪hour-1‬‬
‫‪hour*60+minute‬‬
‫‪minute/60‬‬
‫‪5**2‬‬
‫)‪(5+9)*(15-7‬‬
‫وقد حصل ٌ‬
‫تغيير في عامل القسمة بين نسخة ‪ Python2.x‬ونسخة ‪ ،Python3.x‬ففي ‪،Python3.x‬‬
‫ً‬
‫تحوي نتيجة عملية القسمة التالية فاصلة عشرية‪:‬‬
‫‪>>> minute = 59‬‬
‫‪>>> minute/60‬‬
‫‪0.9833333333333333‬‬
‫أما العامل ذاته في ‪ Python2.0‬فيقسم العددين الصحيحين ُويقرب النتيجة لعدد صحيح فقط‪:‬‬
‫‪>>> minute = 59‬‬
‫‪>>> minute/60‬‬
‫‪0‬‬
‫استخدم عامل القسمة ذي التقريب لألدنى (‪ )//‬للحصول على نفس اإلجابة في ‪.Python3.0‬‬
‫‪>>> minute = 59‬‬
‫‪>>> minute//60‬‬
‫‪0‬‬
‫تعمل توابع قسمة العدد الصحيح في ‪ Python3.0‬كما لو أنك تستخدم آلة حاسبة لحساب ناتج‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪28‬‬
‫القسمة‪.‬‬
‫‪ 6.2‬التعابير‬
‫ُي َعد التعبير ً‬
‫مزيجا من القيم واملتغيرات والعوامل‪ُ ،‬وت َع ُّد القيمة بمفردها ً‬
‫تعبيرا‪ ،‬وينطبق األمر ذاته‬
‫ُ‬
‫ُ‬
‫على املتغير‪ .‬وفي املثال التالي‪ ،‬تعد جميع التعابير التالية صحيحة (على فرض أن املتغير ‪ x‬قد أسند‬
‫إلى قيمة)‪:‬‬
‫‪17‬‬
‫‪x‬‬
‫‪x + 17‬‬
‫إذا كتبت تعبي ًرا في الوضع التفاعلي (‪ ،)interactive mode‬فسيفسره املفسر ويعرض النتيجة‪:‬‬
‫‪>>> 1 + 1‬‬
‫‪2‬‬
‫إال أن التعبير لوحده ال يقوم بش يء في النص البرمجي‪ ،‬وهذا أحد األمور الشائعة التي تحير املبتدئين‪.‬‬
‫التمرين ‪ :1‬اكتب التعليمات التالية في مفسر بايثون لترى ما تقوم به‪:‬‬
‫‪5‬‬
‫‪x =5‬‬
‫‪x +1‬‬
‫ّ‬
‫ّ‬
‫العمليات‬
‫تراتبية‬
‫‪7.2‬‬
‫عندما يظهر أكثر من عامل في التعبير‪ ،‬تعتمد تراتبية الحل على قواعد األسبقية‪ ،‬ففي العمليات‬
‫الرياضية‪ ،‬تتبع بايثون االصطالحات الرياضية املعروفة‪.‬‬
‫ُيشكل االختصار ‪ PEMDAS‬طريقة مفيدة لتذكر القواعد التالية‪:‬‬
‫ األقواس (‪ )Parentheses‬لها األسبقية‪ ،‬ويمكن استخدامها للحل بالترتيب الذي تريده‪ .‬بما أن‬‫ً‬
‫ُ‬
‫التعبيرات بين قوسين ت َحل أوال‪ ،‬فالعملية الرياضية )‪ 2*(3-1‬تعطي ‪ ،4‬والعملية الرياضية‬
‫)‪ (1+1)**(5-2‬تعطي ‪. 8‬‬
‫ويمكن استخدام األقواس لتسهيل قراءة التعبير‪ ،‬كما في املثال ‪ ،(minute*100)/60‬حتى لو لم‬
‫تغير النتيجة‪.‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪29‬‬
‫ يمثل عامل الرفع إلى قوة (‪ )Exponentiation‬األسبقية التالية بعد األقواس‪ ،‬فالعملية الرياضية‬‫‪ 2**1+1‬ناتجها ‪ ،3‬وليس ‪ ،4‬و‪ 3*1**3‬ناتجها ‪ 3‬وليس ‪.27‬‬
‫ أما الضرب (‪ )Multiplication‬والقسمة (‪ ،)Division‬فلهما نفس األسبقية‪ ،‬والتي تسبق عمليتا‬‫الجمع (‪ )Addition‬والطرح (‪ )Subtraction‬اللتان لهما نفس األولوية‪ ،‬لذلك ‪ 2*3-1‬ناتجها ‪ ،5‬وليس‬
‫‪ ،4‬و‪ 6+4/2‬ناتجها ‪ ،8‬وليس ‪.5‬‬
‫ُت َّ‬
‫قيم العوامل التي تملك نفس األولوية من اليسار إلى اليمين‪ ،‬لذلك ناتج التعبير ‪ 5-3-1‬يساوي ‪،1‬‬
‫ً‬
‫ً‬
‫أقواسا في تعبيراتك‬
‫وليس ‪ ،3‬ألن ‪ 5-3‬تحدث أوال‪ ،‬ثم ‪ 1‬مطروح من ‪ .2‬لتجنب الشك في األولوية‪ ،‬ضع‬
‫دائما للتأكد من أن إجراء الحسابات يحدث بالترتيب الذي ُ‬
‫ً‬
‫تريده‪.‬‬
‫‪ 8.2‬عامل باقي القسمة‬
‫يعمل مع األعداد الصحيحة‪ ،‬ويعطي باقي قسمة املعامل األول على الثاني‪.‬‬
‫َّ‬
‫ُيمثل في لغة بايثون عامل باقي القسمة بإشارة ‪ ،%‬والقواعد هي نفسها بالنسبة ألي عامل آخر‪.‬‬
‫‪>>> quotient = 7 // 3‬‬
‫)‪>>> print(quotient‬‬
‫‪2‬‬
‫‪>>> remainder = 7 % 3‬‬
‫)‪>>> print(remainder‬‬
‫‪1‬‬
‫أي ‪ 7‬مقسومة على ‪ 3‬يساوي ‪ 2‬مع الباقي ‪.1‬‬
‫ً‬
‫على عكس ما يبدو‪ ،‬يملك عامل باقي القسمة فائدة كبيرة‪ ،‬إذ يمكنك مثال التحقق من قابلية قسمة‬
‫أحد األرقام على رقم آخر‪ ،‬فإذا كانت ‪( X%Y‬أي باقي قسمة ‪ X‬على ‪ )Y‬تساوي الصفر‪ ،‬يكون الرقم ‪X‬‬
‫ً‬
‫قابال للقسمة على ‪.Y‬‬
‫ً‬
‫كما يمكن استخراج رقم أو عدة أرقام موجودة في أقص ى يمين عدد‪ ،‬فمثال العملية ‪ X%10‬تعطي‬
‫الرقم املوجود أقص ى اليمين من ‪ X‬في األساس ‪( 10‬على سبيل املثال ‪ 115%10‬تعطي ‪ )5‬وكذلك تعطي‬
‫من أجل ‪ 100%‬قيمة آخر رقمين (‪ 15‬في حالة العدد ‪.)115‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪30‬‬
‫العمليات على السالسل ّ‬
‫ّ‬
‫النص ّية‬
‫‪9.2‬‬
‫يعمل العامل ‪ +‬مع السالسل النصية‪ ،‬لكنه ال يعني الجمع بمعناه الرياض ي‪ ،‬بل يجري تجميع‪ ،‬والذي‬
‫يعني ضم السالسل ً‬
‫معا‪ ،‬مثل‪:‬‬
‫‪>>> first = 10‬‬
‫‪>>> second = 15‬‬
‫)‪>>> print(first+second‬‬
‫‪25‬‬
‫'‪>>> first = '100‬‬
‫'‪>>> second = '150‬‬
‫)‪>>> print(first + second‬‬
‫‪100150‬‬
‫كما يعمل العامل * مع السالسل النصية عبر تكرار محتوى السلسلة ً‬
‫ً‬
‫صحيحا من املرات‪ ،‬مثل‪:‬‬
‫عددا‬
‫' ‪>>> first = 'Test‬‬
‫‪>>> second = 3‬‬
‫)‪>>> print(first * second‬‬
‫‪Test Test Test‬‬
‫‪ 10.2‬إدخال البيانات من املستخدم‬
‫ً‬
‫أحيانا إلى أخذ قيمة متغير ما من املستخدم عبر لوحة املفاتيح‪ ،‬وتوفر لغة بايثون ً‬
‫تابعا‬
‫قد نحتاج‬
‫ٍ‬
‫ً‬
‫جاهزا يدعى ‪ ،input‬والذي يقبل ً‬
‫قيما من لوحة املفاتيح‪( .‬كان هذا التابع يدعى ‪ raw_input‬في ‪Python‬‬
‫‪)2.0‬‬
‫يتوقف البرنامج وينتظر املستخدم لكتابة ش يء ما عندما ُيستدعى هذا التابع‪ ،‬وعندما يضغط‬
‫املستخدم مفتاح اإلدخال )‪ )enter‬أو العودة )‪ ،(return‬يستأنف البرنامج‪ ،‬ويعيد التابع ‪ input‬ما‬
‫كتبه املستخدم بشكل سلسلة نصية‪.‬‬
‫)(‪>>> inp = input‬‬
‫‪Some silly stuff‬‬
‫)‪>>> print(inp‬‬
‫‪Some silly stuff‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪31‬‬
‫ُ‬
‫من األفضل طباعة عبارة تخبر املستخدم بما عليه إدخاله قبل الحصول على مدخالت منه‪.‬‬
‫ُ‬
‫يمكنك تمرير سلسلة نصية إلى التابع ‪ input‬كي تعرض للمستخدم قبل التوقف املؤقت بانتظار‬
‫الدخل‪.‬‬
‫)'‪>>> name = input('What is your name?\n‬‬
‫?‪What is your name‬‬
‫‪Chuck‬‬
‫)‪>>> print(name‬‬
‫‪Chuck‬‬
‫ً‬
‫جديدا‪ ،‬وهي ٌ‬
‫ً‬
‫رمز خاص يتسبب في فصل األسطر‪.‬‬
‫سطرا‬
‫تضيف السلسلة ‪ \n‬في نهاية موجه األوامر‬
‫لهذا السبب يظهر دخل املستخدم أسفل العبارة‪ ،‬وليس على نفس السطر‪.‬‬
‫إذا كنت تتوقع أن يكتب املستخدم عدد صحيح‪ ،‬فيمكنك تحويل القيمة املعادة لعدد صحيح ‪int‬‬
‫باستخدام التابع )(‪:int‬‬
‫'‪>>> prompt = 'What... is the airspeed velocity of an unladen swallow?\n‬‬
‫)‪>>> speed = input(prompt‬‬
‫?‪What... is the airspeed velocity of an unladen swallow‬‬
‫‪17‬‬
‫)‪>>> int(speed‬‬
‫‪17‬‬
‫‪>>> int(speed) + 5‬‬
‫‪22‬‬
‫لكن إذا كتب املستخدم ً‬
‫شيئا آخر غير سلسلة نصية من األرقام‪ ،‬فستظهر رسالة خطأ‪:‬‬
‫)‪>>> speed = input(prompt‬‬
‫?‪What... is the airspeed velocity of an unladen swallow‬‬
‫?‪What do you mean, an African or a European swallow‬‬
‫)‪>>> int(speed‬‬
‫‪ValueError: invalid literal for int() with base 10:‬‬
‫سنرى كيفية التعامل مع األخطاء من هذا النوع ً‬
‫الحقا‪.‬‬
‫‪ 11.2‬التعليقات‬
‫ً‬
‫وغالبا ما يكون من الصعب قراءة جزء من‬
‫تزداد صعوبة قراءة البرامج مع ازدياد حجمها وتعقيدها‪،‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪32‬‬
‫شيفرة برمجية ومعرفة ما يفعله البرنامج وملاذا‪ ،‬لذلك َّ‬
‫يفضل إضافة مالحظات إلى برامجك لتشرح‬
‫فيها باللغة الطبيعية ما يفعله هذا البرنامج‪ .‬تسمى هذه املالحظات التعليقات (‪ ،(comments‬وفي لغة‬
‫بايثون يبدأ التعليق بالرمز ‪:#‬‬
‫‪# compute the percentage of the hour that has elapsed‬‬
‫‪percentage = (minute * 100) / 60‬‬
‫في هذه الحالة‪ ،‬سيظهر تعليق على سطر بمفرده‪ ،‬كما يمكنك وضع التعليقات في نهاية السطر‪:‬‬
‫‪percentage = (minute * 100) / 60 # percentage of an hour‬‬
‫ُي َت َ‬
‫جاهل كل ش يء من الرمز ‪ #‬إلى نهاية السطر‪ ،‬وال يكون له أي تأثير على البرنامج‪.‬‬
‫تبرز فائدة التعليقات عندما توثق ميزات غير واضحة للشيفرة البرمجية‪ ،‬وبما أنه من املنطقي افتراض‬
‫أن القارئ قادر على معرفة ما تفعله الشيفرة‪ُ ،‬يعد التعليق أكثر فائدة عندما يشرح السبب‪.‬‬
‫داع لهذا التعليق غير مفيد‪:‬‬
‫ما من ٍ‬
‫‪v = 5 # assign 5 to v‬‬
‫أما هذا التعليق‪ ،‬فيحوي معلومة مفيدة غير موجودة في الشيفرة‪:‬‬
‫‪v = 5 # velocity in meters/second.‬‬
‫تقلل أسماء املتغيرات الجيدة من الحاجة إلى التعليقات‪ ،‬لكن األسماء الطويلة قد تعطي تعابير‬
‫معقدة تصعب قراءتها‪ ،‬لذلك تجب املحافظة على التوازن بينهما‪.‬‬
‫ّ‬
‫‪ 12.2‬اختيارأسماء ّ‬
‫متغيرات سهلة التذكر‬
‫باتباعك لقواعد تسمية املتغيرات البسيطة‪ ،‬وتجنب الكلمات املحجوزة‪ ،‬ستجد أمامك العديد من‬
‫الخيارات لتسمية املتغيرات الخاصة بك‪.‬‬
‫ً‬
‫ً‬
‫ً‬
‫برنامجا بنفسك‪ .‬فعلى سبيل املثال‪،‬‬
‫برنامجا‪ ،‬وحين تكتب‬
‫في البداية قد يكون الخيار مربكا حين تقرأ‬
‫البرامج الثالثة التالية متطابقة من حيث الفعل‪ ،‬ولكنها مختلفة ج ًدا عندما تقرؤها وتحاول فهمها‪:‬‬
‫‪a = 35.0‬‬
‫‪b = 12.50‬‬
‫‪c=a*b‬‬
‫)‪print(c‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪33‬‬
‫‪hours = 35.0‬‬
‫‪rate = 12.50‬‬
‫‪pay = hours * rate‬‬
‫)‪print(pay‬‬
‫‪x1q3z9ahd = 35.0‬‬
‫‪x1q3z9afd = 12.50‬‬
‫‪x1q3p9afd = x1q3z9ahd * x1q3z9afd‬‬
‫)‪print(x1q3p9afd‬‬
‫َيعتبر مفس ُر لغة البايثون البرامج الثالثة متطابقة ً‬
‫تماما‪ ،‬لكن اإلنسان يرى ويفهم هذه البرامج‬
‫بطريقة مختلفة للغاية‪ ،‬إذ سيفهم اإلنسان الهدف من البرنامج الثاني على الفور ألن املبرمج يملك‬
‫ُ َ‬
‫أسماء متغيرات مختارة تعكس َ‬
‫ستخ َّزن‪.‬‬
‫القيم التي‬
‫ُ‬
‫تدعى أسماء املتغيرات املختارة بحكمة "أسماء املتغيرات سهلة التذكر" ( ‪mnemonic variable‬‬
‫‪ .)names‬الكلمة ‪ mnemonic‬اختصار لـ ‪ ،memory aid‬أي "مساعد للذاكرة"‪ ،‬ونستخدم هذا النوع‬
‫من املتغيرات للمساعدة في تذكر سبب إنشائنا للمتغير في األصل‪ .‬وعلى الرغم من أن كل ذلك يبدو‬
‫ومفيدا‪ ،‬إال أنه قد يشكل ً‬
‫ً‬
‫عائقا أمام املبرمجين املبتدئين في القدرة على تحليل وفهم نوع‬
‫جي ًدا‬
‫الشيفرة‪ ،‬وذلك ألن املبرمجين املبتدئين لن يكونوا قد حفظوا الكلمات املحجوزة بعد (توجد ‪ 35‬منها‬
‫ً‬
‫فقط)‪ .‬وقد تبدو املتغيرات ذات األسماء الوصفية وكأنها ٌ‬
‫أسماء‬
‫جزء من اللغة في بعض األحيان‪ ،‬ال‬
‫مختارة بعناية وحسب‪.‬‬
‫انظر إلى النموذج التالي الذي يمثل شيفرة برمجية بلغة البايثون‪ ،‬ويتعامل مع بيانات ضمن حلقة‬
‫تكرارية‪ .‬سوف نناقش موضوع الحلقات ً‬
‫قريبا‪ ،‬لكن فلنحاول اآلن اكتشاف معنى هذه الحلقة‪:‬‬
‫‪for word in words:‬‬
‫)‪print(word‬‬
‫وأي من تلك الرموز (‪ for‬و‪ word‬و‪ in‬وغيرها‪ ...‬إلخ) ُيمثل كلمات محجوزة؟ ٌّ‬
‫ماذا يحصل هنا؟ ٌّ‬
‫وأي منها‬
‫ُيمثل أسماء متغيرات؟ وهل تفهم بايثون مفهوم الكلمات ً‬
‫أساسا؟‬
‫يواجه املبرمجون املبتدئون صعوبة في تمييز أجزاء الشيفرة التي اختارها املبرمج‪.‬‬
‫تشابه الشيفرة البرمجية التالية الشيفرة التي ذكرناها أعاله‪:‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪34‬‬
‫‪for slice in pizza:‬‬
‫)‪print(slice‬‬
‫ُ‬
‫من األسهل للمبرمج املبتدئ النظر إلى هذه الشيفرة البرمجية ومعرفة أية أجزاء منها تمثل كلمات‬
‫محجوزة محددة من قبل لغة بايثون‪ُّ ،‬‬
‫وأي األجزاء هي أسماء متغيرات اختارها املبرمج‪.‬‬
‫ًّ‬
‫قادر على فهم الكلمتين ‪ pizza‬و ‪ ،slices‬أو حقيقة أن البيتزا تتكون‬
‫من الواضح جدا أن بايثون غير ٍ‬
‫من مجموعة واحدة أو أكثر من الشرائح (‪ ،)slices‬لكن إذا كان برنامجنا متعل ًقا بقراءة البيانات‬
‫والبحث عن الكلمات في البيانات‪ ،‬فمن الصعب تذكر أسماء متغيرات مثل ‪ Pizza‬و‪ ،Slices‬واختيار‬
‫ً‬
‫ضياعا عن معنى البرنامج‪.‬‬
‫أسماء متغيراتك على هذا النحو سيسبب‬
‫ًّ‬
‫تلقائيا‪.‬‬
‫بعد فترة قصيرة سوف تتعلم أكثر عن الكلمات املحجوزة الشائعة‪ ،‬وستتذكرها‬
‫أجزاء الشيفرة البرمجية التي تحددها لغة بايثون هي (‪ ،): ، print ، in ، for‬أما املتغيرات التي اختارها‬
‫املبرمج فهي ‪ word‬و‪.words‬‬
‫تتعامل العديد من برامج تحرير النصوص مع قواعد لغة بايثون‪ ،‬لذا تلون تلك الكلمات بألوان‬
‫مختلفة إلعطاء دليل يميز املتغيرات عن الكلمات املحجوزة‪.‬‬
‫ستبدأ بعد فترة بقراءة شيفرات برمجية مكتوبة بلغة بايثون‪ُ ،‬‬
‫وستميز بسرعة بين الكلمات املحجوزة‬
‫واملتغيرات‪.‬‬
‫‪ 13.2‬التنقيح‬
‫في هذه املرحلة ستواجه الخطأ القواعدي ً‬
‫غالبا بسبب تسمية متغير غير مسموح‪ ،‬مثل ‪ class‬و‪،yield‬‬
‫والتي تمثل كلمات مفتاحية‪ ،‬أو ‪ odd~job‬و‪ ،U$‬والتي تحوي ً‬
‫رموزا غير جائزة‪.‬‬
‫ً‬
‫إذا َوضعت فراغا في اسم متغير‪ ،‬فستعتقد لغة بايثون أنهما معامالن دون عامل‪:‬‬
‫‪>>> bad name = 5‬‬
‫‪SyntaxError: invalid syntax‬‬
‫‪>>> month = 09‬‬
‫‪File "<stdin>", line 1‬‬
‫‪month = 09‬‬
‫^‬
‫‪SyntaxError: invalid token‬‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪35‬‬
‫ً‬
‫عندما تواجهك األخطاء القواعدية‪ ،‬فرسالة الخطأ ال تساعد ً‬
‫شيوعا هي "أخطاء‬
‫كثيرا‪ .‬أكثر الرسائل‬
‫قواعدية لقواعد غير صالحة" (‪ ،)SyntaxError: invalid syntax‬و"أخطاء قواعدية لرموز غير‬
‫صالحة" (‪.)SyntaxError: invalid token‬‬
‫الخطأ الذي يرجح أن ترتكبه أثناء التشغيل )‪ (runtime error‬هو عند محاولتك استخدام متغي ٍر قبل‬
‫إسناده إلى قيمة‪.‬‬
‫ويحدث إذا َ‬
‫كتبت اسم املتغير بشكل خاطئ‪:‬‬
‫‪>>> principal = 327.68‬‬
‫‪>>> interest = principle * rate‬‬
‫‪NameError: name 'principle' is not defined‬‬
‫مع مراعاة أن أسماء املتغيرات حساسة لحالة األحرف‪ ،‬فعلى سبيل املثال ‪ LaTeX‬غير ‪.latex‬‬
‫ً‬
‫السبب األكثر احتماال لوقوعك في خطأ داللي )‪ (semantic error‬في هذه املرحلة هو ترتيب العمليات‪.‬‬
‫ً‬
‫فمثال إليجاد ‪ ،1/2π‬قد تكتب‪:‬‬
‫‪>>> 1.0 / 2.0 * pi‬‬
‫ً‬
‫لكن القسمة ستحدث أوال‪ ،‬لذلك تحصل على ‪ ،π/2‬وهي مختلفة عما كنت تقصده‪.‬‬
‫ال توجد طريقة ملعرفة ما كنت تقصد كتابته في لغة بايثون‪ ،‬لذلك لن تحصل على رسالة خطأ في هذه‬
‫الحال‪ ،‬بل ستحصل على إجابة خاطئة‪.‬‬
‫‪ 14.2‬فهرس املصطلحات‬
‫• اإلسناد (‪ :(assignment‬التعليمة التي تسند قيمة ملتغير‪.‬‬
‫• التجميع )‪ :(concatenate‬ضم معاملين ً‬
‫معا‪.‬‬
‫ٌ‬
‫معلومات توضيحية في البرنامج موجهة ألي مبرمج أو قارئ للشيفرة‬
‫• التعليق )‪:(comment‬‬
‫البرمجية بحيث ال تؤثر على تنفيذ الشيفرة‪.‬‬
‫• تقييم )‪ :(evaluate‬لتبسيط التعبير عبر إجراء العمليات بالترتيب للحصول على قيمة‬
‫واحدة‪.‬‬
‫• التعبير )‪ :(expression‬مجموعة من املتغيرات والعوامل والقيم التي تمثل قيمة نتيجة‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪36‬‬
‫واحدة‪.‬‬
‫ّ‬
‫العشرية )‪ :(floating point‬نوع بيانات يمثل األرقام ذات الفاصلة العشرية‪.‬‬
‫• الفاصلة‬
‫• العدد الصحيح )‪ :(integer‬نوع بيانات يمثل األعداد الصحيحة‪.‬‬
‫َ‬
‫ّ‬
‫مستخدمة من املترجم للتعامل مع البرنامج‬
‫املفتاحية )‪ :(keyword‬كلمة محجوزة‬
‫• الكلمة‬
‫(ال يمكنك استخدام كلمات مفتاحية مثل ‪ if‬و‪ def‬و‪ while‬كأسماء متغيرات)‪.‬‬
‫ّ‬
‫ً‬
‫وغالبا نستخدم أسماء متغيرات سهلة‬
‫• سهل التذكر )‪ :(mnemonic‬مساعدة الذاكرة‪،‬‬
‫ُ‬
‫التذكر لتساعدنا في تذكر ما خزن في املتغيرات‪.‬‬
‫• عامل باقي القسمة )‪ :(modulus operator‬عامل يشار إليه باإلشارة ‪ ،%‬يعمل مع األعداد‬
‫الصحيحة‪ ،‬وينتج الباقي عندما يكون الرقم مقسم على آخر‪.‬‬
‫• املعامل )‪ :(operand‬أحد القيم التي يعمل عليها العامل‪.‬‬
‫• العامل )‪ :(operator‬رمز خاص‪ ،‬ويمثل عملية حسابية بسيطة‪ ،‬كالجمع والضرب أو تجميع‬
‫سالسل نصية‪.‬‬
‫ّ‬
‫األولوية )‪ :(rules of precedence‬مجموعة من القواعد التي تحكم ترتيب التعابير‬
‫• قواعد‬
‫التي تشمل العديد من العوامل واملعامالت‪.‬‬
‫• التعليمة )‪ :(statement‬جزء من الشيفرة البرمجية التي تمثل ً‬
‫أمرا أو إجر ًاء‪ .‬التعليمات التي‬
‫رأيناها حتى اآلن هي تعليمة اإلسناد وتعليمة طباعة‪.‬‬
‫• السلسة ّ‬
‫النص ّية )‪ :(string‬نوع بيانات يمثل سلسلة من املحارف‪.‬‬
‫• نوع البيانات )‪ :(type‬تصنيف للقيم التي أيناها ً‬
‫سابقا‪ ،‬وهي ‪ int‬و‪ float‬و‪.string‬‬
‫ر‬
‫• القيمة )‪ :(value‬إحدى الوحدات األساسية للبيانات‪ ،‬مثل رقم أو سلسلة نصية ‪ ،‬التي تتغير‬
‫في البرنامج‪.‬‬
‫ّ‬
‫املتغير)‪ :(variable‬اسم يشير إلى قيمة‪.‬‬
‫•‬
‫الفصل الثاني‪ :‬املتغيرات والتعابير والتعليمات‬
‫‪37‬‬
‫‪ 15.2‬تمارين‬
‫ً‬
‫ً‬
‫برنامجا يستخدم دخال ‪ input‬لتوجيه أمر للمستخدم لكتابة اسمه‬
‫• التمرين األول‪ :‬اكتب‬
‫والترحيب به كما يلي‪:‬‬
‫‪Enter your name: Chuck‬‬
‫‪Hello Chuck‬‬
‫ً‬
‫برنامجا يسمح للمستخدم بإدخال ساعات ومعدل األجر لحساب‬
‫• التمرين الثاني‪ :‬اكتب‬
‫الراتب اإلجمالي كما يلي‪:‬‬
‫‪Enter Hours: 35‬‬
‫‪Enter Rate: 2.75‬‬
‫‪Pay: 96.25‬‬
‫ال داعي للقلق في حال تجاوزت قيمة الراتب ‪ pay‬رقمين بعد الفاصلة العشرية‪.‬‬
‫َّ‬
‫املضمن في لغة بايثون لتقريب الراتب الناتج إلى منزلتين عشريتين‪.‬‬
‫بإمكانك باستخدام تابع التقريب‬
‫• التمرين الثالث‪ :‬على فرض أننا ننفذ تعليمات اإلسناد التالية‪:‬‬
‫‪width = 17‬‬
‫‪height = 12.0‬‬
‫اكتب قيمة التعبير ونوع بيانات والناتج لكل من التعابير التالية‪:‬‬
‫‪o width//2‬‬
‫‪o width/2.0‬‬
‫‪o height/3‬‬
‫‪o 1+2*5‬‬
‫استخدم مفسر بايثون للتحقق من إجابتك‪.‬‬
‫ً‬
‫برنامجا يطلب من املستخدم إدخال قيمة درجة الحرارة لتحويلها من‬
‫• التمرين الرابع‪ :‬اكتب‬
‫درجة مئوية (سيليسيوس) إلى فهرنهايت‪ ،‬واطبع نتيجة التحويل‪.‬‬
‫الفصل الثالث‬
‫التنفيذ الشرطي‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪39‬‬
‫ّ‬
‫ّ‬
‫الش ّ‬
‫رطي‬
‫‪ 3‬التنفيذ‬
‫ّ‬
‫ّ‬
‫املنطقية‬
‫‪ 1.3‬التعابير‬
‫ً‬
‫ُيعرف التعبير املنطقي بأنه ٌ‬
‫محققا ‪ ،True‬أو خاطئة ‪ .False‬يوضح‬
‫قيمة واحدة فقط‪ ،‬إما‬
‫تعبير ذو ٍ‬
‫َ‬
‫املثال التالي وظيفة العامل ==‪ ،‬والذي ُيقارن بين معاملين‪ ،‬ويقرر إذا ما كانت هذه العملية ‪ True‬أم‬
‫‪.False‬‬
‫‪>>> 5 == 5‬‬
‫‪True‬‬
‫‪>>> 5 == 6‬‬
‫‪False‬‬
‫تجدر اإلشارة إلى أن ‪ True‬و‪ False‬قيمتان خاصتان تنتميان لصنف القيمة املنطقية ‪ ،class bool‬أي‬
‫أنهما َ‬
‫ليستا سلسلتين نصيتين )‪ ،)strings‬ويمكنك مالحظة ذلك من خالل املثال التالي‪:‬‬
‫)‪>>>type (True‬‬
‫>'‪<class 'bool‬‬
‫)‪>>>type (False‬‬
‫>'‪<class 'bool‬‬
‫ُيعد العامل == أحد عوامل املقارنة التي يمكن تلخصيها كما يلي‪:‬‬
‫‪ x‬ال يساوي ‪y‬‬
‫‪x!=y‬‬
‫‪ x‬أكبر ً‬
‫تماما من ‪y‬‬
‫‪x>y‬‬
‫‪ x‬أصغر ً‬
‫تماما من ‪y‬‬
‫‪x<y‬‬
‫‪ x‬أكبر أو يساوي ‪y‬‬
‫‪x >= y‬‬
‫‪ x‬أصغر أو يساوي ‪y‬‬
‫‪x<= y‬‬
‫‪ x‬مثل ‪y‬‬
‫‪x is y‬‬
‫‪ x‬ليس مثل ‪y‬‬
‫‪x is not y‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪40‬‬
‫على الرغم من أن هذه العمليات قد تكون مألوفة لك‪ ،‬إال أن الرموز املستخدمة في لغة بايثون تختلف‬
‫ً‬
‫عن الرموز الرياضية لنفس العمليات‪ .‬على سبيل املثال‪ُ ،‬يعتبر استخدام عالمة مساواة واحدة = بدال‬
‫من عالمة مساواة مزدوجة == من األخطاء الشائعة التي قد يقع فيها املبرمج‪ ،‬وذلك ألن عالمة املساواة‬
‫ُ‬
‫ُ‬
‫الواحدة = تعتبر عامل إسناد‪ ،‬بينما تعتبر عالمة املساواة املزدوجة == عامل مقارنة‪ ،‬كما أنه ال وجود‬
‫لرمز كهذا <= أو هذا <= في لغة بايثون‪.‬‬
‫ّ‬
‫املنطقية‬
‫‪ 2.3‬العوامل‬
‫توجد ثالثة عوامل منطقية في لغة بايثون‪ ،‬وهي‪ and :‬و‪ or‬و ‪ ،not‬وتشابه معاني هذه العوامل في لغة‬
‫بايثون معانيها في اللغة اإلنجليزية‪ ،‬فعلى سبيل املثال‪ُ ،‬تعتبر هذه التعابير َّ‬
‫محققة فقط إذا كانت قيمة‬
‫تماما من ‪ 0‬وأصغر ً‬
‫‪ x‬أكبر ً‬
‫تماما من ‪.10‬‬
‫‪x > 0 and x < 10‬‬
‫أما التعبير‪:‬‬
‫‪n%2 == 0 or n%3 == 0‬‬
‫َّ ً‬
‫ُّ‬
‫ُ‬
‫أي من الشرطين‪ ،‬سواء كان العدد يقبل القسمة على ‪ 2‬أو ‪.3‬‬
‫فيعتبر محققا أي ‪ True‬في حال تحقق ٍ‬
‫ً‬
‫فمثال ُيعتبر )‪َّ not (x > y‬‬
‫ً‬
‫محق ًقا ‪ True‬إذا‬
‫أخيرا‪ُ ،‬يستخدم عامل النفي ‪ not‬لنفي التعابير املنطقية‪،‬‬
‫كان ‪ x > y‬غير َّ‬
‫محقق ‪ ،False‬أي إذا كان ‪ x‬أقل من أو يساوي ‪.y‬‬
‫باملعنى الدقيق للكلمة‪ ،‬يجب أن تكون معامالت العوامل املنطقية عبارة عن تعبيرات منطقية‪ ،‬لكن‬
‫ُ‬
‫لغة بايثون ليست صارمة للغاية؛ إذ تفسر أي رقم غير صفري على أنه ‪.True‬‬
‫‪>>> 17 and True‬‬
‫‪True‬‬
‫قد تكون هذه املرونة مفيدة‪ ،‬إال أن بعض التفاصيل الدقيقة قد تكون مربكة‪ ،‬ومن األفضل تجنبها‬
‫حتى تتأكد من أنك تعرف ما تفعله‪.‬‬
‫ّ‬
‫‪ 3.3‬التنفيذ املشروط‬
‫حقق من الشروط وتغيير سلوك البرنامج ً‬
‫دوما إلى الت ُّ‬
‫من أجل كتابة برامج مفيدة‪ ،‬نحتاج ً‬
‫وفقا لذلك‪،‬‬
‫ُ‬
‫وتستخدم العبارات الشرطية لهذا الغرض‪.‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪41‬‬
‫يوضح املثال التالي أبسط صيغة لعبارة ‪ if‬الشرطية‪:‬‬
‫‪if x > 0 :‬‬
‫)'‪print('x is positive‬‬
‫ُ‬
‫ُيسمى التعبير املنطقي بعد عبارة ‪ if‬بالشرط‪ .‬تنتهي تعليمة ‪ if‬برمز النقطتين ‪ ،:‬وتضاف مسافة بادئة‬
‫قبل األسطر البرمجية التي ستنفذ في حال ُّ‬
‫تحقق الشرط في تعليمة ‪( if‬بمقدار ‪ 4‬فراغات أو‬
‫باستخدام مفتاح ‪ tap‬في لوحة املفاتيح) للداللة على أنها تنتمي إلى بنية ‪ if‬الشرطية‪.‬‬
‫الشكل ‪ :5‬آلية عمل ‪ if‬الشرطية‬
‫ُ‬
‫إذا كان الشرط املنطقي َّ‬
‫محق ًقا‪ ،‬فست َّنفذ التعليمات ذات املسافة البادئة (‪،)indented statement‬‬
‫أما إذا كان الشرط املنطقي غير َّ‬
‫محقق‪ ،‬فسيتم تجاهل تلك التعليمات‪.‬‬
‫تملك عبارة ‪ if‬الشرطية نفس البنية لتعاريف التوابع (‪ )functions‬أو حلقات ‪for‬؛ إذ تتكون عبارة ‪if‬‬
‫ً‬
‫متبوعا بمجموعة تعليمات ذات مسافة بادئة‪.‬‬
‫الشرطية من سطر أساس ي ينتهي برمز النقطتين ‪:‬‬
‫تسمى مثل هذه العبارات بالعبارات املركبة ألنها تتكون من أكثر من سطر‪.‬‬
‫ٌ‬
‫َ‬
‫حد أعلى لعدد التعليمات‪ .‬من‬
‫يجب أن تلي ‪ if‬تعليمة واحدة ذات مسافة بادئة على األقل‪ ،‬وما من ٍ‬
‫ً‬
‫املفيد في بعض األحيان أال تضع تعليمات ذات مسافة بادئة بعد عبارة ‪( if‬عادة ما تكون بمثابة بديل‬
‫عن شيفرة برمجية لم تكتبها بعد)‪ .‬في هذه الحالة‪ ،‬يمكنك استخدام تعليمة ‪ pass‬التي ال تفعل ً‬
‫شيئا‪،‬‬
‫كما في املثال التالي‪:‬‬
‫‪if x < 0 :‬‬
‫!‪pass # need to handle negative values‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪42‬‬
‫إذا كتبت عبارة ‪ if‬في ُم َفسر لغة بايثون‪ ،‬فسيتغير رمز بداية األسطر البرمجية من ثالث عالمات على‬
‫شكل حرف ‪ v‬مقلوب >>>‪ ،‬أو ما ُيعرف باسم شارة تلقين األوامر‪ ،‬إلى ثالث نقاط … لإلشارة إلى أنك‬
‫ضمن مجموعة التعليمات الخاصة بعبارة ‪ ،if‬كما هو موضح أدناه‪:‬‬
‫‪>>> x = 3‬‬
‫‪>>> if x < 10:‬‬
‫‪...‬‬
‫)'‪print('Small‬‬
‫‪...‬‬
‫‪Small‬‬
‫>>>‬
‫ُ‬
‫ً‬
‫ً‬
‫سطرا فارغا في نهاية كتلة التعليمات‪ ،‬وإال سترجع‬
‫عند استخدام مفسر لغة بايثون‪ ،‬يجب أن تترك‬
‫ًّ ً‬
‫قواعديا بدال من تنفيذ تلك األسطر البرمجية‪ ،‬كما هو موضح في املثال التالي‪:‬‬
‫لغة بايثون خطأ‬
‫‪>>> x = 3‬‬
‫‪>>> if x < 10:‬‬
‫)'‪print('Small‬‬
‫)'‪print('Done‬‬
‫‪...‬‬
‫‪...‬‬
‫‪File "<stdin>", line 3‬‬
‫)'‪print('Done‬‬
‫^‬
‫‪SyntaxError: invalid syntax‬‬
‫ًّ‬
‫ضروريا عند كتابة وتنفيذ نص‬
‫تجدر اإلشارة إلى أن كتابة سطر فارغ في نهاية كتلة التعليمات ليس‬
‫برمجي (‪ ،)script‬ولكنه قد يحسن قابلية قراءة شيفرتك‪.‬‬
‫ّ‬
‫‪ 4.3‬التنفيذ البديل‬
‫ُ‬
‫الشكل الثاني من تعليمة ‪ if‬هو التنفيذ البديل‪ ،‬حيث يوجد احتماالن‪ ،‬ويحدد الشرط أيهما ُينفذ‪.‬‬
‫تبدو بنية الجملة كما في املثال التالي‪:‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪43‬‬
‫‪if x%2 == 0 :‬‬
‫)'‪print('x is even‬‬
‫‪else :‬‬
‫)'‪print('x is odd‬‬
‫صفرا‪ ،‬فإن ‪ٌ x‬‬
‫عدد ٌّ‬
‫كما هو معلوم‪ ،‬إذا كان باقي قسمة العدد ‪ x‬على ‪ 2‬يساوي ً‬
‫زوجي‪ ،‬ويعرض البرنامج‬
‫ُ‬
‫رسالة بهذا املعنى‪ .‬أما إذا كان الشرط غير َّ‬
‫محقق‪ ،‬فست َّنفذ املجموعة الثانية من التعليمات‪ ،‬وهي‬
‫عرض رسالة تقول إن ‪ٌ x‬‬
‫عدد ٌّ‬
‫فردي‪.‬‬
‫الشكل ‪ : 6‬آلية عمل بنية ‪if - else‬‬
‫ُ‬
‫ُ‬
‫محق ًقا أو غير َّ‬
‫نظرا ألن الشرط يجب أن يكون إما َّ‬
‫ً‬
‫محقق‪ ،‬فست َنفذ إحدى البدائل فقط‪ ،‬وتسمى‬
‫البدائل بالفروع؛ ألنها فروع في املسار التنفيذي للبرنامج‪.‬‬
‫ّ‬
‫‪ 5.3‬الشروط املتسلسلة‬
‫قد يكون هناك أكثر من احتمالين في بعض األحيان‪ ،‬وعندها سنحتاج إلى أكثر من فرعين‪ .‬في هذه‬
‫الحالة‪ ،‬إحدى الطرق املستخدمة هي التعبير الشرطي املتسلسل‪ ،‬كما في املثال التالي‪:‬‬
‫‪if x < y:‬‬
‫)'‪print ('x is less than y‬‬
‫‪elif x > y:‬‬
‫)'‪print ('x is greater than y‬‬
‫‪else:‬‬
‫)'‪print ('x and y are equal‬‬
‫‪ elif‬هو اختصار لعبارة "‪ ."else if‬مرة أخرى‪ُ ،‬‬
‫سي َّنفذ فرع واحد بالتحديد‪.‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪44‬‬
‫حد لعدد عبارات ‪ elif‬الشرطية‪ ،‬وإذا كان هناك بند يحتوي على عبارة ‪ ،else‬فيجب أن يكون‬
‫ما من ٍ‬
‫في النهاية‪ ،‬ولكن ليس من الضروري أن يوجد‪.‬‬
‫‪if choice == 'a':‬‬
‫)'‪print ('Bad guess‬‬
‫‪elif choice == 'b':‬‬
‫)'‪print ('Good guess‬‬
‫‪elif choice == 'c':‬‬
‫)'‪print ('Close, but not correct‬‬
‫الشكل ‪ :7‬بنية ‪if – elif‬‬
‫ُيوضح املثال أعاله أن كل شرط ُيفحص بالترتيب‪ .‬إذا كان الشرط األول غير َّ‬
‫عندئذ ُيفحص‬
‫محقق‪،‬‬
‫ٍ‬
‫ٌ‬
‫الشرط التالي‪ ،‬وهكذا دواليك‪ .‬إذا َّ‬
‫شرط ما‪ُ ،‬‬
‫فسي َّنفذ الفرع املقابل له‪ ،‬وتنتهي العبارة‪ .‬حتى لو‬
‫تحقق‬
‫َّ َ‬
‫َّ‬
‫تحقق أكثر من شرط واحد‪ُ ،‬‬
‫تحقق شرطه فقط‪.‬‬
‫سي َّنفذ أول فرع‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪45‬‬
‫ّ‬
‫‪ 6.3‬الشروط املتداخلة‬
‫من املمكن ً‬
‫أيضا أن يتداخل أحد الشرطين مع اآلخر‪ .‬فعلى سبيل املثال‪ ،‬كان بإمكاننا كتابة مثال‬
‫الفروع الثالثة السابق بهذا الشكل‪:‬‬
‫‪if x == y:‬‬
‫)'‪print ('x and y are equal‬‬
‫‪else:‬‬
‫‪if x < y:‬‬
‫)'‪print ('x is less than y‬‬
‫‪else:‬‬
‫)'‪print ('x is greater than y‬‬
‫نالحظ من املثال أعاله أن الشرط الخارجي يحتوي على فرعين‪ .‬يحتوي الفرع األول على تعليمة‬
‫بسيطة‪ ،‬بينما يحتوي الفرع الثاني على عبارة ‪ if‬شرطية أخرى تملك فرعين خاصين بها‪ .‬يحتوي هذان‬
‫الفرعان على تعليمات بسيطة ً‬
‫أيضا‪ ،‬على الرغم من أنه كان من املمكن أن تكون عبارات شرطية‬
‫مستقلة‪.‬‬
‫ً‬
‫واضحا‪ ،‬إال أنه من الصعب قراءة‬
‫على الرغم من أن إزاحة التعليمات تجعل هيكل الشروط املتداخلة‬
‫عموما‪ ،‬من الجيد ُّ‬
‫ً‬
‫تجنب استخدام الشروط املتداخلة قدر اإلمكان‪.‬‬
‫الشروط املتداخلة بسهولة‪.‬‬
‫توفر العوامل املنطقية طريقة لتبسيط العبارات الشرطية املتداخلة‪ .‬فعلى سبيل املثال‪ ،‬يمكننا‬
‫إعادة كتابة الشيفرة البرمجية التالية باستخدام شرط واحد فقط‪.‬‬
‫‪if 0 < x:‬‬
‫‪if x < 10:‬‬
‫)'‪print('x is a positive single-digit number.‬‬
‫تنفذ فقط إذا َّ‬
‫بما أن تعليمة ‪َّ print‬‬
‫تحقق الشرطان السابقان لها‪ ،‬فيمكننا الحصول على نفس‬
‫النتيجة باستخدام العامل املنطقي ‪ ،and‬كما في املثال التالي‪:‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪46‬‬
‫الشكل ‪ : 8‬البنية الشرطية املتداخلة‬
‫‪if 0 < x and x < 10:‬‬
‫)'‪print ('x is a positive single-digit number.‬‬
‫ّ‬
‫‪ 7.3‬التعامل مع االستثناء باستخدام بنية ‪ try‬و‪except‬‬
‫ً‬
‫مقطعا من شيفرة برمجية‪ ،‬حيث استخدمنا تابعي ‪ input‬و‪ int‬لقراءة وتمرير‬
‫رأينا في وقت سابق‬
‫رقم صحيح أدخله املستخدم‪ ،‬ورأينا ً‬
‫ً‬
‫خادعا‪ ،‬كما في املثال‬
‫أيضا كيف يمكن أن يكون القيام بذلك‬
‫التالي‪:‬‬
‫"‪>>> prompt = "What is the air velocity of an unladen swallow?\n‬‬
‫)‪>>> speed = input(prompt‬‬
‫?‪What is the air velocity of an unladen swallow‬‬
‫?‪What do you mean, an African or a European swallow‬‬
‫)‪>>> int(speed‬‬
‫‪ValueError: invalid literal for int() with base 10:‬‬
‫>>>‬
‫ُ‬
‫عندما ننفذ هذه التعليمات في ُمفسر لغة بايثون‪ ،‬نحصل على موجه أوامر جديد من املفسر‪،‬‬
‫ونصاب بالحيرة‪ ،‬وننتقل إلى التعليمة التالية‪ ،‬ولكن إذا قمت بوضع هذه الشيفرة في ُمحرر نصوص‬
‫خاص ببايثون وحدث هذا الخطأ‪ ،‬فإن النص البرمجي سيتوقف ً‬
‫فورا‪ ،‬وسيعرض رسالة تقرير‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪47‬‬
‫باألخطاء‪ ،‬ولن ُينفذ التعليمات التالية‪ .‬فيما يلي مثال لبرنامج ُيحول درجة حرارة من وحدة الفهرنهايت‬
‫إلى درجة حرارة مئوية‪:‬‬
‫)' ‪inp = input ('Enter Fahrenheit Temperature:‬‬
‫)‪fahr = float(inp‬‬
‫‪cel = (fahr - 32.0) * 5.0 / 9.0‬‬
‫)‪print(cel‬‬
‫‪# Code: http://www.py4e.com/code3/fahren.py‬‬
‫ً‬
‫إذا نفذنا هذا البرنامج‪ ،‬وأدخلنا ُمدخال غير مسموح به‪ ،‬فلن ُي َّنفذ ذلك البرنامج ببساطة‪ ،‬وستظهر‬
‫لنا رسالة الخطأ‪:‬‬
‫‪python fahren.py‬‬
‫‪Enter Fahrenheit Temperature:72‬‬
‫‪22.22222222222222‬‬
‫‪python fahren.py‬‬
‫‪Enter Fahrenheit Temperature:fred‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "fahren.py", line 2, in <module‬‬
‫)‪fahr = float(inp‬‬
‫'‪ValueError: could not convert string to float: 'fred‬‬
‫توجد بنية تنفيذ شرطية ُمضمنة في لغة بايثون‪ ،‬تسمى بنية ‪ ،try/except‬ومهمتها التعامل مع األخطاء‬
‫املتوقعة وغير املتوقعة‪ .‬تكمن فكرة ‪ try/except‬في أنها تسمح للمبرمج بإضافة بعض التعليمات‬
‫(‪ُ )except block‬لت َّنفذ في حالة حدوث مشاكل في التنفيذ التسلسلي للبرنامج‪ .‬وفي حالة عدم وجود‬
‫ُ‬
‫خطأ في تنفيذ البرنامج‪ ،‬فإن تلك الكتلة من التعليمات ال ت َّنفذ‪ ،‬أو بمعنى آخر يتم تجاهلها‪.‬‬
‫يمكنك أن تشبه خاصية ‪ try/except‬في بايثون بسياسة الضمان للتنفيذ التسلسلي للتعليمات‪.‬‬
‫باالستفادة من هذه الخاصية‪ ،‬يمكننا إعادة كتابة برنامج تحويل درجة الحرارة من الفهرنهايت إلى‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪48‬‬
‫الدرجة املئوية بالشكل التالي‪:‬‬
‫)'‪inp = input ('Enter Fahrenheit Temperature:‬‬
‫‪try:‬‬
‫)‪fahr = float(inp‬‬
‫‪cel = (fahr - 32.0) * 5.0 / 9.0‬‬
‫)‪print(cel‬‬
‫‪except:‬‬
‫)'‪print('Please enter a number‬‬
‫‪# Code: http://www.py4e.com/code3/fahren2.py‬‬
‫َّ‬
‫يبدأ البايثون في تنفيذ التعليمات الخاصة بكتلة ‪ ،try‬فإن سار كل ش يء كما هو مخطط له‪ ،‬عندئذ‬
‫ستتتجاهل بايثون مجموعة التعليمة املوجودة في كتلة ‪ .except‬أما لو حدث خطأ ما‪ ،‬فسوف َّ‬
‫تنفذ‬
‫التعليمات املوجودة في كتلة ‪ ،except‬أي أن البايثون سيقفز من كتلة ‪ try‬إلى كتلة ‪.except‬‬
‫موضح في املثال التالي‪ :‬في الجزء األول‪ ،‬يدخل املستخدم رقم ‪ ،72‬وهو رقم مقبول‪ ،‬لذا َّ‬
‫كما هو َّ‬
‫ستنفذ‬
‫التعليمة الخاصة بتحويل درجة الحرارة‪ .‬أما في الجزء الثاني‪ُ ،‬يدخل املستخدم سلسلة من الحروف‬
‫ً‬
‫بدال من إدخال عدد‪ ،‬وهذا غير مقبول‪ ،‬لذا َّ‬
‫تنفذ التعليمة املوجودة في كتلة تعليمات ‪،except‬‬
‫‪fred‬‬
‫وهي )'‪.print ('please enter a number‬‬
‫‪python fahren2.py‬‬
‫‪Enter Fahrenheit Temperature:72‬‬
‫‪22.22222222222222‬‬
‫‪python fahren2.py‬‬
‫‪Enter Fahrenheit Temperature:fred‬‬
‫‪Please enter a number‬‬
‫ُ‬
‫تعرف عملية التعامل مع االستثناء )‪ (exception‬باستخدام تعليمة ‪ try‬بالتقاط االستثناء ( ‪catching‬‬
‫‪ .)an exception‬في املثال السابق‪ ،‬تظهر تعليمات كتلة ‪ except‬رسالة خطأ‪.‬‬
‫بشكل عام‪ ،‬تمنحك خاصية التقاط االستثناء فرصة إلصالح املشكلة‪ ،‬أو املحاولة مرة أخرى‪ ،‬أو على‬
‫األقل إنهاء البرنامج بأمان‪.‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪49‬‬
‫ّ‬
‫ّ ُّ‬
‫ّ‬
‫املنطقية‬
‫‪ 8.3‬تجاوزالتحقق من التعابير‬
‫ًّ‬
‫عندما ُيعالج ُمفسر لغة بايثون ً‬
‫منطقيا‪ ،‬مثل ‪ ،x >= 2 and (x/y) > 2‬فإنه يفحص التعبير‬
‫تعبيرا‬
‫املنطقي من اليسار إلى اليمين‪ .‬وبما أن العامل املنطقي هو ‪ ،and‬فإذا كانت ‪ x‬أقل من ‪ ،2‬فإن التعبير‬
‫ُ‬
‫‪ x >= 2‬يكون غير َّ‬
‫محقق ‪ ،False‬وبالتالي فإن التعبير بأكمله يكون ‪ False‬بغض النظر عما إذا قي َمت‬
‫‪ (x / y)> 2‬كـ ‪ True‬أو ‪.False‬‬
‫عندما يكتشف ُمفسر لغة بايثون أنه ما من حاجة لتقييم بقية التعبير املنطقي‪ ،‬فإنه يتوقف عن‬
‫ُ‬
‫تقييمه‪ ،‬وال ُيجري الحسابات الخاصة ببقية التعبير املنطقي‪ .‬تعرف العملية التي تجعل ُمفسر لغة‬
‫بايثون يتوقف عن تقييم التعبير املنطقي ألن القيمة اإلجمالية معروفة بالفعل باسم تجاوز التحقق‬
‫من التعابير املنطقية (‪.)short-circuiting the evaluation‬‬
‫في حين أن هذه العملية قد تبدو وكأنها خاصية جيدة‪ ،‬فإن سلوك تجاوز الت ُّ‬
‫حقق من التعابير‬
‫املنطقية يؤدي إلى أسلوب ذكي في البرمجة‪ ،‬يسمى نمط الحماية من األخطاء (‪.)guardian pattern‬‬
‫لتوضيح ذلك‪ ،‬الحظ تسلسل الشيفرة التالية في ُمفسر لغة بايثون‪:‬‬
‫‪>>> x = 6‬‬
‫‪>>> y = 2‬‬
‫‪>>> x >= 2 and (x/y) > 2‬‬
‫‪True‬‬
‫‪>>> x = 1‬‬
‫‪>>> y = 0‬‬
‫‪>>> x >= 2 and (x/y) > 2‬‬
‫‪False‬‬
‫‪>>> x = 6‬‬
‫‪>>> y = 0‬‬
‫‪>>> x >= 2 and (x/y) > 2‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫‪ZeroDivisionError: division by zero‬‬
‫\>>>‬
‫في املثال أعاله‪ ،‬فشلت العملية الحسابية الثالثة‪ ،‬والسبب أنه أثناء تقييم ُمفسر لغة بايثون للعملية‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪50‬‬
‫الحسابية ‪ُ ،(x/y) > 2‬وجد أن ‪ ،y = 0‬مما َّ‬
‫تسبب بحدوث خطأ أثناء التشغيل (‪ .)runtime error‬لكن‬
‫ُ‬
‫ُ‬
‫املثالين األول والثاني نفذا بنجاح‪ ،‬فالجزء األول من هذه التعبيرات ‪ x> = 2‬قيم كـ ‪ False‬في املثال‬
‫الثاني‪ ،‬لذا فإن (‪ )x/y‬لم ُي َّنفذ على اإلطالق بسبب قاعدة اختصار التقييم ولم يكن هناك خطأ‪.‬‬
‫يمكننا بناء التعبير املنطقي لوضع نمط الحماية من األخطاء بشكل استراتيجي قبل التقييم مباشرة‬
‫والذي قد يتسبب في حدوث خطأ بالشكل التالي‪:‬‬
‫‪>>> x = 1‬‬
‫‪>>> y = 0‬‬
‫‪>>> x >= 2 and y != 0 and (x/y) > 2‬‬
‫‪False‬‬
‫‪>>> x = 6‬‬
‫‪>>> y = 0‬‬
‫‪>>> x >= 2 and y != 0 and (x/y) > 2‬‬
‫‪False‬‬
‫‪>>> x >= 2 and (x/y) > 2 and y != 0‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫‪ZeroDivisionError: division by zero‬‬
‫>>>‬
‫في املثال أعاله‪ ،‬نالحظ في التعبير املنطقي األول أن الشرط املنطقي ‪ ،x >= 2‬ولكن قيمة ‪ x‬تساوي ‪،1‬‬
‫لذا فعبارة الشرط املنطقي غير َّ‬
‫محققة ‪ ،False‬فلن يقيم ُمفسر لغة بايثون الجزء الثاني من الشرط‬
‫املنطقي ‪ )x/y(>2‬بسبب عدم تحقق الجزء األول من الشرط املنطقي ‪ ،x >= 2‬أي سيتوقف ُمفسر‬
‫لغة بايثون عند عبارة ‪ .and‬أما في التعبير املنطقي الثاني‪ ،‬فالجزء األول ‪ x >= 2‬محقق ‪ ،True‬ولكن‬
‫الجزء الثاني من الشرط املنطقي ‪ y != 0‬غير محقق ‪ ،False‬لذلك فلن يقيم ُمفسر لغة بايثون الجزء‬
‫الثالث من الشرط املنطقي ‪ .)x/y(>2‬وفي التعبير املنطقي الثالث‪ ،‬نالحظ أن الشرط ‪ y != 0‬أتى بعد‬
‫حساب (‪ ،)x/y‬لذلك يفشل تنفيذ هذه التعليمات‪ ،‬وتظهر لنا رسالة خطأ بسبب القسمة على الصفر‪.‬‬
‫خالصة األمر‪ ،‬في التعبير الثاني يمكننا أن نقول إن ‪ y != 0‬تعمل كتعليمة حماية للتأكد من أننا ننفذ‬
‫(‪ )x/y‬فقط‪ ،‬إذا كانت قيمة ‪ y‬غير صفرية‪.‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪51‬‬
‫ّ‬
‫‪ 9.3‬التنقيح‬
‫ُي َ‬
‫عرض تقرير بالخطأ عند حدوث خطأ ما‪ .‬يحتوي هذا التقرير على الكثير من املعلومات‪ ،‬ولكن هذه‬
‫ً‬
‫املعلومات قد تكون كثيرة لدرجة ال يقدر املبرمج على استيعابها‪ .‬عادة ما تكون األجزاء األكثر فائدة في‬
‫هذ املعلومات هي‪:‬‬
‫• ماهية الخطأ الذي حدث‪.‬‬
‫• في أي جزء من الشيفرة حدث ذلك الخطأ‪.‬‬
‫عادة ما يكون من السهل العثور على األخطاء القواعدية‪ ،‬إال أن بعض التفاصيل قد تكون مضللة؛‬
‫إذ يمكن أن تكون أخطاء املسافات الفارغة )‪ (Whitespace‬خادعة ألن الفراغات واملسافة ‪ tap‬غير‬
‫مرئية ونحن معتادون على تجاهلها‪ ،‬كما في املثال التالي‪:‬‬
‫‪>>> x = 5‬‬
‫‪>>> y = 6‬‬
‫‪File "<stdin>", line 1‬‬
‫‪y=6‬‬
‫^‬
‫‪IndentationError: unexpected indent‬‬
‫في هذا املثال‪ ،‬تكمن املشكلة في أن السطر الثاني يحتوي على مسافة بادئة بمسافة واحدة‪ .‬لكن رسالة‬
‫الخطأ تشير إلى ‪ ،y‬وهذ أمر مضلل‪ .‬بشكل عام‪ ،‬تشير رسائل الخطأ إلى مكان اكتشاف املشكلة‪ ،‬ولكن‬
‫ً‬
‫وأحيانا في السطر السابق للتعليمة التي‬
‫الخطأ الفعلي قد يكون حدث في مكان سابق في التعليمة‪،‬‬
‫يشير الخطأ إليها‪ .‬بشكل عام‪ ،‬تخبرك رسائل الخطأ حول مكان اكتشاف املشكلة‪ ،‬ولكن ً‬
‫غالبا ال يكون‬
‫هذا هو املكان الذي حدثت فيه املشكلة بالضبط‪.‬‬
‫‪ 10.3‬فهرس املصطلحات‬
‫ّ‬
‫• جسم التعليمة (‪ :)body‬تسلسل التعليمات ضمن تعليمة مركبة‪.‬‬
‫ّ‬
‫ّ‬
‫املنطقي (‪ :)Boolean expression‬هو تعبير قيمته الصواب أو الخطأ ( ‪True or‬‬
‫• التعبير‬
‫‪.)False‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪52‬‬
‫• الفرع (‪ :)branch‬هو إحدى التعليمات املتسلسلة البديلة في العبارات الشرطية‪.‬‬
‫ّ‬
‫الش ّ‬
‫رطية املتسلسلة (‪ :)chained conditional‬هي العبارات الشرطية التي‬
‫• العبارات‬
‫تحتوي على مجموعة من الفروع التسلسلية‪.‬‬
‫• عامل املقارنة (‪ :)comparison operator‬هو أحد العوامل املنطقية التي تقارن بين قيم‬
‫معامالتها‪ ،‬مثل‪ == :‬أو > أو <‪.‬‬
‫ّ‬
‫الش ّ‬
‫رطية (‪ :)conditional statement‬هي العبارة التي تتحكم في تسلسل تنفيذ‬
‫• العبارة‬
‫ً‬
‫اعتمادا على شرط ما‪.‬‬
‫التعليمات‬
‫ّ‬
‫• الشرط (‪ :)condition‬هو التعبير املنطقي املوجود في العبارات الشرطية‪ ،‬والذي يحدد أي‬
‫من الفروع ُ‬
‫سي َّنفذ‪.‬‬
‫ّ‬
‫• العبارات املركبة (‪ :)compound statement‬هي العبارات التي تتكون من جزأين‪ :‬سطر‬
‫أساس ي‪ ،‬وكتلة تعليمات تابعة له‪ .‬تكتب عالمة النقتطين ‪ :‬في نهاية السطر األساس ي‪ ،‬بينما‬
‫ُ‬
‫تزاح تعليمات الكتلة بمسافة بادئة لتشير إلى ارتباطها بالسطر األساس ي‪.‬‬
‫• نمط الحماية من األخطاء (‪ :)guardian pattern‬هو النمط الذي ينتج عند كتابة تعبير‬
‫منطقي يحتوي على مقارنات إضافية لالستفادة من خاصية تجاوز التحقق من التعابير‬
‫املنطقية‪.‬‬
‫ّ‬
‫منطقي (‪ :)logical operator‬أحد العوامل التي تجمع بين التعابير املنطقية‪ ،‬مثل‪:‬‬
‫• عامل‬
‫‪AND‬أو ‪ OR‬أو ‪. NOT‬‬
‫ّ‬
‫الش ّ‬
‫رطية املتداخلة (‪ :)nested conditional‬عبارة شرطية تظهر في أحد فروع‬
‫• العبارات‬
‫جملة شرطية أخرى‪.‬‬
‫ُ‬
‫ُ‬
‫• عرض تقريربالخطأ )‪ :(Traceback‬قائمة بالتوابع التي ت َّنفذ وتطبع عند حدوث استثناء‪.‬‬
‫ّ‬
‫ّ ُّ‬
‫ّ‬
‫املنطقية (‪ :)short circuit‬يقصد بها العملية التي يتوقف فيها‬
‫• تجاوز التحقق من التعابير‬
‫مفسر لغة بايثون عن تقييم تعبير منطقي ما ألن القيمة النهائية للتعبير املنطقي معروفة‬
‫ً‬
‫سلفا دون الحاجة لتقييم بقية أجزاء التعبير املنطقي‪.‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪53‬‬
‫‪ 11.3‬تمارين‬
‫• التمرين األول‪ :‬اكتب برنامج لحساب الراتب ملنح املوظف ‪ 1.5‬ضعف سعر الساعة بالنسبة‬
‫لساعات العمل التي تزيد عن ‪ 40‬ساعة‪.‬‬
‫‪Enter Hours: 45‬‬
‫‪Enter Rate: 10‬‬
‫‪Pay: 475.0‬‬
‫• التمرين الثاني‪ :‬أعد كتابة برنامج حساب الراتب باستخدام ‪ try /except‬بحيث يتعامل‬
‫البرنامج مع املدخالت غير الرقمية بشكل آمن عن طريق طباعة رسالة خطأ والخروج من‬
‫البرنامج‪ .‬املثال التالي يوضح عمليتي تنفيذ للبرنامج‪:‬‬
‫‪Enter Hours: 20‬‬
‫‪Enter Rate: nine‬‬
‫‪Error, please enter numeric input‬‬
‫‪Enter Hours: forty‬‬
‫‪Error, please enter numeric input‬‬
‫ً‬
‫برنامجا اطلب فيه إدخال درجة تتراوح بين ‪ 0.0‬و‪ .1.0‬في حال كانت‬
‫• التمرين الثالث‪ :‬اكتب‬
‫ً‬
‫تقديرا‬
‫النتيجة خارج النطاق‪ ،‬اطبع رسالة خطأ‪ ،‬وإذا كانت الدرجة بين ‪ 0.0‬و‪ ،1.0‬اطبع‬
‫يقابل قيمة الدرجة باستخدام الجدول التالي‪:‬‬
‫‪>= 0.9 A‬‬
‫‪>= 0.8 B‬‬
‫‪>= 0.7 C‬‬
‫‪>= 0.6 D‬‬
‫‪F‬‬
‫‪< 0.6‬‬
‫‪Enter score: 0.95‬‬
‫‪A‬‬
‫‪Enter score: perfect‬‬
‫‪Bad score‬‬
‫الفصل الثالث‪ :‬التنفيذ الشرطي‬
‫‪54‬‬
‫‪Enter score: 10.0‬‬
‫‪Bad score‬‬
‫‪Enter score: 0.75‬‬
‫‪C‬‬
‫‪Enter score: 0.5‬‬
‫‪F‬‬
‫نفذ البرنامج بشكل متكرر كما هو موضح أعاله الختبار القيم املختلفة لإلدخال‪.‬‬
‫الفصل الرابع‬
‫التوابع‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪56‬‬
‫‪ 4‬التوابع‬
‫‪ 1.4‬استدعاء التوابع‬
‫عرف التابع (‪ )function‬على َّأنه سلسلة ُم َّ‬
‫في السياق البرمجي‪ُ ،‬ي َّ‬
‫عرفة من التعليمات (العبارات‬
‫َّ‬
‫ُ‬
‫البرمجية) التي تنفذ عملية حسابية‪ .‬أي أن تعريف تابع ما يتطلب تحديد اسم التابع وتسلسل‬
‫التعليمات‪ ،‬بحيث تستطيع "استدعاء" التابع من خالل اسمه ً‬
‫الحقا‪.‬‬
‫ً‬
‫لقد رأينا من قبل مثاال عن استدعاء تابع‪:‬‬
‫)‪>>> type (32‬‬
‫>' ‪<class ' int‬‬
‫اسم التابع ُهنا هو ‪( type‬بمعنى نوع)‪ ،‬أما التعبير داخل األقواس‪ُ ،‬‬
‫ُ‬
‫فيسمى وسيط التابع‬
‫ً‬
‫ُ‬
‫(‪ ،(argument‬وقد يكون الوسيط قيمة ثابتة (‪ )value‬أو متغي ًرا (‪ )variable‬نمررها إلى التابع بصفتها‬
‫ً‬
‫دخال‪ .‬نتيجة التابع ‪ type‬هي تحديد نوع الوسيط‪.‬‬
‫َ‬
‫ُ‬
‫ُ‬
‫ُ‬
‫من الشائع قول إن التابع "يأخذ" الوسيط َو ُ"يعيد" النتيجة‪ ،‬وتدعى النتيجة ُهنا القيمة املعادة‬
‫(‪.)return value‬‬
‫‪ 2.4‬التوابع الجاهزة‬
‫ُ‬
‫تقدم لغة بايثون العديد من التوابع الجاهزة التي يمكننا استخدامها دون الحاجة إلى تعريفها‪ ،‬حيث‬
‫وضع ُمبتكرو لغة بايثون مجموعة من التوابع لحل مسائل شائعة‪َّ ،‬‬
‫وضمنوا هذه التوابع في لغة بايثون‬
‫ليتيحوا لنا استخدامها‪.‬‬
‫َ‬
‫ضمن قائمة )‪.(list‬‬
‫ُيقدم لنا التابعان ‪َ max‬و‪ min‬القيم األكبر واألصغر على الترتيب‬
‫)'‪>>> max ('Hello world‬‬
‫'‪'w‬‬
‫)'‪>>> min ('Hello world‬‬
‫' '‬
‫>>>‬
‫ُيخبرنا التابع ‪ max‬باملحرف األكبر ضمن السلسلة النصية‪ ،‬وهو الحرف ‪ .w‬ويبين التابع ‪ min‬املحرف‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪57‬‬
‫األصغر‪ ،‬وهو الفراغ (‪.)space‬‬
‫ُي ُّ‬
‫عد التابع ‪ len‬من التوابع الجاهزة شائعة االستخدام‪ ،‬ويبين عدد العناصر املوجودة ضمن وسيطه‪،‬‬
‫ً‬
‫فإذا كان وسيط التابع ‪ len‬سلسلة نصية‪ُ ،‬يعيد التابع عدد العناصر في السلسلة‪.‬‬
‫)'‪>>> len ('Hello world‬‬
‫‪11‬‬
‫>>>‬
‫ال تقتصر هذه التوابع على السالسل النصية‪ ،‬بل يمكنها التعامل مع أية مجموعة من القيم‪ ،‬وهذا ما‬
‫سنراه في الفصول القادمة‪.‬‬
‫يجب أن ُتعامل أسماء التوابع الجاهزة بصفتها كلمات محجوزة (أي َّأنه علينا ُّ‬
‫تجنب استخدام كلمة‬
‫ً‬
‫ً ُ‬
‫اسما ملتغير)‪.‬‬
‫‪ max‬مثال بصفتها‬
‫‪ 3.4‬توابع تحويل النوع‬
‫ُتقدم بايثون ً‬
‫أيضا َ‬
‫توابع جاهزة تحول َ‬
‫القيم من نوع آلخر‪ .‬يأخذ التابع ‪ int‬أية قيمة ويحولها إلى عدد‬
‫صحيح (‪ )integer‬إن أمكن‪ ،‬أو يظهر رسالة خطأ إذا لم يكن التحويل ً‬
‫ممكنا‪.‬‬
‫) '‪>>> int ( '32‬‬
‫‪32‬‬
‫) '‪>>> int ( 'Hello‬‬
‫'‪ValueError: invalid literal for int() with base 10: 'Hello‬‬
‫كما بإمكان التابع ‪ int‬تحويل األعداد ذات الفاصلة العشرية )‪ (float‬إلى أعداد صحيحة‪ ،‬لكنه ال‬
‫ُيقربها‪ ،‬بل يكتفي بإلغاء القسم العشري‪.‬‬
‫)‪>>> int (3.99999‬‬
‫‪3‬‬
‫)‪>>> int (-2.3‬‬
‫‪-2‬‬
‫يحول التابع ‪ float‬األعداد الصحيحة والسالسل النصية (األرقام وليس األحرف) إلى أعداد ذات‬
‫فواصل عشرية‪.‬‬
‫)‪>>> float (32‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪58‬‬
‫‪32.0‬‬
‫) ' ‪>>> float ( ' 3.14159‬‬
‫‪3.14159‬‬
‫َ‬
‫ً‬
‫أخيرا‪ ،‬يحول التابع ‪ str‬وسيطه إلى سلسلة نصية‪.‬‬
‫)‪>>> str (32‬‬
‫' ‪' 32‬‬
‫)‪>>> str (3.14159‬‬
‫' ‪' 3.14159‬‬
‫ّ‬
‫الرياضية‬
‫‪ 4.4‬التوابع‬
‫تمتلك لغة بايثون وحدة رياضية تحوي معظم التوابع الرياضية املعروفة‪ ،‬وعلينا استدعاء هذه‬
‫الوحدة حتى نتمكن من استخدامها‪:‬‬
‫‪>>> import math‬‬
‫تنش ئ هذه التعليمة كائن وحدة (‪ (module object‬يدعى ‪ .math‬ستحصل على بعض املعلومات عنه‬
‫حين تضعه ضمن تعليمة الطباعة‪.‬‬
‫)‪>>> print(math‬‬
‫> )‪< module 'math' (built-in‬‬
‫يحتوي كائن الوحدة على التوابع واملتغيرات َّ‬
‫املعرفة في الوحدة‪ .‬للوصول إلى أحد هذه التوابع‪ ،‬عليك‬
‫َ‬
‫مفصولين بنقطة (‪ ،)dot‬والتي ُتعرف ً‬
‫أيضا باسم (‪ ،)period‬وتدعى‬
‫أن تحدد اسم الوحدة واسم التابع‬
‫هذه الصيغة تأشيرة النقطة (‪.)dot notation‬‬
‫‪>>> ratio = signal_power / noise_power‬‬
‫)‪>>> decibels = 10 * math.log10(ratio‬‬
‫‪>>> radians = 0.7‬‬
‫)‪>>> height = math.sin (radians‬‬
‫يحسب املثال األول اللوغاريتم ذا األساس ‪ 10‬لنسبة اإلشارة إلى الضجيج (‪.)ratio-noise-to-signal‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪59‬‬
‫كما تحوي الوحدة الرياضية ً‬
‫تابعا ُيدعى ‪ ،log‬والذي يحسب اللوغاريتم ذا األساس النيبري ‪.e‬‬
‫ً‬
‫تلميحا إلى أن‬
‫يوجد املثال الثاني الجيب )‪ )sin‬للعدد املسند في املتغير ‪ُ .radians‬يعطي اسم املتغير‬
‫الجيب والدوال املثلثية األخرى‪ ،‬مثل (…‪ ،)cos, tan,‬تأخذ قيمها بالراديان‪ .‬للتحويل من الدرجات إلى‬
‫الراديان نقسم على ‪ ،360‬ثم نضرب بـ ‪.2π‬‬
‫‪>>> degrees = 45‬‬
‫‪>>> radians = degrees / 360.0 * 2 * math.pi‬‬
‫)‪>>> math.sin(radians‬‬
‫‪0.7071067811865476‬‬
‫ُ‬
‫تستخدم العبارة ‪ math.pi‬للحصول على قيمة املتغير ‪ pi‬من الوحدة ‪ ،math‬والذي تمثل قيمته‬
‫العدد ‪ π‬بدقة ‪ 15‬خانة‪.‬‬
‫إن كنت ً‬
‫خبيرا في علم املثلثات‪ ،‬يمكنك التحقق من صحة النتيجة السابقة بقسمة الجذر التربيعي‬
‫للرقم ‪ 2‬على ‪ 2‬كما يلي‪:‬‬
‫‪>>> math.sqrt (2) / 2.0‬‬
‫‪0.7071067811865476‬‬
‫ّ‬
‫العشوائية‬
‫‪ 5.4‬األعداد‬
‫ُ‬
‫تولد غالبية البرامج الحاسوبية نفس قيم الخرج في كل مرة تتلقى فيها قيم الدخل نفسها‪ ،‬لذلك تدعى‬
‫ُ‬
‫ً‬
‫وعادة ما تكون الحتمية ً‬
‫أمرا جي ًدا‪ ،‬حيث أننا نتوقع أن تثمر العملية‬
‫حتمية (‪.)Deterministic‬‬
‫َ‬
‫الحسابية النتيجة ذاتها‪ ،‬إال أننا قد نحتاج أن يكون الحاسوب غير قابل للتنبؤ في بعض التطبيقات‪.‬‬
‫تعتبر األلعاب خير مثال‪ ،‬ولكن ثمة تطبيقات أخرى سواها‪.‬‬
‫حتمي باملطلق‪ ،‬لكن َّثمة بعض األساليب التي تجعله يبدو‬
‫برنامج غير‬
‫في الواقع‪ ،‬من غير السهل بناء‬
‫ٍ‬
‫ٍ‬
‫ُ‬
‫ً‬
‫أعدادا‬
‫كذلك على األقل‪ .‬أحد هذه األساليب تكمن في استخدام الخوارزميات )‪ (algorithms‬التي تولد‬
‫شبه عشوائية )‪ .)pseudorandom‬األعداد شبه العشوائية ليست عشوائية باملطلق‪ ،‬وذلك ألن‬
‫عملية حاسوبية حتمية تولدها‪ ،‬إنما يستحيل تمييز تلك األعداد عن األعداد العشوائية بمجرد النظر‬
‫إليها‪.‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪60‬‬
‫ُتقدم الوحدة العشوائية توابع تولد أعداد شبه عشوائية (والتي سندعوها "عشوائية" للسهولة ً‬
‫بدءا‬
‫من اآلن)‪.‬‬
‫ُيعيد التابع ‪ً random‬‬
‫ًّ‬
‫ًّ‬
‫عشوائيا بين ‪َ 0.0‬و‪( 1.0‬متضم ًنا ‪ 0.0‬دون ‪.)1.0‬‬
‫عشريا‬
‫عددا‬
‫ً‬
‫في كل مرة تستدعي التابع ‪ random‬ستحصل على عدد من سلسلة طويلة من األعداد‪ .‬لترى مثاال على‬
‫ذلك‪ ،‬شغل الحلقة التالية‪:‬‬
‫‪import random‬‬
‫‪for i in range (10) :‬‬
‫)(‪x = random.random‬‬
‫)‪print (x‬‬
‫ُ‬
‫ينتج عن البرنامج القائمة التالية املؤلفة من ‪ 10‬أعداد بين ‪َ 0.0‬و‪ 1.0‬وغير املتضمنة لـ ‪:1.0‬‬
‫‪0.11132867921152356‬‬
‫‪0.5950949227890241‬‬
‫‪0.04820265884996877‬‬
‫‪0.841003109276478‬‬
‫‪0.997914947094958‬‬
‫‪0.04842330803368111‬‬
‫‪0.7416295948208405‬‬
‫‪0.510535245390327‬‬
‫‪0.27447040171978143‬‬
‫‪0.028511805472785867‬‬
‫التمرين األول‪ :‬شغل البرنامج على حاسوبك وشاهد األرقام التي ستحصل عليها‪ .‬شغل البرنامج أكثر‬
‫من مرة لترى األعداد الناتجة‪.‬‬
‫ُيعتبر التابع ‪ً random‬‬
‫واحدا من عدة َ‬
‫توابع تتعامل مع األعداد العشوائية‪.‬‬
‫يأخذ التابع ‪ randint‬معاملين األول يمثل الحد األدنى (‪ )low‬والثاني الحد األعلى (‪ُ )high‬ويعيد ً‬
‫عددا‬
‫ً‬
‫صحيحا بينهما ُ(متضم ًنا القيمتين)‪.‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪61‬‬
‫)‪>>> random.randint (5 , 10‬‬
‫‪5‬‬
‫)‪>>> random.randint (5 , 10‬‬
‫‪9‬‬
‫الختيار عنصر من مجموعة عشوائية‪ ،‬بإمكانك استخدام التعليمة ‪:choice‬‬
‫]‪>>> t = [1 , 2 , 3‬‬
‫)‪>>> random.choice(t‬‬
‫‪2‬‬
‫)‪>>> random.choice(t‬‬
‫‪3‬‬
‫ُ‬
‫باإلضافة إلى ذلك‪ ،‬تؤمن الوحدة ‪ random‬توابع لتوليد قيم عشوائية من التوزيعات املستمرة‪ ،‬ومن‬
‫ضمنها التوزيعات الغوصية (‪ ،)Gaussians‬واألسية (‪َ ،)Exponential‬وغاما )‪ ،(gamma‬وغيرها‪.‬‬
‫‪ 6.4‬إضافة توابع جديدة‬
‫ما زلنا نستخدم التوابع الجاهزة في بايثون حتى اآلن‪ ،‬ولكن بإمكاننا ً‬
‫أيضا إضافة توابع جديدة‪.‬‬
‫ُ‬
‫ُيحدد تعريف التابع (‪ (function definition‬اسم التابع الجديد وسلسلة التعليمات التي ت َّنفذ عندما‬
‫ُيستدعى التابع‪.‬‬
‫حاملا نعرف ً‬
‫تابعا‪ ،‬يصبح باإلمكان إعادة استخدامه مر ًارا وتكر ًارا في البرنامج‪.‬‬
‫إليك املثال التالي‪:‬‬
‫‪def print_lyrics () :‬‬
‫)" ‪print (" I'm a lumberjack, and I'm okay.‬‬
‫)' ‪print (' I sleep all night and I work all day‬‬
‫‪ def‬هي الكلمة املفتاحية الدالة على تعريف التابع‪ .‬اسم التابع هو ‪ .print_lyrics‬القواعد التي تنطبق‬
‫على أسماء املتغيرات تنطبق بدورها على أسماء التوابع‪ُ ،‬ويسمح باستخدام األحرف واألرقام وبعض‬
‫َ‬
‫الشرطة السفلية _ )‪ ،‬ولكن ال يجوز أن يكون املحرف األول من اسم التابع ً‬
‫رقما أو‬
‫عالمات الترقيم (ك‬
‫يحوي فراغات‪ ،‬كما أنه ليس بإمكانك استخدام كلمة مفتاحية لتسمية التابع‪ ،‬باإلضافة إلى ذلك‪،‬‬
‫ينبغي ُّ‬
‫تجنب أن يكون للتابع وللمتغير االسم ذاته‪.‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪62‬‬
‫ُتشير األقواس الفارغة بعد اسم التابع ( ) إلى أنه ال يأخذ أي وسيط‪ .‬سننش ئ ً‬
‫الحقا توابع تقبل‬
‫الوسائط بصفتها ُمدخالت‪.‬‬
‫ُ‬
‫ُيسمى السطر األول من تعريف التابع الترويسة )‪ ،)Header‬وتسمى البقية جسم التابع (‪.)body‬‬
‫يجب أن ينتهي العنوان بنقطتي القول ‪ ، :‬أما جسم التابع‪ ،‬فيجب أن يكون ُمز ً‬
‫احا‪ُّ .‬اتف َق على أن تكون‬
‫املسافة البادئة ‪ 4‬فراغات ً‬
‫دوما‪ ،‬ويمكن لجسم التابع أن يحتوي أي عدد من التعليمات‪.‬‬
‫إذا َ‬
‫كتبت تعريف التابع في الوضع التفاعلي (‪ ،(interactive mode‬فإن املفسر سيطبع ثالث نقاط ‪...‬‬
‫َ‬
‫إلعالمك بأن التعريف غير كامل‪.‬‬
‫‪>>> def print_lyrics() :‬‬
‫)" ‪print (" I'm a lumberjack, and I'm okay.‬‬
‫‪...‬‬
‫)' ‪print (' I sleep all night and I work all day.‬‬
‫‪...‬‬
‫‪...‬‬
‫ًّ‬
‫ضروريا في حال كتابة النص البرمجي ضمن‬
‫إلنهاء التابع‪ ،‬سيتعين عليك إدخال سطر فارغ (وهذا ليس‬
‫ملف)‪.‬‬
‫إن عملية تعريف تابع تعطي بدورها ُمتغي ًرا بنفس اسم التابع‪.‬‬
‫)‪>>> print(print_lyrics‬‬
‫>‪<function print_lyrics at 0xb7e99e9c‬‬
‫))‪>>> print(type(print_lyrics‬‬
‫>'‪<class 'function‬‬
‫قيمة التابع ‪ print_lyrics‬هي كائن لتابع (‪ (function object‬من النوع "‪ ،"function‬وطريقة استدعاء‬
‫تابع جديد مشابهة الستدعاء التوابع الجاهزة‪:‬‬
‫)(‪>>> print_lyrics‬‬
‫‪I'm a lumberjack, and I'm okay‬‬
‫‪I sleep all night and I work all day‬‬
‫ً‬
‫حاملا تعرف تابع‪ُ ،‬يمكنك استخدامه ضمن تابع آخر‪ .‬مثال‪ ،‬لتكرار كلمات األغنية السابقة‪ ،‬باإلمكان‬
‫إضافة تابع ُيدعى ‪.repeat_lyrics‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪63‬‬
‫‪def repeat_lyrics() :‬‬
‫)(‪print_lyrics‬‬
‫)(‪print_lyrics‬‬
‫ثم استدع التابع ‪.repeat_lyrics‬‬
‫)(‪>>> repeat_lyrics‬‬
‫‪I'm a lumberjack, and I'm okay‬‬
‫‪I sleep all night and I work all day.‬‬
‫‪I'm a lumberjack, and I'm okay‬‬
‫‪I sleep all night and I work all day.‬‬
‫‪ 7.4‬التعاريف واستخداماتها‬
‫سيبدو البرنامج بأكمله على الشكل التالي بعد تجميع أجزاء النص البرمجي من القسم السابق‪:‬‬
‫‪def print_lyrics():‬‬
‫)"‪print("I'm a lumberjack, and I'm okay.‬‬
‫)'‪print('I sleep all night and I work all day.‬‬
‫‪def repeat_lyrics():‬‬
‫)(‪print_lyrics‬‬
‫)(‪print_lyrics‬‬
‫)(‪repeat_lyrics‬‬
‫‪# Code: http://www.py4e.com/code3/lyrics.py‬‬
‫ُ‬
‫يحتوي هذا البرنامج على تعاريف لتابعين‪َ print_lyrics :‬و‪ .repeat_lyrics‬ت َن َّفذ تعريفات التابع مثل‬
‫ُ‬
‫غيرها من التعليمات‪ ،‬وهي تنش ئ كائنات التابع‪ .‬ال ت َّنفذ العبارات داخل التابع حتى ُيستدعى التابع‪،‬‬
‫كما أن تعريف التابع ال ُيولد ً‬
‫خرجا‪.‬‬
‫بالطبع عليك أن تنش ئ ً‬
‫تابعا قبل أن تنفذ محتواه‪ .‬بمعنى آخر‪ ،‬يجب كتابة تعريف التابع قبل‬
‫استدعائه ألول مرة‪.‬‬
‫التمرين الثاني‪ :‬انقل السطر األخير من البرنامج السابق إلى األعلى بحيث تصبح تعليمة استدعاء‬
‫التابع موجودة قبل التعريفات‪ .‬شغل البرنامج والحظ رسالة الخطأ الناتجة‪.‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪64‬‬
‫ً‬
‫التمرين الثالث‪ :‬انقل تعليمة استدعاء التابع إلى األسفل ثانية‪ ،‬وانقل تعريف ‪ print_lyrics‬ليصبح‬
‫بعد تعريف ‪ .repeat_lyrics‬ما الذي يحدث عند تشغيل البرنامج؟‬
‫‪ 8.4‬تسلسل التنفيذ‬
‫ُ‬
‫من أجل ضمان أن التابع ُعر َف َ‬
‫قبل استخدامه ألول مرة‪ ،‬عليك أن تعرف الترتيب الذي ت َنفذ وفقه‬
‫التعليمات‪ ،‬والذي ُيعرف بـتسلسل التنفيذ )‪.(Flow of execution‬‬
‫ُ‬
‫يبدأ التنفيذ ً‬
‫دوما من التعليمة األولى في البرنامج‪ ،‬حيث تنفذ التعليمات واحدة تلو األخرى بالترتيب‬
‫ُ‬
‫من األعلى لألسفل‪ .‬ال تغير تعريفات التوابع من تسلسل التنفيذ في البرنامج‪ ،‬لكن تذكر أن التعليمات‬
‫ُ‬
‫ال تنفذ حتى ُيستدعى التابع‪.‬‬
‫ً‬
‫ُ‬
‫تعتبر عملية استدعاء التابع بمثابة انعطاف في تسلسل التنفيذ‪ ،‬فبدال من الذهاب إلى الجملة‬
‫ً‬
‫التالية‪ ،‬يقفز التسلسل إلى جسم التابع ُمنفذا جميع التعليمات هناك‪ ،‬ثم يعود بعد ذلك ليستأنف‬
‫من حيث توقف‪.‬‬
‫ً‬
‫يبدو هذا سهال إلى أن تتذكر أن بإمكان التابع نفسه استدعاء تابع آخر‪ ،‬حيث قد يضطر البرنامج ‪-‬‬
‫أثناء وصوله ملنتصف أحد التوابع‪ -‬إلى تنفيذ تعليمات في تابع آخر‪ ،‬ولكن خالل تنفيذ التابع الجديد‬
‫قد ُينفذ البرنامج ً‬
‫تابعا آخر‪.‬‬
‫لحسن الحظ‪ ،‬فإن لغة بايثون جيدة في حفظ مسارها‪ ،‬إذ في كل مرة يكتمل تنفيذ أحد التوابع‪،‬‬
‫يستأنف البرنامج من حيث توقف في التابع الذي استدعاه‪ ،‬وعندما يصل إلى نهاية البرنامج تنتهي‬
‫العملية‪.‬‬
‫ً‬
‫ً‬
‫برنامجا‪ ،‬قد ال تكون القراءة من األعلى لألسفل فعالة‬
‫ما املغزى من هذه القصة الشيقة؟ عندما تقرأ‬
‫ً‬
‫ًّ‬
‫فأحيانا يكون ُّ‬
‫ً‬
‫منطقيا أكثر‪.‬‬
‫تتب ُع تسلسل التنفيذ‬
‫دائما‪،‬‬
‫ُ‬
‫‪ 9.4‬املعامالت والوسائط‬
‫ً‬
‫تتطلب بعض التوابع الجاهزة التي صادفناها وسائط‪ ،‬فمثال عندما تستدعي التابع ‪ ،math.sin‬فإنك‬
‫ً‬
‫تمرر له رقم باعتباره وسيطا‪ .‬تأخذ بعض التوابع أكثر من وسيط‪ :‬التابع ‪ math.pow‬يأخذ وسيطين‪،‬‬
‫هما "األساس واألس"‪.‬‬
‫ُ‬
‫ُ‬
‫ُ‬
‫تسند هذه الوسائط ملتغيرات داخل التابع تدعى ُمعامالت (‪.)Parameters‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪65‬‬
‫ً‬
‫ً‬
‫إليك مثاال عن التوابع املعرفة من قبل املستخدم (‪ ،(User defined functions‬والتي تأخذ وسيطا‪:‬‬
‫‪>>> def print_twice(bruce):‬‬
‫)‪print(bruce‬‬
‫)‪print(bruce‬‬
‫يسند هذا التابع الوسيط إلى ُمعامل اسمه ‪ .bruce‬عندما ُيستدعى التابع‪ ،‬فإنه يطبع قيمة املعامل‬
‫(مهما كانت) مرتين‪.‬‬
‫يعمل هذا التابع مع أية قيمة ُيمكن كتابتها‪.‬‬
‫)'‪>>> print_twice('Spam‬‬
‫‪Spam‬‬
‫‪Spam‬‬
‫)‪>>> print_twice(17‬‬
‫‪17‬‬
‫‪17‬‬
‫‪>>> import math‬‬
‫)‪>>> print_twice(math.pi‬‬
‫‪3.141592653589793‬‬
‫‪3.141592653589793‬‬
‫ُ‬
‫قواعد إنشاء التوابع (ذاتها التي تنطبق على التوابع‬
‫تنطبق على التوابع املعرفة من قبل املستخدم‬
‫الجاهزة‪ ،‬لذا بإمكاننا استخدام أي تعبير كوسيط للتابع ‪.print_twice‬‬
‫)‪>>> print_twice('Spam '*4‬‬
‫‪Spam Spam Spam Spam‬‬
‫‪Spam Spam Spam Spam‬‬
‫))‪>>> print_twice(math.cos(math.pi‬‬
‫‪-1.0‬‬
‫‪-1.0‬‬
‫ُ‬
‫ُي َ‬
‫حسب الوسيط قبل استدعاء التابع‪ ،‬لذلك فإن التعابير ‪َ 'spam' *4‬و)‪ math.cos(math.pi‬تحسب‬
‫مرة واحدة فقط‪.‬‬
‫بإمكانك ً‬
‫أيضا استخدام ُمتغير َ‬
‫كوسيط‪:‬‬
‫ٍ‬
‫'‪>>> michael = 'Eric, the half a bee.‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪66‬‬
‫)‪>>> print_twice(michael‬‬
‫‪Eric, the half a bee.‬‬
‫‪Eric, the half a bee.‬‬
‫ُ‬
‫ال عالقة السم املتغير الذي مررناه كوسيط ‪ Michael‬باسم املعامل ‪ ،bruce‬فبغض النظر عن االسم‬
‫ُ‬
‫الذي أطل َق على القيمة في عملية االستدعاء‪ُ ،‬هنا في التابع ‪ print_twice‬ندعوها ‪.bruce‬‬
‫ُ‬
‫‪ 10.4‬التوابع املنتجة والتوابع الخالية‬
‫ُ‬
‫بعض التوابع التي نستخدمها (كالتوابع الرياضية) ُتعطي ً‬
‫ابتكرت‬
‫نتائجا‪ .‬ولعدم وجود اسم أفضل‪،‬‬
‫ُ‬
‫لها اسم التوابع املنتجة )‪.(fruitful functions‬‬
‫ُ‬
‫ُ‬
‫ُ‬
‫التوابع األخرى‪ ،‬مثل ‪ ،print_twice‬تنجز مهمة‪ ،‬لكنها ال ترجع قيمة‪ .‬نطلق على هذه التوابع اسم‬
‫التوابع الخالية )‪.)Void functions‬‬
‫تابعا ُم ً‬
‫عندما تستدعي ً‬
‫نتجا‪ ،‬فهدفك في أغلب األحيان هو االستفادة من النتيجة‪.‬‬
‫ً‬
‫ُ‬
‫مثال‪ ،‬قد تسند النتيجة إلى ُمتغير أو تستخدمها كجزء من التعبير‪:‬‬
‫)‪X = math.cos(radians‬‬
‫‪golden = (math.sqrt(5) + 1) / 2‬‬
‫عندما تستدعي ً‬
‫تابعا في الوضع التفاعلي‪ ،‬فإن لغة بايثون تعرض النتيجة‪.‬‬
‫)‪>>> math.sqrt(5‬‬
‫‪2.23606797749979‬‬
‫ُ‬
‫تابعا ُم ً‬
‫لكن في وضع كتابة النص البرمجي ضمن ملف‪ ،‬إذا استدعيت ً‬
‫نتجا ولم تخزن النتيجة في ُمتغير‪،‬‬
‫ُ‬
‫فإن القيمة املرجعة ستختفي‪.‬‬
‫)‪math.sqrt(5‬‬
‫َيحسب هذا النص البرمجي الجذر التربيعي للعدد ‪ ،5‬ولكن بما أنه لم ُيخزن النتيجة في متغير أو‬
‫يعرضها‪ ،‬فهو غير مفيد‪.‬‬
‫ُ‬
‫قد تعرض التوابع الخالية ً‬
‫شيئا ما على الشاشة‪ ،‬أو قد تملك ً‬
‫تأثيرا آخر‪ ،‬لكنها ال تملك قيمة ُمرجعة‪.‬‬
‫إذا حاولت أن تسند النتيجة إلى ُمتغير‪ ،‬ستحصل على قيمة مميزة تدعى ‪.None‬‬
‫)'‪>>> result = print_twice('Bing‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪67‬‬
‫‪Bing‬‬
‫‪Bing‬‬
‫)‪>>> print(result‬‬
‫‪None‬‬
‫ُ ُّ‬
‫نوع خاص‪.‬‬
‫القيمة ‪ None‬ليست ذاتها السلسلة النصية "‪ ،"None‬بل تعد قيمة مميزة ذات ٍ‬
‫))‪>>> print (type (None‬‬
‫>'‪<class 'NoneType‬‬
‫ً‬
‫نستخدم التعليمة ‪ return‬في التابع الخاص بنا إلرجاع نتيجة التابع‪ .‬مثال‪ ،‬بإمكاننا إنشاء تابع بسيط‬
‫للغاية اسمه ‪ ،addtwo‬والذي يجمع رقمين ُويرجع نتيجة الجمع‪.‬‬
‫‪def addtwo (a, b):‬‬
‫‪added = a + b‬‬
‫‪return added‬‬
‫)‪x = addtwo(3, 5‬‬
‫)‪print(x‬‬
‫‪# Code: http://www.py4e.com/code3/addtwo.py‬‬
‫عندما ُينفذ هذا النص البرمجي‪ ،‬تطبع تعليمة ‪ print‬العدد ‪ 8‬بسبب التابع ‪ addtwo‬الذي ُ‬
‫استدعي‬
‫ُومرر الوسيطان ‪ 3‬و‪ 5‬له‪.‬‬
‫داخل التابع‪ ،‬املعامالت ‪َ a‬و‪ b‬هما ‪َ 3‬و‪ 5‬على الترتيب‪.‬‬
‫َيحسب التابع ناتج جمع العددين‪ ،‬ويضعه في متغير محلي للتابع اسمه ‪ ،added‬ثم يستخدم تعليمة‬
‫ُ‬
‫‪ return‬إلرسال النتيجة املحسوبة إلى التابع املستدعى كنتيجة للتابع‪ ،‬والتي تكون ُمسندة بدورها إلى‬
‫ُ‬
‫املتغير ‪ ،x‬وتكتب على الشاشة‪.‬‬
‫‪ 11.4‬ملاذا نستخدم التوابع‬
‫ً‬
‫ُّ‬
‫ً‬
‫واضحا‪َ .‬‬
‫قد ال يكون‬
‫تستحق العناء‪.‬‬
‫لم ُي َعد تقسيم البرنامج إلى توابع عملية‬
‫إليك عدة أسباب‪:‬‬
‫َ‬
‫• تمنحك عملية إنشاء تابع جديد الفرصة لتسمية مجموعة من التعليمات‪ ،‬مما يجعل‬
‫برنامجك أسهل للقراءة والفهم والتصحيح‪.‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪68‬‬
‫• يمكن للتوابع أن تجعل برنامجك أصغر من خالل التخلص من التعليمات َّ‬
‫املكررة‪،‬‬
‫بحيث إن َ‬
‫أردت ً‬
‫الحقا إجراء تغيير‪ ،‬فسينحصر ذلك في مكان واحد فقط‪.‬‬
‫َ‬
‫تنقيح أجزاء البرنامج ٌّ‬
‫كل على حدة‪ ،‬ومن ثم‬
‫• تتيح لك عملية تجزئة البرنامج الطويل‬
‫تجميعها ً‬
‫معا في برنامج واحد‪.‬‬
‫ً‬
‫َّ‬
‫املصممة بشكل جيد مفيدة في العديد من البرامج‪ .‬حاملا تكتب‬
‫غالبا ما تكون التوابع‬
‫•‬
‫وتنقح أحدها‪ ،‬بإمكانك إعادة استخدامه‪.‬‬
‫في بقية الكتاب‪ ،‬سنستخدم ً‬
‫غالبا تعريف التابع لشرح مفهوم ما‪.‬‬
‫أساسيات مهارة إنشاء التوابع واستخدامها أن تملك ً‬
‫َّ‬
‫تابعا ُيجسد فكرة‪ ،‬مثل "أوجد القيمة‬
‫تتضمن‬
‫الصغرى في مجموعة من َ‬
‫القيم"‪.‬‬
‫سنعرض عليك ً‬
‫الحقا مجموعة تعليمات توجد أصغر قيمة ضمن مجموعة قيم‪ ،‬وسنقدمها لك‬
‫كتابع يدعى "‪ ،"min‬والذي يأخذ سلسلة القيم كوسائط له ُويعيد القيمة األصغر بينها‪.‬‬
‫ّ‬
‫‪ 12.4‬التنقيح‬
‫إذا كنت تستخدم محرر نصوص لكتابة نصوصك البرمجية‪ ،‬فستواجه ً‬
‫غالبا مشاكل متعلقة‬
‫بالفراغات )‪ (spaces‬واإلزاحات )‪.(tabs‬‬
‫ُ‬
‫ً‬
‫حصرا (دون اإلزاحات)‪ .‬تقوم غالبية‬
‫الطريقة املثلى لتجنب هذه املشاكل هي استخدام فراغات‬
‫محررات النصوص التي تتعامل مع لغة بايثون بهذا األمر بشكل افتراض ي‪ ،‬لكن البعض ال يفعل‪.‬‬
‫ً‬
‫عادة ما تكون اإلزاحات والفراغات غير مرئية‪ ،‬مما يجعل تنقيحها أصعب‪ ،‬لذا حاول إيجاد محرر‬
‫نصوص ُينظم لك املسافات البادئة‪.‬‬
‫إضافة إلى ذلك‪ ،‬ال َ‬
‫تنس حفظ برنامجك قبل تشغيله‪ .‬تقوم بعض بيئات التطوير بذلك بشكل‬
‫ً‬
‫مختلفا‬
‫تلقائي‪ ،‬ولكن بعضها اآلخر ال يفعل‪ ،‬لذا قد يكون البرنامج الذي تشاهده في محرر النصوص‬
‫عن البرنامج الذي تشغله‪.‬‬
‫ً‬
‫ستأخذ عملية التنقيح ً‬
‫وقتا طويال إذا استمريت بتشغيل نفس البرنامج الخاطئ مر ًارا وتكر ًارا‪ .‬احرص‬
‫على أن يكون النص البرمجي التي تنظر إليه هو ذات النص الذي تشغله‪ .‬وفي حال لم تكن ُمتأك ًدا‪،‬‬
‫اكتب ً‬
‫شيئا ما مثل )"‪ print("hello‬في بداية البرنامج وشغله من جديد‪.‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪69‬‬
‫إذا لم تظهر لك الكلمة ‪ ،hello‬فإنك ال تشغل البرنامج الصحيح‪.‬‬
‫‪ 13.4‬فهرس املصطلحات‬
‫ّ‬
‫الخوارزمية (‪ :)Algorithm‬الخطوات العامة لحل أنواع من املشكالت‪.‬‬
‫•‬
‫ُ‬
‫ُ‬
‫• الوسيط (‪ :)Argument‬قيمة تقدم للتابع عند استدعائه‪ ،‬تسند هذه القيمة إلى املعامل‬
‫املناسب في التابع‪.‬‬
‫• جسم التابع (‪ :)body‬سلسلة من التعليمات داخل تعريف التابع‪.‬‬
‫• التركيب (‪ :)composition‬استخدام تعبير كجزء من تعبير أوسع‪ ،‬أو تعليمة كجزء من‬
‫تعليمة أوسع‪.‬‬
‫• الحتمية (‪ُ :)deterministic‬يشير إلى البرنامج الذي ينفذ الش يء ذاته عند إعطائه نفس‬
‫ُ‬
‫املدخالت في كل مرة يجري تشغيله‪.‬‬
‫• تأشيرة النقطة (‪ :)dot notation‬صياغة تستخدم عند استدعاء تابع في وحدة عبر كتابة‬
‫ً‬
‫متبوعا ُبنقطة واسم التابع‪.‬‬
‫اسم الوحدة‬
‫• تسلسل التنفيذ (‪ :)flow of execution‬الترتيب الذي َّ‬
‫تنفذ وفقه التعليمات خالل تشغيل‬
‫البرنامج‪.‬‬
‫ُ‬
‫• التابع املنتج (‪ :)fruitful function‬التابع الذي ُيرجع قيمة‪.‬‬
‫• التابع (‪ :)function‬سلسلة ُمعرفة من التعليمات التي تنجز عملية مفيدة‪ .‬قد تأخذ التوابع‬
‫وسائط وقد ال تأخذ‪ ،‬كما قد تقدم نتيجة وقد ال تفعل‪.‬‬
‫• استدعاء التابع (‪ :)function call‬تعليمة تؤدي إلى بدء تنفيذ التابع‪ ،‬وتتألف من اسم التابع‬
‫ً‬
‫متبوعا بسلسلة وسائط‪.‬‬
‫ً‬
‫• تعريف التابع (‪ :)function definition‬تعليمة تنش ئ ً‬
‫جديدا عبر تخصيص اسم له‪،‬‬
‫تابعا‬
‫ُومعامالت وتعليمات تؤدي إلى تنفيذه‪.‬‬
‫• كائن التابع (‪ :)function object‬قيمة تنشأ بعد تعريف التابع‪ .‬إن اسم التابع هو متغير‬
‫يدل على كائن التابع‪.‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪70‬‬
‫• الترويسة (‪ :)header‬السطر األول من تعريف التابع‪.‬‬
‫• تعليمة ‪ :)Import statement( import‬تعليمة تقرأ ملف الوحدة‪ ،‬وتنش ئ كائن منه‪.‬‬
‫• كائن النموذج (‪ :)module object‬القيمة التي ُتنشئها تعليمة ‪ ،import‬والتي تتيح الوصول‬
‫إلى البيانات والشيفرات املعرفة في الوحدة‪.‬‬
‫ً‬
‫ُ‬
‫عامل (‪ :)parameter‬اسم ُيستخدم داخل التابع للداللة على قيمة ُممررة بصفتها وسيطا‪.‬‬
‫• امل ِّ‬
‫ُ‬
‫ّ‬
‫العشوائي (‪ :)pseudorandom‬تشير إلى سلسلة من األعداد التي تبدو وكأنها‬
‫• شبه‬
‫َّ‬
‫عشوائية‪ ،‬ولكنها تولد من قبل برنامج حتمي‪.‬‬
‫• القيمة املُرجعة (‪ :)return value‬نتيجة التابع‪ .‬إذا ُ‬
‫استخدم استدعاء التابع كتعبير‪ ،‬فإن‬
‫القيمة املرجعة هي قيمة هذا التعبير‪.‬‬
‫• التابع الخالي (‪ :)void function‬هو التابع الذي ال ُيرجع أية قيمة‪.‬‬
‫‪ 14.4‬تمارين‬
‫• التمرين الرابع‪ :‬ما هو الهدف من الكلمة املفتاحية "‪ "def‬في لغة بايثون؟‬
‫‪ .a‬هي كلمة عامية تعني "الشيفرة التالية رائعة"‪.‬‬
‫ُ‬
‫‪ .b‬تشير إلى بداية التابع‪.‬‬
‫خزنة لالستخدام ً‬
‫‪ُ .c‬تشير إلى أن املسافة البادئة التالية من الشيفرة ُم َّ‬
‫الحقا‪.‬‬
‫‪ .d‬كل من ‪ b‬و‪ c‬صحيح‪.‬‬
‫‪ .e‬ال ش يء مما سبق‪.‬‬
‫• التمرين الخامس‪ :‬ماذا سيعرض برنامج بايثون التالي على الخرج؟‬
‫‪def fred():‬‬
‫)"‪print("Zap‬‬
‫‪def jane():‬‬
‫)"‪print("ABC‬‬
‫)(‪jane‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪71‬‬
‫)(‪fred‬‬
‫)(‪jane‬‬
‫‪Zap ABC jane fred jane .a‬‬
‫‪Zap ABC Zap .b‬‬
‫‪ABC Zap jane .c‬‬
‫‪ABC Zap ABC .d‬‬
‫‪Zap Zap Zap .e‬‬
‫• التمرين السادس‪ :‬أعد كتابة برنامج حساب الراتب الذي يعطي قيمة ‪ 1.5‬ضعف األجر‬
‫للوقت اإلضافي‪ ،‬وأنش ئ ً‬
‫تابعا يسمى ‪ computepay‬بحيث يأخذ ُمعاملين ( ‪ hours‬و‪.)rate‬‬
‫‪Enter Hours: 45‬‬
‫‪Enter Rate: 10‬‬
‫‪Pay: 475.‬‬
‫مستخدما ً‬
‫ً‬
‫تابعا يدعى‬
‫• التمرين السابع‪ :‬أعد كتابة برنامج الدرجات من الفصل السابق‬
‫‪ ،computegrade‬والذي يأخذ النتيجة كمعامل له ويعيد الدرجة كسلسلة نصية‪.‬‬
‫‪Score Grade‬‬
‫‪A‬‬
‫‪>= 0.9‬‬
‫‪B‬‬
‫‪>= 0.8‬‬
‫‪>= 0.7 C‬‬
‫‪>= 0.6 D‬‬
‫‪F‬‬
‫‪< 0.6‬‬
‫‪Enter score: 0.95‬‬
‫‪A‬‬
‫‪Enter score: perfect‬‬
‫‪Bad score‬‬
‫الفصل الرابع‪ :‬التوابع‬
‫‪72‬‬
‫‪Enter score: 10.0‬‬
‫‪Bad score‬‬
‫‪Enter score: 0.75‬‬
‫‪C‬‬
‫‪Enter score: 0.5‬‬
‫‪F‬‬
‫كرر تشغيل البرنامج واختبره مع القيم املختلفة للدخل‪.‬‬
‫الفصل الخامس‬
‫التكرار‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪74‬‬
‫‪ 5‬التكرار‬
‫‪ 1.5‬تحديث قيم املتغيرات‬
‫ً‬
‫اعتمادا على قيمته القديمة‪:‬‬
‫تستخدم تعليمة اإلسناد لتحديث قيمة متغير‬
‫‪x=x+1‬‬
‫ً‬
‫ً‬
‫واحدا ثم اجعل الناتج قيمة‬
‫ويعني هذا السطر‪ :‬قم بإحضار قيمة املتغير ‪ x‬الحالية وأضف إليها‬
‫ً‬
‫جديدة للمتغير ‪.x‬‬
‫سنحصل على رسالة خطأ في حال حاولنا أن نحدث قيمة متغير غير موجود ً‬
‫سابقا ألن لغة بايثون‬
‫تنفذ الطرف األيمن قبل أن تحدث قيمة املتغير ‪:x‬‬
‫‪>>> x = x + 1‬‬
‫‪NameError: name 'x' is not defined‬‬
‫ً‬
‫لذا عليك تعريف املتغير أوال قبل أن تحدث قيمته‪:‬‬
‫‪>>> x = 0‬‬
‫‪>>> x = x + 1‬‬
‫تسمى عملية تحديث قيمة متغير ما بإضافة ‪ 1‬إلى قيمته القديمة بالزيادة (‪ )increment‬أما في حال‬
‫ً‬
‫إنقاصا (‪.)decrement‬‬
‫طرح ‪ 1‬من القيمة القديمة فتسمى‬
‫‪ 2.5‬حلقة ‪while‬‬
‫ُ‬
‫ً‬
‫تستخدم الحواسيب عادة ألتمتة املهام املتكررة‪ ،‬ففي حين تبرع الحواسيب في تكرار املهام املتطابقة‬
‫أو املتشابهة‪ ،‬يعجز البشر عن ذلك دون ارتكاب العديد من األخطاء‪ ،‬لذا فإن لغة بايثون تزودنا‬
‫بالعديد من املميزات التي تسهل تنفيذ مثل هذه العمليات‪.‬‬
‫ً‬
‫ٌ‬
‫برنامج بسيط يقوم بالعد التنازلي‬
‫تعد حلقة ‪ while‬شكال من أشكال التكرار في لغة بايثون‪ ،‬وفيما يلي‬
‫ً‬
‫ابتداء بالرقم ‪ 5‬ثم ينتهي بعبارة‪."Blastoff!" :‬‬
‫‪n=5‬‬
‫‪while n > 0:‬‬
‫)‪print(n‬‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪75‬‬
‫‪n=n–1‬‬
‫)'!‪print('Blastoff‬‬
‫يمكن فهم هذه التعليمات بسهولة فهي تعني‪" :‬اطبع قيمة ‪ n‬ثم اطرح منها ً‬
‫واحدا إذا كانت قيمة ‪ n‬أكبر‬
‫من الصفر‪ ،‬وعندما تصبح قيمة ‪ً n‬‬
‫صفرا اخرج من تعليمة ‪ while‬واطبع كلمة "‪ ،"!Blastoff‬حيث‬
‫تنفذ تعليمة ‪ while‬كاآلتي‪:‬‬
‫‪ .1‬قيم فيما إذا كان الشرط قد حقق أم ال‪.‬‬
‫‪ .2‬إذا لم ُيحقق الشرط‪ ،‬اخرج من الحلقة ثم نفذ التعليمة التالية‪.‬‬
‫‪ .3‬إذا ُحقق نفذ محتوى (جسم) الحلقة ثم عد إلى الخطوة األولى‪.‬‬
‫لعلك عرفت اآلن سبب تسميتها بالحلقة (‪ )Loop‬وذلك ألن الخطوة الثالثة تعود إلى الخطوة األولى‬
‫مرة أخرى‪.‬‬
‫نطلق على كل مرة يتم فيها تنفيذ جسم الحلقة بالتكرار (‪ ،)iteration‬فالحلقة املذكورة في املثال‬
‫السابق لها خمس تكرارات أي أن جسم الحلقة َّ‬
‫ينفذ خمس مرات متتالية‪.‬‬
‫يجب أن تغير التعليمات الواردة في جسم الحلقة قيمة متغير معين نسميه متغير التكرار ( ‪iteration‬‬
‫‪ )variable‬حتى نصل إلى مرحلة ال يتحقق فيها شرط الحلقة ومن ثم يتوقف تنفيذها‪ .‬وفي حال غياب‬
‫متغير التكرار‪ ،‬سيتكرر تنفيذ الحلقة باستمرار وينتج عن ذلك ما يسمى بالحلقة الالنهائية ( ‪infinite‬‬
‫‪.)loop‬‬
‫‪ 3.5‬الحلقات الالنهائية‬
‫يجد املبرمجون التعليمات املكتوبة على عبوات الشامبو مضحكة‪ ،‬حيث أن خطوات االستخدام هي‬
‫ً‬
‫(ضع قليال من املستحضر‪ ،‬اغسل باملاء‪ ،‬وكرر ذلك) لكنها تمثل حلقة النهائية لغياب متغير التكرار‬
‫الذي يحدد عدد مرات تنفيذ هذه الحلقة‪.‬‬
‫نعلم في مثال العد التنازلي السابق أن الحلقة منتهية حيث أعطينا ‪ n‬قيمة محددة‪ ،‬ونالحظ‬
‫انخفاض قيمة ‪ n‬عند كل مرة َّ‬
‫ينفذ فيها جسم الحلقة حتى تصل ً‬
‫أخيرا إلى الصفر‪.‬‬
‫ً‬
‫قد يغيب متغير التكرار في بعض الحاالت األخرى لتصبح الحلقة النهائية‪ ،‬فقد ال نعلم مثال متى ينتهي‬
‫تنفيذ الحلقة إال في منتصفها‪ ،‬وعندها نتعمد كتابة حلقة النهائية ثم نستخدم تعليمة اإليقاف ‪break‬‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪76‬‬
‫للخروج من الحلقة عند تحقق شرط معين‪.‬‬
‫الحلقة التالية النهائية وذلك ألن الشرط املستخدم فيها هو الثابت املنطقي ‪( True‬وهو محقق ً‬
‫دائما)‪.‬‬
‫‪n = 10‬‬
‫‪while True:‬‬
‫)' '=‪print (n, end‬‬
‫‪n=n–1‬‬
‫)'!‪print('Done‬‬
‫إذا نفذت هذا البرنامج فإما أن تتعلم كيف تنهي مهمة بايثون الخارجة عن السيطرة أو ستضطر إلى‬
‫استخدام زر الطاقة إليقاف تشغيل الحاسوب‪ ،‬فالبرنامج سيستمر في العمل بشكل النهائي أو حتى‬
‫تنفذ بطارية جهازك‪ .‬تعني' '=‪ end‬أن القيم ستظهر على سطر واحد‪.‬‬
‫قد تبدو هذه الحلقة الالنهائية بال فائدة‪ ،‬لكن نستطيع توظيف هذا النمط من الحلقات إن أضفنا‬
‫ً‬
‫أمرا إلى جسم الحلقة للخروج منها باستخدام تعليمة اإليقاف ‪ break‬عند تحقق شرط معين‪ ،‬فعلى‬
‫ً‬
‫فرض أننا نريد كتابة برنامج يأخذ من املستخدم دخال حتى يدخل كلمة ‪ ،done‬يمكننا كتابة الحلقة‬
‫التالية‪:‬‬
‫‪while True:‬‬
‫)' >'( ‪line = input‬‬
‫‪if line == 'done':‬‬
‫‪break‬‬
‫)‪print(line‬‬
‫)'!‪print('Done‬‬
‫‪# Code: http://www.py4e.com/code3/copytildone1.py‬‬
‫الحظ أن الشرط املستخدم في هذه الحلقة هو الثابت ‪ True‬وهو محقق ً‬
‫دائما‪ ،‬وعليه فإن الحلقة‬
‫ستتكرر حتى تنفذ تعليمة اإليقاف ‪َّ .break‬كلما نفذت الحلقة سيظهر للمستخدم إشارة < ً‬
‫طالبا منه‬
‫إدخال ما يريد‪ ،‬وعند إدخال كلمة ‪ done‬تقوم تعليمة اإليقاف ‪ break‬بالخروج من الحلقة‪ ،‬وإال فإن‬
‫البرنامج سيطبع ما يدخله املستخدم ثم يعود إلى بداية الحلقة‪.‬‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪77‬‬
‫ً‬
‫ًّ‬
‫تجريبيا للبرنامج السابق‪:‬‬
‫إليك تشغيال‬
‫‪> hello there‬‬
‫‪hello there‬‬
‫‪> finished‬‬
‫‪finished‬‬
‫‪> done‬‬
‫!‪Done‬‬
‫من الشائع استخدام هذه الطريقة في كتابة حلقة ‪ ،while‬حيث أنه من املمكن التحقق من شرط‬
‫الحلقة في جسمها وليس فقط في ترويستها‪ ،‬كما يمكن أن نعبر عن شرط اإليقاف بالشكل (توقف‬
‫ً‬
‫عند تحقق ذلك الشرط) بدال من التعبير (تابع التنفيذ حتى يحدث ذلك الشرط)‪.‬‬
‫‪ 4.5‬إنهاء التكرار باستخدام تعليمة ‪Continue‬‬
‫أثناء تنفيذ أحد تكرارات الحلقة‪ ،‬قد نحتاج إلى إيقاف تنفيذ التكرار الحالي والعودة لبدء تكرار‬
‫جديد‪ ،‬نستخدم تعليمة املتابعة ‪ continue‬التي توقف تنفيذ التكرار الحالي دون الخروج من الحلقة‪.‬‬
‫فيما يلي مثال عن حلقة تقوم بطباعة النص املدخل إلى أن يدخل املستخدم كلمة ‪ ،done‬ولكنها‬
‫تتجاهل السطور املدخلة التي تبدأ برمز ‪ #‬وال تقوم بطباعتها (ما يشبه التعليقات املستخدمة في لغة‬
‫بايثون)‪:‬‬
‫‪while True:‬‬
‫)' >'( ‪line = input‬‬
‫‪if line [0] == '#':‬‬
‫‪continue‬‬
‫‪if line == 'done':‬‬
‫‪break‬‬
‫)‪print(line‬‬
‫)'!‪print ('Done‬‬
‫‪# Code: http://www.py4e.com/code3/copytildone2.py‬‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪78‬‬
‫يظهر عند تشغيل البرنامج مع إضافة تعليمة املتابعة ‪:continue‬‬
‫‪> hello there‬‬
‫‪hello there‬‬
‫‪> # don't print this‬‬
‫!‪> print this‬‬
‫!‪print this‬‬
‫‪> done‬‬
‫!‪Done‬‬
‫نالحظ طباعة كل السطور التي تم إدخالها ما عدا السطر الذي ابتدأ بالرمز ‪ ،#‬ألن تنفيذ تعليمة‬
‫املتابعة ‪ continue‬يوقف تنفيذ التكرار الحالي ويعود لتنفيذ حلقة ‪ while‬للبدء بتكرار جديد وبالتالي‬
‫تجاهل تعليمة الطباعة‪.‬‬
‫‪ 5.5‬الحلقات املحددة باستخدام ‪For‬‬
‫ً‬
‫أحيانا أن نتعامل مع مجموعة من األشياء كقائمة من الكلمات أو األرقام أو حتى مع أسطر‬
‫نحتاج‬
‫ملف نص ي‪ ،‬حينئذ يستحسن استخدام الحلقة املحددة ‪ .for‬تعد حلقة ‪ while‬حلقة غير محددة‬
‫ً‬
‫ألنها ببساطة تتكرر حتى يصبح شرطها غير صحيح‪ ،‬في حين تعد حلقة ‪ for‬حلقة محددة ألنها تتكرر‬
‫بعدد األشياء املوجودة في املجموعة‪.‬‬
‫إن قواعد كتابة حلقة ‪ for‬مماثلة لكتابة حلقة ‪ while‬حيث يوجد ترويسة لحلقة ‪ for‬ويتلوها جسم‬
‫الحلقة‪ .‬مثال‪:‬‬
‫]'‪friends = ['Joseph', 'Glenn', 'Sally‬‬
‫‪for friend in friends:‬‬
‫)‪print('Happy New Year:', friend‬‬
‫)'!‪print('Done‬‬
‫قد ال يتضح معنى هذه الحلقة للقارئ مباشرة كما هو الحال في حلقة ‪ ،while‬ولكن إذا اعتبرنا املتغير‬
‫‪ friends‬قائمة تتكون من ثالث عناصر من النوع سلسلة نصية فيمكن أن نصيغ معنى الحلقة كما‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪79‬‬
‫يلي‪ :‬نفذ التعليمات الواردة في جسم الحلقة مرة لكل عنصر ‪ friend‬موجود في القائمة املسماة‬
‫‪.friends‬‬
‫ً‬
‫نرى أن كال من ‪ for‬و‪ in‬كلمات محجوزة للغة بايثون‪ ،‬وكل من ‪ friend‬و‪ friends‬متغيرات‪.‬‬
‫‪for friend in friends:‬‬
‫)‪print ('Happy New Year:', friend‬‬
‫ً‬
‫نسمي املتغير ‪ friend‬متغير التكرار في الحلقة‪ ،‬حيث أنه يتغير لكل تكرار ويعد مسؤوال عن اكتمال‬
‫تنفيذ الحلقة‪ ،‬كما يتعاقب على العناصر النصية الثالثة املوجودة في القائمة ‪ ،friends‬وفيما يلي‬
‫الخرج الناتج عن تنفيذ هذه الحلقة‪:‬‬
‫‪Happy New Year: Joseph‬‬
‫‪Happy New Year: Glenn‬‬
‫‪Happy New Year: Sally‬‬
‫!‪Done‬‬
‫‪ 6.5‬أنماط كتابة الحلقات‬
‫نستخدم عادة كل من حلقتي ‪ for‬و‪ while‬لتنفيذ عملية ما على مجموعة عناصر لقائمة (‪ )list‬أو‬
‫محتويات ملف‪ ،‬قد تكون هذه العملية البحث عن ش يء ما كأكبر أو أصغر قيمة بين البيانات التي‬
‫نتعامل معها‪.‬‬
‫تتم عادة بناء الحلقات كما يلي‪:‬‬
‫‪ -1‬إعطاء قيمة ابتدائية ملتغير أو عدة متغيرات قبل بداية الحلقة‪.‬‬
‫‪ -2‬تنفيذ عملية حسابية على كل عنصر في جسم الحلقة‪ ،‬وقد يترافق ذلك مع تغيير في‬
‫قيم املتغيرات‪.‬‬
‫‪ -3‬إظهار القيم الناتجة للمتغيرات بعد إتمام تنفيذ الحلقة‪.‬‬
‫ً ً‬
‫مثاال نستخدم فيه قائمة من األرقام لنوضح املفاهيم الواردة ً‬
‫سابقا وطريقة بناء عدة‬
‫سنورد تاليا‬
‫أنماط للحلقات‪.‬‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪80‬‬
‫‪ 1.6.5‬حلقات العد والجمع‬
‫إذا أردنا ان نحص ي عدد األرقام املوجودة في قائمة ما‪ ،‬فيمكن أن نكتب الحلقة التالية‪:‬‬
‫‪count = 0‬‬
‫‪for itervar in [3, 41, 12, 9, 74, 15]:‬‬
‫‪count = count + 1‬‬
‫)‪print ('Count: ', count‬‬
‫ً‬
‫بداية أعطينا املتغير ‪ count‬القيمة االبتدائية صفر‪ ،‬ثم كتبنا حلقة ‪ for‬لتنفيذها على قائمة األرقام‪.‬‬
‫إن متغير التكرار في هذا املثال هو املتغير ‪ ،itervar‬ونالحظ أننا ال نستخدم هذا املتغير مباشرة في‬
‫جسم الحلقة‪ ،‬إال أنه يتحكم في تنفيذ الحلقة ويتسبب بتنفيذ جسمها مرة لكل عنصر في القائمة‪.‬‬
‫أضفنا واحد إلى قيمة املتغير ‪ count‬في جسم الحلقة لكل عنصر من عناصر القائمة‪ ،‬وأثناء تنفيذ‬
‫الحلقة فإن قيمة املتغير ‪ count‬تساوي عدد القيم التي مررنا بها حتى اآلن‪.‬‬
‫عند اكتمال تنفيذ الحلقة تساوي قيمة املتغير ‪ count‬العدد اإلجمالي للعناصر‪ ،‬الذي يظهر عند‬
‫اكتمال التنفيذ‪.‬‬
‫ً‬
‫ً‬
‫لنرى اآلن حلقة مشابهة للحلقة السابقة ولكنها تقوم بحساب مجموع قائمة من األرقام‪:‬‬
‫‪total = 0‬‬
‫‪for itervar in [3, 41, 12, 9, 74, 15]:‬‬
‫‪total = total + itervar‬‬
‫)‪print ('Total: ', total‬‬
‫ً‬
‫استخدمنا في هذه الحلقة ًّ‬
‫فعليا متغير التكرار ‪ ،itervar‬فبدال عن إضافة واحد إلى املتغير كما في‬
‫الحلقة السابقة‪ ،‬فقد أضفنا القيمة الفعلية للعنصر (‪ 3‬و‪ 41‬و‪ ........12‬إلخ) إلى املجموع الحالي عند‬
‫كل تكرار للحلقة‪ ،‬وبالنظر إلى املتغير ‪ total‬فإنه يمثل قيمة املجموع الجاري للقيم التي مررنا بها حتى‬
‫اآلن‪ ،‬ولذلك فإننا نعطي هذا املتغير القيمة صفر قبل بداية الحلقة‪ .‬يمثل ذلك املتغير عند اكتمال‬
‫الحلقة مجموع القيم في القائمة‪ .‬أثناء تنفيذ الحلقة فإن املتغير ‪ total‬يجمع أو يراكم قيم العناصر‪،‬‬
‫لذا فهو يسمى املراكم (‪.)accumulator‬‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪81‬‬
‫حلقات مفيدة ًّ‬
‫عمليا لوجود توابع جاهزة لهذا الغرض (التابع‬
‫ال تعتبر أي من الحلقتين السابقتين‬
‫ٍ‬
‫)(‪ len‬لحساب عدد العناصر في قائمة والتابع )(‪ sum‬لحساب مجموع العناصر في قائمة)‪.‬‬
‫‪ 2.6.5‬حلقات إيجاد القيم الكبرى والصغرى‬
‫للحصول على القيمة الكبرى في قائمة أو سلسلة يمكن أن نكتب الحلقة التالية‪:‬‬
‫‪largest = None‬‬
‫)‪print ('Before:', largest‬‬
‫‪for itervar in [3, 41, 12, 9, 74, 15]:‬‬
‫‪if largest is None or itervar > largest :‬‬
‫‪largest = itervar‬‬
‫)‪print ('Loop:', itervar, largest‬‬
‫)‪print ('Largest:', largest‬‬
‫وعند تنفيذ هذا البرنامج ينتج لدينا الخرج التالي‪:‬‬
‫‪Before: None‬‬
‫‪Loop: 3 3‬‬
‫‪Loop: 41 41‬‬
‫‪Loop: 12 41‬‬
‫‪Loop: 9 41‬‬
‫‪Loop: 74 74‬‬
‫‪Loop: 15 74‬‬
‫‪Largest: 74‬‬
‫يمثل املتغير ‪ largest‬أكبر قيمة مررنا بها حتى اآلن حيث قبل بداية الحلقة يحمل هذا املتغير القيمة‬
‫‪ ،None‬يعتبر الثابت ‪ None‬قيمة مميزة يمكن أن نعطيها ملتغير ما لنقول عنه إنه فارغ (أي ال يحتوي‬
‫أي قيمة)‪.‬‬
‫قبل بداية تنفيذ الحلقة تكون القيمة ‪ None‬هي أكبر قيمة ألننا لم نمر بأي قيمة بعد‪ ،‬وفي أثناء‬
‫التنفيذ إذا كانت القيمة املخزنة في املتغير ‪ largest‬هي ‪ None‬نعتبر قيمة أول عنصر هي القيمة األكبر‪،‬‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪82‬‬
‫حيث نالحظ عند تنفيذ البرنامج السابق أننا في أول تكرار للحلقة وعندما كان املتغير ‪ itervar‬يحمل‬
‫القيمة ‪ None‬أصبحت قيمة ‪ largest‬تساوي ‪.3‬‬
‫بعد ذلك لم يعد املتغير ‪ largest‬يحمل القيمة ‪ ،None‬ولذلك فإن القسم الثاني من التعبير املنطقي‬
‫املركب يتحقق فقط إذا مررنا بقيمة أكبر من القيمة الحالية للمتغير ‪ .largest‬وعندئذ فإنها تصبح‬
‫هي القيمة األكبر والتي تخزن فيه‪ ،‬ويمكن أن نراقب تزايد القيمة الكبرى من ‪ 3‬إلى ‪ 41‬ثم إلى ‪ 74‬في‬
‫خرج املثال املوضح أعاله‪.‬‬
‫عند انتهاء الحلقة نكون قد أجرينا ً‬
‫مسحا على كافة القيمة املوجودة في القائمة وعندها يحمل املتغير‬
‫‪ largest‬أكبر قيمة موجودة في القائمة‪.‬‬
‫الستخراج القيمة الصغرى في قائمة ما نكتب حلقة مشابهة للحلقة السابقة مع تغيير بسيط‪:‬‬
‫‪smallest = None‬‬
‫)‪print('Before:', smallest‬‬
‫‪for itervar in [3, 41, 12, 9, 74, 15]:‬‬
‫‪if smallest is None or itervar < smallest:‬‬
‫‪smallest = itervar‬‬
‫)‪print('Loop:', itervar, smallest‬‬
‫)‪print('Smallest:', smallest‬‬
‫نقول إن املتغير ‪ smallest‬يحمل القيمة الصغرى الحالية قبل وأثناء وبعد تنفيذ الحلقة‪ ،‬وعند انتهاء‬
‫الحلقة يحمل هذا املتغير أصغر قيمة موجودة في القائمة‪ .‬وكما هو الحال مع حلقات الجمع والعد‬
‫فإن وجود التوابع الجاهزة ( )(‪ min‬و)(‪ ) max‬يغني عن كتابة حلقات كهذه‪.‬‬
‫إليك نسخة مبسطة عن التابع الجاهز )(‪ min‬في لغة بايثون‪:‬‬
‫‪def min(values):‬‬
‫‪smallest = None‬‬
‫‪for value in values:‬‬
‫‪if smallest is None or value < smallest:‬‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪83‬‬
‫‪smallest = value‬‬
‫‪return smallest‬‬
‫الحظ أننا قمنا بحذف أوامر الطباعة حتى نحصل على تابع مشابه للتابع الجاهز في لغة بايثون‪.‬‬
‫‪ 7.5‬التنقيح‬
‫ً‬
‫ستجد عندما تبدأ بكتابة برامج أعقد أنك تمض ي ً‬
‫وقتا طويال في التنقيح‪ ،‬حيث أن كتابة املزيد من‬
‫الشيفرات يزيد من احتمالية ارتكاب األخطاء واألماكن التي يمكن أن تختبئ فيها‪.‬‬
‫لذا تعتبر عملية التنقيح بالتجزئة إحدى طرق تقليل الوقت املستهلك في التنقيح‪ .‬فعلى سبيل املثال‪،‬‬
‫سطرا ً‬
‫إذا احتوى البرنامج على مئة سطر واختبرتها ً‬
‫سطرا فستحتاج إلى مئة خطوة‪ .‬لذا قسم املشكلة‬
‫إلى نصفين ً‬
‫عوضا عن ذلك‪ ،‬وابحث في منتصف البرنامج ‪-‬أو قرب املنتصف‪ -‬عن قيمة وسطية يمكن‬
‫ً‬
‫التأكد منها‪ ،‬ثم أضف تعليمة الطباعة (أو إضافة أي تغيير يعطي ً‬
‫واضحا) وقم بتشغيل البرنامج‪.‬‬
‫أثرا‬
‫إذا فشلت عملية التحقق التي أضفناها تكون املشكلة في النصف األول للبرنامج‪ ،‬وفي حال كانت نتيجة‬
‫هذه العملية واضحة فاملشكلة إذا في النصف الثاني‪ .‬في كل مرة نقوم بتكرار هذه الطريقة فإننا‬
‫نختصر عدد السطور التي نحتاج إلى التحقق منها إلى النصف‪ ،‬وبعد ست خطوات (وهو عدد اقل‬
‫ًّ‬
‫(نظريا على األقل)‪.‬‬
‫بكثير من مئة خطوة) فإننا سنحصر املشكلة في سطر أو سطرين فقط‬
‫عند التطبيق العملي لهذه الطريقة‪ ،‬قد ال يكون من الواضح ً‬
‫دائما املكان الذي يعتبر نصف البرنامج‬
‫ً‬
‫وقد ال يكون هذا املوضع قابال للتعيين‪ ،‬كما أنه من غير املعقول أن نعد األسطر ونجد نقطة املنتصف‬
‫ً‬
‫ً‬
‫عوضا عن ذلك بالبحث عن األماكن التي يمكن أن تحتوي على أخطاء أو التي يسهل‬
‫تماما‪ ،‬فنقوم‬
‫التحقق من نتيجتها ثم نختار نقطة تمثل املنتصف بالنسبة لهذه األماكن‪.‬‬
‫‪ 8.5‬فهرس املصطلحات‬
‫• املراكم (‪ :)accumulator‬متغير يستخدم في الحلقة ليجمع النتائج مع بعضها‪.‬‬
‫• العداد (‪ :)counter‬متغير يستخدم في حلقة ليقوم بعد املرات التي يحدث فيها ش يء ما‪.‬‬
‫يعطى هذا املتغير قيمة ابتدائية تساوي الصفر ونزيد قيمته بمقدار ‪ 1‬كل مرة نعد ً‬
‫شيئا ما‪.‬‬
‫• التنقيص (‪ :)decrement‬إنقاص قيمة املتغير‪.‬‬
‫• إعطاء قيمة ابتدائية (‪ :)initialize‬إسناد قيمة ابتدائية ملتغير ما سيتم تحديثه ً‬
‫الحقا‪.‬‬
‫الفصل الخامس‪ :‬التكرار‬
‫‪84‬‬
‫• الزيادة (‪ :)increment‬تحديث لقيمة متغير ما يسبب زيادتها (عادة بمقدار ‪.)1‬‬
‫• حلقة ال نهائية (‪ :)infinite loop‬وهي حلقة ال يتحقق فيها شرط اإلنهاء ً‬
‫بتاتا أو هي الحلقة‬
‫التي يغيب عنها هذا الشرط ً‬
‫أساسا‪.‬‬
‫‪ 9.5‬تمارين‬
‫ً‬
‫برنامجا يقرأ األرقام املدخلة بشكل متكرر حتى يدخل املستخدم كلمة‬
‫• التمرين األول‪ :‬اكتب‬
‫‪ ،done‬وعندها يطبع البرنامج كل من املجموع واملتوسط والعدد الكلي لهذه األرقام‪ .‬إذا أدخل‬
‫املستخدم أي محارف عدا األرقام اكتشف هذا الخطأ باستخدام تعليمتي ‪ try‬و‪expect‬‬
‫وأظهر رسالة خطأ ثم انتقل إلى اإلدخال التالي‪.‬‬
‫‪Enter a number: 4‬‬
‫‪Enter a number: 5‬‬
‫‪Enter a number: bad data‬‬
‫‪Invalid input‬‬
‫‪Enter a number: 7‬‬
‫‪Enter a number: done‬‬
‫‪16 3 5.333333333333333‬‬
‫ً‬
‫برنامجا يطلب قائمة من األرقام كما في املثال السابق وعند النهاية‬
‫• التمرين الثاني‪ :‬اكتب‬
‫ً‬
‫يظهر القيمة الكبرى والصغرى لألرقام بدال عن املتوسط‪.‬‬
‫الفصل السادس‬
‫السالسل النصية‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪86‬‬
‫‪ 6‬السالسل النصية‬
‫‪ 1.6‬السلسلة النصية هي سلسلة من املحارف‬
‫ً‬
‫ً‬
‫ً‬
‫ُّ‬
‫كل منها وصوال منفصال باستخدام‬
‫تعد السلسة النصية سلسلة من املحارف التي يمكن الوصول إلى ٍ‬
‫عامل القوس ] [‪.‬‬
‫'‪>>> fruit = 'banana‬‬
‫]‪>>> letter = fruit[1‬‬
‫ٌ‬
‫تعيد التعلمية الثانية املحرف املوجود في املوقع ذي الفهرس ‪ 1‬من املتغير ‪ُ fruit‬ليسند إلى املتغير‬
‫‪.letter‬‬
‫ُيدعى التعبير ما بين األقواس [ ] بالفهرس الذي يشير إلى املحرف املرغوب َو ً‬
‫فقا لتسلسله (من هنا‬
‫جاءت التسمية "السلسلة النصية")‪ ،‬لكنك قد ال تحصل على ما تتوقعه ً‬
‫دائما‪:‬‬
‫)‪>>> print (letter‬‬
‫‪a‬‬
‫َ‬
‫املحرف َّ‬
‫األول من كلمة ‪ banana‬هو ‪ b‬وليس ‪ ،a‬لكن قيمة الفهرس في لغة‬
‫قد يكون من البديهي أن‬
‫بدءا من َّأول السلسلة‪ ،‬وترتيب املحرف َّ‬
‫بايثون ُتعبر عن الترتيب ً‬
‫األول فيها هو الصفر‪.‬‬
‫]‪>>> letter = fruit [0‬‬
‫)‪>>> print(letter‬‬
‫‪b‬‬
‫مما سبق أن الحرف ‪ b‬هو الحرف َّ‬
‫نجد َّ‬
‫األول (ذو الفهرس ‪ )0‬من كلمة ‪ banana‬والحرف ‪ a‬هو الحرف‬
‫الثاني (ذو الفهرس ‪ )1‬و‪ n‬هو الحرف الثالث (ذو الفهرس ‪.)2‬‬
‫باإلمكان استخدام أي تعبير بما في ذلك من املتغيرات واملعامالت على أنها فهرس‪ ،‬لكن قيمها يجب أن‬
‫تكون ً‬
‫ً‬
‫صحيحا وإال فإنك ستحصل على خطأ‪“ :‬خطأ في نوع البيانات‪ :‬فهارس السالسل النصية‬
‫عددا‬
‫يجب أن تكون أعداد صحيحة”‬
‫]‪>>> letter = fruit [1.5‬‬
‫‪TypeError: string indices must be integers‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪87‬‬
‫الشكل ‪ : 9‬فهارس السلسلة النصية‬
‫‪ 2.6‬الحصول على طول السلسلة النصية باستخدام التابع ‪len‬‬
‫التابع ‪َ len‬‬
‫ُيعيد ُ‬
‫عدد املحارف في السلسة النصية‪.‬‬
‫'‪>>> fruit = 'banana‬‬
‫)‪>>> len (fruit‬‬
‫‪6‬‬
‫قد تظن أنه يمكن كتابة التعليمات التالية للحصول على آخر محرف في السلسلة النصية‪:‬‬
‫)‪>>> length = len (fruit‬‬
‫]‪>>> last = fruit [length‬‬
‫‪IndexError: string index out of range‬‬
‫لكن سيعترضك خطأ "خطأ فهرسة‪َّ :‬‬
‫إن فهرس السلسلة النصية خارج املجال"‪.‬‬
‫يعود السبب في ظهور خطأ الفهرسة إلى عدم وجود محرف في كلمة ‪ banana‬له الفهرس ‪ ،6‬وما دام‬
‫ُ‬
‫أن العد يبدأ من الصفر؛ فاألحرف الستة ُمفهرسة من ‪ 0‬حتى ‪ ،5‬أي يجب طرح ‪ 1‬من طول السلسلة‬
‫النصية للحصول على املحرف األخير‪:‬‬
‫]‪>>> last = fruit[length-1‬‬
‫)‪>>> print(last‬‬
‫‪a‬‬
‫وبطريقة أخرى‪ ،‬يمكنك استخدام الفهارس العكسية التي ُت ُّ‬
‫ًّ‬
‫عكسيا من نهاية السلسلة النصية؛‬
‫عد‬
‫إذ َّ‬
‫التعبير [‪ُ fruit]-1‬يعيد الحرف األخير و[‪ fruit]-2‬يعيد الحرف ما َ‬
‫َ‬
‫قبل األخير وهكذا دواليك‪.‬‬
‫إن‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪88‬‬
‫‪ 3.6‬التعامل مع محارف السلسة النصية باستخدام الحلقات‬
‫َ‬
‫تتطلب ُ‬
‫لجة محارف السلسلة النصية كل منها على حدى ً‬
‫بدءا من َّأول محرف‪ ،‬حيث‬
‫بعض البرامج معا‬
‫ُ‬
‫ُ‬
‫ُ‬
‫عمليات ما عليه واملتابعة بهذا النحو حتى املحرف األخير‪.‬‬
‫ُيحدد املحرف ثم ت َّنفذ‬
‫ُيدعى هذا َّ‬
‫الن َمط من عمليات املعالجة باملرور على عناصر السلسلة )‪ُّ (traversal‬‬
‫وتعد حلقة ‪while‬‬
‫إحدى طرق تنفيذه‪:‬‬
‫‪index = 0‬‬
‫‪while index < len(fruit):‬‬
‫]‪letter = fruit[index‬‬
‫)‪print(letter‬‬
‫‪index = index + 1‬‬
‫ً‬
‫ً‬
‫عناصر السلسلة النصية ُوتظهر َّ‬
‫َ‬
‫ظهورا مستقال‪ .‬وألن‬
‫كل محرف على سطر‬
‫تمر هذه الحلقة على‬
‫شرط هذه الحلقة هو )‪ ،index < len(fruit‬لذا سيختل الشرط عندما يتساوى طو ُل السلسلة‬
‫النصية والفهرس‪ ،‬فال تنفذ التعليمات في جسم الحلقة‪.‬‬
‫آخر محرف ُوصل إليه هو الذي يملك الفهرس ‪ len(fruit)-1‬الذي يدل على آخر محرف في السلسلة‬
‫النصية‪.‬‬
‫َ‬
‫التمرين األول‪ :‬استخدم حلقة ‪ while‬بحيث تبدأ من نهاية السلسلة النصية لتنتهي عند املحرف‬
‫َّ‬
‫سطر مستقل‪.‬‬
‫األول لها واطبع كل حرف على‬
‫ٍ‬
‫حلقة ‪ for‬هي طريقة أخرى للمرور على عناصر السلسلة‬
‫‪for char in fruit:‬‬
‫)‪print(char‬‬
‫ُ‬
‫ُي َ‬
‫سند املحرف املوجود في السلسلة النصية إلى املتحول ‪ char‬في كل دور من أدوار الحلقة التي تستمر‬
‫حتى آخر محرف في السلسلة‪.‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪89‬‬
‫‪ 4.6‬تجزئة السالسل النصية‬
‫ُ‬
‫َ‬
‫َ‬
‫ُ‬
‫اختيار محرف في‬
‫اختيار شريحة‬
‫الجزء من السلسلة النصية بالشريحة (‪ ،)slice‬يشابه‬
‫نسمي‬
‫السلسلة النصية‬
‫'‪>>> s = 'Monty Python‬‬
‫)]‪>>> print(s[0:5‬‬
‫‪Monty‬‬
‫)]‪>>> print(s[6:12‬‬
‫‪Python‬‬
‫يعيد العامل [‪ً ]n,m‬‬
‫جزءا من السلسلة النصية‪ ،‬من املحرف ذي الفهرس ‪ n‬إلى املحرف الذي يسبق‬
‫َ‬
‫املحرف ذا الفهرس ‪ ،m‬أي يتضمن املحرف ذو الفهرس َّ‬
‫األول ‪ n‬وال يتضمن ذو الفهرس األخير ‪.m‬‬
‫َ‬
‫ُ‬
‫الفهرس ‪( n‬قبل عامل النقطتين) فإن التجزئة ستبدأ من بداية السلسلة النصية‪ ،‬وفي‬
‫في حال ُحذف‬
‫ُ‬
‫ُّ‬
‫تستمر حتى نهاية السلسلة النصية‪.‬‬
‫الفهرس الثاني ‪( m‬بعد عامل النقطتين) فإن التجزئة‬
‫حال ُحذف‬
‫'‪>>> fruit = 'banana‬‬
‫]‪>>> fruit[:3‬‬
‫'‪'ban‬‬
‫]‪>>> fruit[3:‬‬
‫'‪'ana‬‬
‫ُ َّ‬
‫إذا كان الفهرس َّ‬
‫األول َ‬
‫أكبر أو يساوي الثاني؛ فإن النتيجة هي سلسلة نصية فارغة تمثل بعالمة‬
‫اقتباس‪.‬‬
‫'‪>>> fruit = 'banana‬‬
‫]‪>>> fruit[3:3‬‬
‫'‬
‫'‬
‫ٌ‬
‫ال تحوي السلسلة النصية الفارغة َّ‬
‫أي محارف وطولها صفر‪ ،‬وعلى الرغم من هذا‪ ،‬فهي سلسلة‬
‫نصية‪.‬‬
‫التمرين الثاني‪ :‬بالعودة إلى السلسلة النصية ‪ fruit‬املُعطاة ً‬
‫سابقا‪ ،‬ما نتيجة التعليمة التالية [‪fruit]:‬؟‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪90‬‬
‫‪ 5.6‬السالسل النصية غير قابلة للتعديل‬
‫ُ‬
‫محرف في السلسلة النصية كما يلي‪:‬‬
‫استخدام عامل اإلسناد لتغيير‬
‫قد يبدو من املناسب‬
‫ٍ‬
‫'!‪>>> greeting = 'Hello, world‬‬
‫'‪>>> greeting [0] = 'J‬‬
‫‪TypeError: 'str' object does not support item assignment‬‬
‫فتظهر لك رسالة خطأ "خطأ تصنيف‪ :‬الكائن ‪ str‬ال يدعم إسناد العنصر"‪.‬‬
‫ُ‬
‫السلسلة النصية و"العنصر" هو املحرف الذي حاولت أن َ‬
‫تسنده‪ ،‬يمكنك‬
‫"الكائن" في هذه الحالة هو‬
‫َ ً ُّ ً‬
‫مشابها ً‬
‫ً‬
‫َّ‬
‫تعرفا أفضل)‪،‬‬
‫(ستتعرف هذا املفهوم الحقا‬
‫تماما ملفهوم القيمة‬
‫األن اعتبار مفهوم الكائن‬
‫َّأما العنصر فهو أحد القيم في سلسلة‪.‬‬
‫يظهر خطأ النوع ألن السالسل النصية ُ‬
‫غير قابلة للتعديل مما يعني أنك ال تستطيع تغيير سلسلة‬
‫إنشاء سلسلة نصية جديدة تمثل ُّ‬
‫ُ‬
‫التغير على السلسلة األصلية‪.‬‬
‫نصية‪ ،‬ما يمكنك القيام به هو‬
‫'!‪>>> greeting = 'Hello, world‬‬
‫]‪>>> new_greeting = 'J' + greeting[1:‬‬
‫)‪>>> print(new_greeting‬‬
‫!‪Jello, world‬‬
‫ُ‬
‫َ‬
‫ٌ‬
‫أضيف في هذا املثال حرف جديد إلى جزء من السلسلة النصية ‪ greeting‬من َدون التعديل على‬
‫السلسلة األصلية‪.‬‬
‫ّ‬
‫والعد‬
‫‪ 6.6‬استخدام الحلقات‬
‫يحسب البرنامج التالي َ‬
‫عدد مرات ظهور املحرف "‪ "a‬في السلسلة النصية‬
‫'‪word = 'banana‬‬
‫‪count = 0‬‬
‫‪for letter in word:‬‬
‫‪if letter == 'a':‬‬
‫‪count = count + 1‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪91‬‬
‫)‪print(count‬‬
‫ً‬
‫نموذجا لبرامج تقوم بعمليات حسابية كالعد‪ ،‬فاملتغير ‪ count‬يبدأ من القيمة ‪ 0‬ثم‬
‫ُيمثل هذا البرنامج‬
‫َ‬
‫َ‬
‫(العدد َّ‬
‫الكلي‬
‫يزداد في كل مرة يظهر فيها املحرف ‪ a‬وعند انتهاء الحلقة يتضمن املتغير ‪ count‬النتيجة‬
‫ملرات ظهور املحرف ‪.)a‬‬
‫َ‬
‫البرنامج السابق في تابع سمه ‪ count‬بحيث يقبل السلسلة النصية‬
‫التمرين الثالث‪ :‬أعد كتابة‬
‫َ‬
‫ُ‬
‫َ‬
‫والحرف املراد معرفة مرات تكراره باعتبارهم وسائط‪.‬‬
‫‪ 7.6‬العامل ‪in‬‬
‫ً‬
‫ً‬
‫ُّ‬
‫ًّ‬
‫منطقيا يأخذ سلسلتين نصيتين ويعيد الثابت املنطقي ‪ True‬إذا كانت األولى سلسلة‬
‫يعد ‪ in‬عامال‬
‫فرعية م َن الثانية‪.‬‬
‫'‪>>> 'a' in 'banana‬‬
‫‪True‬‬
‫'‪>>> 'seed' in 'banana‬‬
‫‪False‬‬
‫‪ 8.6‬مقارنة السالسل النصية‬
‫ُّ‬
‫ُ‬
‫للتحقق من تساوي سلسلتين‪.‬‬
‫عوامل املقارنة على السالسل النصية‬
‫تعمل‬
‫‪if word == 'banana' :‬‬
‫)'‪print ('All right, bananas.‬‬
‫ُ‬
‫عوامل مقارنة أخرى لترتيب مجموعة سالسل نصية َو َ‬
‫ُ‬
‫فق الترتيب األبجدي‪.‬‬
‫تستخدم‬
‫‪if word < 'banana':‬‬
‫)'‪print('Your word,' + word + ', comes before banana.‬‬
‫‪elif word > 'banana':‬‬
‫)'‪print('Your word,' + word + ', comes after banana.‬‬
‫‪else:‬‬
‫)'‪print('All right, bananas.‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪92‬‬
‫ُ‬
‫َ‬
‫َ‬
‫ال تتعامل لغة بايثون واألحرف الكبيرة والصغيرة كما يتعامل الناس معها‪ ،‬ففي لغة البايثون تأتي‬
‫ُ‬
‫قبل األحرف الصغيرة ً‬
‫كلمة ‪َ Pinapple‬‬
‫األحرف الكبيرة َ‬
‫قبل ‪.banana‬‬
‫دوما‪ ،‬لذلك تأتي‬
‫ُ َ‬
‫توحيد ن َمط السالسل النصية (حروف صغيرة فقط‬
‫إحدى الطرائق الشائعة لتفادي هذه املشكلة هي‬
‫ً‬
‫مثال) َ‬
‫قبل القيام بعملية املقارنة‪ ،‬أبق هذه املالحظة في بالك عند املقارنة بين كلمات ذات حروف‬
‫صغيرة وكبيرة‪.‬‬
‫‪ 9.6‬توابع السالسل النصية‬
‫ُّ‬
‫تعد السالسل النصية إحدى أمثلة الكائنات في لغة بايثون‪ ،‬يتضمن الكائن البيانات (السلسلة بحد‬
‫َ‬
‫ضمن الكائن ومتاحة ألي نسخة من هذا الكائن‪.‬‬
‫ذاتها) وتوابع الصنف )‪ (methods‬وهي توابع مبنية‬
‫التابع ‪َ type‬‬
‫َ‬
‫التوابع املتاحة لكائن ما‪ ،‬في حين ُيظهر ُ‬
‫ُيظهر التابع ‪ dir‬في لغة بايثون‬
‫نوع الكائن‪.‬‬
‫'‪>>> stuff = 'Hello world‬‬
‫)‪>>> type (stuff‬‬
‫>'‪<class 'str‬‬
‫)‪>>> dir (stuff‬‬
‫‪['capitalize', 'casefold', 'center', 'count', 'encode',‬‬
‫‪'endswith' , 'expandtabs', 'find', 'format', 'format_map',‬‬
‫‪'index' , 'isalnum', 'isalpha', 'isdecimal', 'isdigit',‬‬
‫‪'isidentifier' , 'islower', 'isnumeric', 'isprintable',‬‬
‫‪'isspace' , 'istitle', 'isupper', 'join', 'ljust', 'lower',‬‬
‫‪'lstrip' , 'maketrans', 'partition', 'replace', 'rfind',‬‬
‫‪'rindex' , 'rjust', 'rpartition', 'rsplit', 'rstrip',‬‬
‫‪'split' , 'splitlines', 'startswith', 'strip', 'swapcase',‬‬
‫]'‪'title' , 'translate', 'upper', 'zfill‬‬
‫)‪>>> help (str.capitalize‬‬
‫‪Help on method_descriptor:‬‬
‫)‪capitalize(...‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪93‬‬
‫‪S.capitalize() -> str‬‬
‫‪Return a capitalized version of S, i.e. make the first character‬‬
‫‪have upper case and the rest lower case.‬‬
‫>>>‬
‫باإلمكان استعر ُ‬
‫اض التوابع باستخدام التابع ‪ ،dir‬كما يمكن استخدام ‪ help‬للحصول على شرح‬
‫مختصر عن تابع ما‪َّ ،‬أما للحصو ُل على ملفات تفصيلية خاصة بتوابع السالسل النصية‪ ،‬فمن‬
‫األفضل زيارة الرابط‪https://docs.python.org/library/stdtypes.html#string-methods. :‬‬
‫َ‬
‫استدعاء التابع العادي (‪ )function‬حيث كالهما يأخذان‬
‫يشابه استدعاء تابع الصنف (‪(method‬‬
‫َ‬
‫وسائط ويعيدان قيمة لكن قواعد الكتابة ُمختلفة‪ .‬نستدعي َ‬
‫توابع الصنف عن طريق إلحاق اسمها‬
‫باسم املتغير باستخدام عامل النقطة‪.‬‬
‫ً‬
‫ً‬
‫ً‬
‫ً‬
‫يأخذ التابع ‪-،upper‬مثال‪ -‬سلسلة نصية ليعيد نسخة منها مكتوبة بأحرف كبيرة؛ فبدال من كتابة‬
‫التابع بالشكل (‪ upper(word‬نكتب ()‪.word.upper‬‬
‫'‪>>> word = 'banana‬‬
‫)( ‪>>> new_word = word.upper‬‬
‫)‪>>> print(new_word‬‬
‫‪BANANA‬‬
‫َ‬
‫عامل النقطة َ‬
‫يحدد ُ‬
‫واسم السلسلة النصية التي سيتعامل معها التابع ‪.word‬‬
‫اسم التابع ‪upper‬‬
‫َ‬
‫ُ‬
‫يشير وجود أقواس فارغة إلى َّ‬
‫أن التابع ال يأخذ وسائط‪.‬‬
‫َ‬
‫ُ‬
‫التابع ‪ upper‬على‬
‫استخدام التابع باالستدعاء وفي هذه الحالة يمكن القول‪ :‬إننا نستخدم‬
‫ُيدعى‬
‫السلسلة النصية ‪.word‬‬
‫ً‬
‫فمثال‪ ،‬لدينا تابع لسلسلة نصية يدعى ‪ find‬يبحث عن موقع سلسلة نصية َّ‬
‫محدد في سلسلة نصية‬
‫أخرى‪.‬‬
‫'‪>>> word = 'banana‬‬
‫)'‪>>> index = word.find('a‬‬
‫)‪>>> print(index‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪94‬‬
‫‪1‬‬
‫َ‬
‫َ‬
‫التابع ‪ find‬على السلسلة النصية ‪ word‬وأدخلنا املحرف الذي نبحث‬
‫استخدمنا‪-‬في املثال السابق‪-‬‬
‫َ‬
‫محرف ما‪.‬‬
‫سالسل فرعية أو‬
‫عنه على َّأنه وسيط‪ .‬يمكن لهذا التابع العثور على‬
‫ٍ‬
‫)'‪>>> word.find('na‬‬
‫‪2‬‬
‫ً‬
‫قد يأخذ وسيطا آخر يعبر عن الفهرس الذي يجب أن يبدأ عنده البحث‪.‬‬
‫)‪>>> word.find('na', 3‬‬
‫‪4‬‬
‫َ‬
‫التابع ‪ strip‬للتخلص من املسافات البيضاء (مسافات فارغة‪ ،‬إزاحة باستخدام املفتاح‬
‫نستخدم‬
‫‪ ،tap‬محارف السطور الجديدة) من بداية السلسلة النصية أو نهايتها‪.‬‬
‫'‬
‫‪Here we go‬‬
‫' = ‪>>> line‬‬
‫)(‪>>> line.strip‬‬
‫'‪'Here we go‬‬
‫مثل ‪ً startswith‬‬
‫تعيد بعض التوابع‪ُ ،‬‬
‫قيما منطقية‪.‬‬
‫'‪>>> line = 'Have a nice day‬‬
‫)'‪>>> line.startswith('Have‬‬
‫‪True‬‬
‫)'‪>>> line.startswith('h‬‬
‫‪False‬‬
‫ُ‬
‫ُ‬
‫تحويل سلسة نصية إلى‬
‫ستلحظ أن التابع ‪ startswith‬يحتاج إلى معامل ملطابقته‪ ،‬لذا من األحسن‬
‫أحرف صغيرة باستخدام التابع ‪َ lower‬‬
‫قبل القيام بأي عمليات مطابقة‪.‬‬
‫'‪>>> line = 'Have a nice day‬‬
‫)'‪>>> line.startswith('h‬‬
‫‪False‬‬
‫)(‪>>> line.lower‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪95‬‬
‫'‪'have a nice day‬‬
‫)'‪>>> line.lower().startswith('h‬‬
‫‪True‬‬
‫ُ‬
‫التابع ‪ ،lower‬فنستخدم ‪ startswith‬للتحقق من أن السلسة النصية‬
‫في املثال األخير ُيستدعى‬
‫برمجي واحد مع‬
‫تعبير‬
‫الناتجة تبدأ بمحرف"‪ ،"h‬وباإلمكان القيام ٍ‬
‫بعدد من االستدعاءات للتوابع في ٍ‬
‫ٍ‬
‫أخذ الترتيب باالعتبار‪.‬‬
‫َّ‬
‫ٌ‬
‫مشابه ً‬
‫تماما ملا قمنا به في التمارين السابقة‪ ،‬وتتوفر‬
‫التمرين الرابع‪ :‬يوجد تابع صنف ُيدعى ‪count‬‬
‫معلومات عن هذا التابع في الرابط التالي‪:‬‬
‫‪https://docs.python.org/library/stdtypes.html#string-methods‬‬
‫اكتب شيفرة برمجية لعد َّ‬
‫مرات ظهور الحرف "‪ "a‬في كلمة "‪ "banana‬باستدعاء هذا التابع‪.‬‬
‫‪ 10.6‬تحليل السالسل النصية‬
‫ً‬
‫َ‬
‫ضمن السلسلة النصية‪ ،‬على سبيل املثال‪ :‬في حال‬
‫أحيانا إلى البحث عن سلسلة فرعية‬
‫قد نحتاج‬
‫لدينا مجموعة من األسطر كالتالية‪:‬‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫ونريد استخر َ‬
‫اج النصف الثاني من عنوان البريد االلكتروني املعطى‪ ،‬أي (‪ )uct.ac.za‬من كل سطر‪:‬‬
‫يمكننا القيام بذلك من خالل استخدام التابع ‪ find‬وتجزئة السلسلة النصية‪.‬‬
‫ً‬
‫بداية عن موقع عالمة @ في السلسلة النصية ُثم نحدد موقع َّأول مسافة فارغة َ‬
‫بعد عالمة @‬
‫نبحث‬
‫َ‬
‫ومن ثم نجزئ السلسلة النصية القتطاع الجزء املطلوب من السلسلة‪.‬‬
‫'‪>>> data = 'From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫)'@'(‪>>> atpos = data.find‬‬
‫)‪>>> print(atpos‬‬
‫‪21‬‬
‫)‪>>> sppos = data.find(' ',atpos‬‬
‫)‪>>> print(sppos‬‬
‫‪31‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪96‬‬
‫]‪>>> host = data[atpos+1:sppos‬‬
‫)‪>>> print(host‬‬
‫‪uct.ac.za‬‬
‫>>>‬
‫اإلصدار من التابع ‪ find‬بتحديد املوقع في السلسلة النصية الذي نريد منه َ‬
‫ُ‬
‫بدء البحث‪.‬‬
‫يسمح هذا‬
‫َ‬
‫املحارف ً‬
‫بدءا من املحرف الذي يلي إشارة @ حتى املحرف الذي‬
‫اقتطعنا بعملية التجزئة السابقة‬
‫يسبق املسافة الفارغة‪.‬‬
‫ملزيد من املعلومات عن التابع ‪ ،find‬باإلمكان زيارة الرابط التالي‪:‬‬
‫‪https://docs.python.org/library/stdtypes.html#string-methods‬‬
‫‪ 11.6‬عامل التنسيق‬
‫عامل التنسيق ‪َ %‬‬
‫َ‬
‫ُ‬
‫سالسل نصية واستبدال أجزاء منها‪ ،‬ببيانات مخزنة في املتغيرات‪ُ .‬يمثل‬
‫بناء‬
‫يتيح‬
‫ُ‬
‫عامل باقي القسمة لكن عندما يكون املعامل َّ‬
‫َ‬
‫األول‬
‫الرمز ‪ %‬عند استعماله مع األعداد الصحيحة‬
‫ً‬
‫سلسلة نصية يكون عامل تنسيق‪.‬‬
‫ُ‬
‫حيث َّ‬
‫األول ‪-‬وهو سلسلة نصية‪ً -‬‬
‫يضم املعامل َّ‬
‫إن‬
‫رموزا محددة لتحدد كيفية تنسيق املعامل الثاني‬
‫ً‬
‫ٌ‬
‫نتيجة هذه العملية هي سلسلة نصية؛ فمثال يشير رمز التنسيق ‪ %d‬إلى أن املعامل الثاني يجب أن‬
‫ُي َن َّسق باعتباره ً‬
‫ً‬
‫ً‬
‫اختصارا لـ ‪.)decimal‬‬
‫صحيحا (‪d‬‬
‫عددا‬
‫‪>>> camels = 42‬‬
‫‪>>> '%d' % camels‬‬
‫'‪'42‬‬
‫َّ َ‬
‫ينتج َّ‬
‫مما سبق السلسلة النصية '‪ '42‬ويجب أال ُيخلط بينها وبين العدد الصحيح ‪.42‬‬
‫ُ‬
‫يمكن أن تظهر رموز التنسيق في أي مكان من السلسلة حيث يمكنك ذلك من إضافة جملة معينة‪.‬‬
‫‪>>> camels = 42‬‬
‫‪>>> 'I have spotted %d camels.' % camels‬‬
‫'‪'I have spotted 42 camels.‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪97‬‬
‫ُ‬
‫في حال وجود َ‬
‫أكثر من رمز تنسيق في السلسلة النصية؛ فالوسيط الثاني يجب أن يكون من نوع‬
‫ٌ‬
‫البيانات صف (‪ُّ .)Tuple‬‬
‫كل رمز تنسيق مرتبط بعنصر من الصف َح َس َب الطلب‪.‬‬
‫ُ‬
‫املثال التالي ‪ %d‬لتنسيق عدد صحيح ‪ g%‬لتنسيق رقم ذي فاصلة عشرية و‪ %s‬لتنسيق‬
‫يستخدم‬
‫سلسلة نصية‪.‬‬
‫)'‪>>> 'In %d years I have spotted %g %s.' % (3, 0.1, 'camels‬‬
‫'‪'In 3 years I have spotted 0.1 camels.‬‬
‫عدد العناصر في الصف َ‬
‫يجب أن يساوي ُ‬
‫عدد رموز التنسيق في السلسلة النصية‪ ،‬كما يجب أن‬
‫َ‬
‫يرتبط نوع العناصر بتسلسل التنسيق‪.‬‬
‫)‪>>> '%d %d %d' % (1, 2‬‬
‫‪TypeError: not enough arguments for format string‬‬
‫ُ‬
‫ٌ‬
‫ال توجد وسائط كافية لتنسيق السلسلة‪.‬‬
‫'‪>>> '%d' % 'dollars‬‬
‫‪TypeError: %d format: a number is required, not str‬‬
‫رمز التنسيق ‪ %d‬يتطلب رق ًما وليس سلسلة نصية‪.‬‬
‫ٌ‬
‫ُ‬
‫ال يوجد في املثال َّ‬
‫كاف ونوع العنصر في الثاني خطأ‪.‬‬
‫األول عدد عناصر ٍ‬
‫عامل التنسيق قو ٌّي ومفيد لكنة صعب االستخدام‪ ،‬باإلمكان قراءة املزيد عنه من خالل الرابط التالي‪:‬‬
‫‪https://docs.python.org/library/stdtypes.html#printf-style-string-formatting‬‬
‫‪ 12.6‬التنقيح‬
‫ُ‬
‫حيث َ‬
‫إنك ُمبرمج‪ -‬هي أن تسأل نفسك ً‬
‫دوما‪" :‬ما الخطأ الذي يمكن‬
‫املهارة التي ينبغي لك تطويرها ‪-‬من‬
‫ُ‬
‫فعلها لتفشل بر ُ‬
‫امجنا التي تبدو‬
‫أن يحصل هنا أو باألحرى ما هي األشياء التي يمكن للمستخدم‬
‫مثالية؟"‪.‬‬
‫البرنامج الذي استخدمناه لشرح حلقة ‪ while‬في فصل َّ‬
‫َ‬
‫التكرار‪:‬‬
‫على سبيل املثال‪ ،‬لنعد إلى‬
‫‪while True:‬‬
‫)' >'(‪line = input‬‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪98‬‬
‫‪if line[0] == '#':‬‬
‫‪continue‬‬
‫‪if line == 'done':‬‬
‫‪break‬‬
‫)‪print(line‬‬
‫)'!‪print('Done‬‬
‫‪# Code: http://www.py4e.com/code3/copytildone2.py‬‬
‫ً‬
‫انتبه ما الذي يحصل عندما ُيدخل املستخدم ً‬
‫سطرا فارغا‪.‬‬
‫‪> hello there‬‬
‫‪hello there‬‬
‫‪> # don't print this‬‬
‫!‪> print this‬‬
‫!‪print this‬‬
‫>‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "copytildone.py", line 3, in <module‬‬
‫‪if line[0] == '#':‬‬
‫‪IndexError: string index out of range‬‬
‫تظهر رسالة خطأ "خطأ في الفهرسة‪ :‬فهرس السلسلة النصية خارج املجال"‬
‫ً‬
‫عمال ً‬
‫ٌ‬
‫سطر فارغ‪ ،‬في هذه الحالة ال يوجد محرف في املوقع [‪]0‬‬
‫سليما حتى ُيدخل‬
‫سيعمل البرنامج‬
‫لذلك نحصل على تقرير بالخطأ‪ ،‬ثمة حالن لهذه املشكلة‪.‬‬
‫ُ‬
‫استخدام التابع ‪ startswith‬الذي يعيد الثابت املنطقي ‪ False‬في حال‬
‫أحد هذه الحلول هي بسهولة‬
‫كانت السلسلة النصية فارغة‪.‬‬
‫‪if line.startswith('#'):‬‬
‫أكثر ً‬
‫الطريقة األخرى ُ‬
‫أمانا وهي باستخدام عبارة ‪ if‬الشرطية مع استخدام تعليمات تفادي األخطاء‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪99‬‬
‫ُ‬
‫تحقق من الشرط الثاني إال في حال َّ‬
‫بحيث ال ُي َّ‬
‫ُ‬
‫تحقق َّ‬
‫وجود محرف واحد‬
‫األول وهو‬
‫باستخدام شرطين‬
‫على األقل‪.‬‬
‫‪if len(line) > 0 and line[0] == '#':‬‬
‫‪ 13.6‬فهرس املصطلحات‬
‫ً‬
‫● العداد (‪ :)counter‬هو متغير لعد ش يء ما‪ ،‬عادة ما يبدأ من الصفر وتزداد قيمته‪.‬‬
‫ُ َّ‬
‫● سلسلة نصية فارغة (‪ :)empty string‬هي سلسلة نصية دون أي محارف وطولها ‪ ،0‬تمثل‬
‫باستخدام عالمتي االقتباس‪.‬‬
‫ُ‬
‫َ‬
‫● عامل التنسيق (‪ :)format operator‬هو العامل ‪ %‬يطلب رموز التنسيق َوصف لتوليد‬
‫سلسلة نصية تتضمن عناصر الصف ُمنسقة على َوفق رموز التنسيق‪.‬‬
‫َُ‬
‫● رموز التنسيق )‪ :)format sequence‬سلسلة من املحارف‪َ ،‬‬
‫مثل‪ %d :‬تحدد كيف تن َّسق‬
‫ٌ‬
‫قيمة معينة‪.‬‬
‫ُ‬
‫ُ‬
‫● سلسلة التنسيق )‪ :)format string‬سلسلة نصية تستخدم مع عامل التنسيق بحيث‬
‫َ‬
‫تتضمن رموز تنسيق‪.‬‬
‫َ‬
‫محقق أو غير َّ‬
‫منطقي يشير فيما إذا كان الشرط َّ‬
‫ٌّ‬
‫محقق‪.‬‬
‫● العلم )‪ :(flag‬متغير‬
‫● استدعاء (‪ :(invocation‬عبارة نستدعي من خاللها تابع الصنف‪.‬‬
‫ٌ‬
‫ُ‬
‫تعديل عناصرها‪.‬‬
‫● غيرقابل للتعديل )‪ :)Immutable‬ميزة للسالسل بحيث ال يمكن‬
‫● الفهرس (‪ٌ :)index‬‬
‫عدد صحيح ُيستخدم لتحديد عنصر في سلسلة مثل محرف ضمن‬
‫سلسلة نصية‪.‬‬
‫● عنصر (‪ُ :)item‬‬
‫أحد القيم في سلسلة ما‪.‬‬
‫ٌ‬
‫● تابع الصنف (‪ :)method‬تابع مرتبط بكائن ُويستدعى باستخدام عامل النقطة‪.‬‬
‫● الكائن (‪ :)object‬ش ٌيء يمكن للمتحول أن يشير إليه‪ ،‬حتى اآلن يمكنك ُّ‬
‫عد "الكائن"‬
‫و"القيمة" الش َيء َ‬
‫نفسه‪.‬‬
‫● البحث )‪ٌ :)search‬‬
‫شكل من أشكال املرور على عناصر سلسلة بحيث يتوقف عندما يجد ما‬
‫الفصل السادس‪ :‬السالسل النصية‬
‫‪100‬‬
‫ُ‬
‫يبحث عنه‪.‬‬
‫ٌ‬
‫ٌ‬
‫مرتبة من القيم بحيث ُّ‬
‫كل قيمة معرفة باستخدام فهرس‪.‬‬
‫● سلسلة (‪ :)sequence‬مجموعة‬
‫جزء من السلسلة النصية َّ‬
‫● شريحة (‪ٌ :)slice‬‬
‫املحدد بعدد من الفهارس‪.‬‬
‫● املرور على عناصر السلسة )‪ :)traverse‬املرور على عناصر سلسلة وإجراء عمليات مماثلة‬
‫في كل مرة‪.‬‬
‫‪ 14.6‬تمارين‬
‫• التمرين الخامس‪ :‬الشيفرة البرمجية التالية مكتوبة بلغة بايثون تخزن سلسلة نصية‪:‬‬
‫'‪str = 'X-DSPAM-Confidence:0.8475‬‬
‫استخدم تعليمة ‪ find‬وتجزئة السالسل النصية القتطاع الجزء من السلسلة الواقع َ‬
‫بعد النقطتين‬
‫ُ‬
‫ُ‬
‫عدد ذي فاصلة عشرية‪.‬‬
‫ثم استخدم التابع ‪ float‬لتحويل السلسلة املقتطعة إلى ٍ‬
‫• التمرين السادس‪ :‬اقرأ توصيف توابع السلسلة النصية عبر زيارة الرابط‪:‬‬
‫‪https://docs.python.org/library/stdtypes.html#string-methods‬‬
‫من املفيد التعامل مع أحدها للتأكد من فهمها وفهم كيف عملها‪ .‬مثل ‪ strip‬و‪ replace‬فهما‬
‫مفيدان ًّ‬
‫جدا‪.‬‬
‫ً‬
‫ً‬
‫قد يعترضك أثناء قراءة التوصيف جمال قد تكون غير مفهومة‪ ،‬مثال‪:‬‬
‫)]]‪in find (sub[, start[, end‬‬
‫َ‬
‫ٌ‬
‫مطلوب لكن ‪ start‬اختيارية‪ ،‬وفي‬
‫تشير األقواس إلى وسائط اختيارية‪ ،‬أي أن الوسيط ‪sub‬‬
‫حال ُ‬
‫ضمنت ‪ start‬تكون ‪ end‬اختيارية‪.‬‬
‫الفصل السابع‬
‫امللفات‬
‫الفصل السابع‪ :‬امللفات‬
‫‪102‬‬
‫‪ 7‬ا ِّمللفات‬
‫‪ 1.7‬اإلصرارعلى التعلم‬
‫تعلمنا حتى اآلن كيفية كتابة البرامج وتنفيذ ما نريده عبر وحدة املعالجة املركزية باستخدام التنفيذ‬
‫املشروط والتوابع َّ‬
‫والتكرار‪ .‬كما تعلمنا كيفية إنشاء بنى البيانات (‪ )data structures‬واستخدامها في‬
‫الذاكرة الرئيسة‪ .‬حيث ُيخزن ال َ‬
‫برنامج ُوينفذ في وحدة املعالجة املركزية والذاكرة ُويعتبران املكان الذي‬
‫يحدث فيه "التفكير"‪ .‬ولكن إذا َ‬
‫كنت تتذكر نقاشنا عن بنية الحاسب‪ ،‬فبمجرد فصل التغذية‬
‫الكهربائية عن الحاسوب‪ُ ،‬يحذف أي ش يء مخزن في وحدة املعالجة املركزية أو في الذاكرة الرئيسية‪.‬‬
‫ما األمر التالي؟‬
‫الشبكة‬
‫الذاكرة الثانوية‬
‫البرمجيات‬
‫وحدة املعالجة املركزية‬
‫أجهزة الدخل والخرج‬
‫الذاكرةالرئيسية‬
‫الشكل ‪: 10‬الذاكرة الثانوية‬
‫َّ‬
‫سنتعرف في هذا الفصل إلى وسيط تخزين جديد ُيسمى الذاكرة الثانوية (أو امللفات)‪ .‬تمتاز الذاكرة‬
‫الثانوية بعدم فقدانها محتوياتها عند فقدان الطاقة‪ .‬أو في حالة وحدة تخزين متنقلة (‪،)USB Flash‬‬
‫يمكن إزالة البيانات‪-‬التي نكتبها من برامجنا‪ -‬من النظام ونقلها إلى نظام َ‬
‫آخر‪.‬‬
‫سنركز ً‬
‫أساسيا على قراءة امللفات النصية وكتابتها‪َ ،‬‬
‫ًّ‬
‫مثل تلك التي ننشئها في محرر النصوص‪.‬‬
‫تركيزا‬
‫سنرى ً‬
‫ً‬
‫الحقا كيفية العمل مع ملفات قواعد البيانات وهي ملفات ثنائية (‪َّ ،)Binary‬‬
‫خصيصا‬
‫مصممة‬
‫للقراءة والكتابة من خالل برمجيات َمعنية بقواعد البيانات‪.‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪103‬‬
‫‪ 2.7‬فتح ا ِّمللفات‬
‫عندما نريد قراءة ملف أو الكتابة عليه ‪-‬على سبيل املثال‪ :‬ملف محفوظ على محرك األقراص‬
‫ً‬
‫الصلبة‪ ،-‬يجب َّأوال فتح امللف‪ .‬يؤدي فتح امللف إلى االتصال بنظام تشغيلك‪ ،‬الذي يعرف مكان‬
‫تخزين البيانات الخاصة بكل ملف‪ .‬عندما تفتح م ًلفا‪ ،‬فإنك تطلب من نظام التشغيل العثور على‬
‫امللف باالسم والتأكد من وجوده‪ .‬يوضح املثال أدناه طريقة فتح امللف النص ي ‪ ،mbox.txt‬الذي يجب‬
‫تخزينه في املجلد نفسه الذي استخدمته عند بدء تشغيل بايثون‪ .‬يمكنك تنزيل هذا امللف من خالل‬
‫الضغط على الرابط التالي‪:‬‬
‫‪www.py4e.com/code3/mbox.txt‬‬
‫)'‪>>> fhand = open('mbox.txt‬‬
‫)‪>>> print(fhand‬‬
‫>'‪<_io.TextIOWrapper name='mbox.txt' mode='r' encoding='cp1252‬‬
‫ُ‬
‫ً‬
‫بنجاح‪ ،‬فسيعيد لنا نظام التشغيل معرفا للملف (‪ .)file handle‬ال يمثل املعرف‬
‫لف‬
‫امل‬
‫تح‬
‫ف‬
‫إذا‬
‫ٍ‬
‫ً‬
‫ً‬
‫البيانات الفعلية املوجودة في امللف‪ ،‬ولكنه بدال من ذلك يكون واجهة يمكننا استخدامها لقراءة‬
‫ً‬
‫البيانات‪ُ .‬ت َ‬
‫ً‬
‫موجودا ولديك األذونات املطلوبة لقراءة امللف‪.‬‬
‫منح معرفا للملف إذا كان امللف املطلوب‬
‫الشكل ‪ :11‬معرف امللف‬
‫الفصل السابع‪ :‬امللفات‬
‫‪104‬‬
‫ً‬
‫موجودا‪ ،‬فستفشل عملية الفتح ُ‬
‫وسيعرض في الشاشة تقرير بالخطأ ولن تحصل‬
‫إذا لم يكن امللف‬
‫على معرف للوصول إلى محتويات امللف كما يوضح املثال التالي‪:‬‬
‫)'‪>>> fhand = open('stuff.txt‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "<stdin>", line 1, in <module‬‬
‫'‪FileNotFoundError: [Errno 2] No such file or directory: 'stuff.txt‬‬
‫سوف نستخدم ً‬
‫الحقا خاصية التعامل مع االستثناءات ‪ try/except‬للتعامل بأمان َ‬
‫أكثر مع الحاالت‬
‫التي نحاول فيه فتح ملف غير موجود‪.‬‬
‫‪3.7‬‬
‫ِّملفات النصوص واألسطر‬
‫يمكن عد امللف النص ي على أنه سلسلة من األسطر‪ُ ،‬‬
‫مثل السلسلة النصية في لغة بايثون التي يمكن‬
‫ً‬
‫اعتبارها سلسلة من املحارف‪ .‬مثال‪ ،‬هذه عينة من ملف نص ي يسجل نشاط البريد من أفراد مختلفين‬
‫مشروع مفتوح املصدر‪.‬‬
‫في فريق تطوير‬
‫ٍ‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫>‪Return-Path: <postmaster@collab.sakaiproject.org‬‬
‫‪Date: Sat, 5 Jan 2008 09:12:18 -0500‬‬
‫‪To: source@collab.sakaiproject.org‬‬
‫‪From: stephen.marquard@uct.ac.za‬‬
‫‪Subject: [sakai] svn commit: r39772 - content/branches/‬‬
‫‪Details: http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772‬‬
‫ً‬
‫يمكنك الحصول على ملف نشاطات البريد اإللكتروني كامال من خالل الضغط على الرابط التالي‪:‬‬
‫‪www.py4e.com/code3/mbox.txt‬‬
‫كما يمكنك الحصو ُل على النسخة املختصرة من هذا امللف من خالل الضغط على الرابط التالي‪:‬‬
‫‪www.py4e.com/code3/mbox-short.txt‬‬
‫هذه امللفات ذات صيغة قياسية؛ إذ يحتوي امللف على عدد من رسائل بريدية‪ .‬واألسطر التي تبدأ‬
‫بكلمة "‪ "From‬تفصل بين الرسائل املختلفة‪ .‬األسطر التي تبدأ بكلمة "‪ُ "From‬تعد ً‬
‫جزءا من الرسائل‪.‬‬
‫ملعرفة املزيد من املعلومات عن صيغة رسائل البريد‪ ،‬باإلمكان زيارة الرابط التالي‪:‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪105‬‬
‫‪https://en.wikipedia.org/wiki/Mbox‬‬
‫ٌ‬
‫لتقسيم امللف إلى عدد من األسطر‪ُ ،‬يستخدم محرف خاص ُيمثل "نهاية السطر" ويطلق عليه اسم‬
‫محرف السطر الجديد (‪.)newline‬‬
‫ٌ‬
‫تستخدم في لغة باثيون شرطة مائلة عكسية (‪ )backslash‬مع حرف ‪ n‬في السالسل النصية إلنشاء‬
‫ٌ‬
‫سطر جديد ‪ . \n‬على الرغم من أن محرف إنشاء سطر جديد يبدو محرفين‪ ،‬فهو في الواقع محرف‬
‫واحد‪ .‬عندما نكتب املتغير ‪ stuff‬في مفسر لغة بايثون‪ ،‬فإنه يظهر ‪ \n‬في السلسلة النصية الناتجة‪،‬‬
‫ولكن عندما نستخدم ‪ print‬إلظهار السلسلة‪ ،‬نرى السلسلة َّ‬
‫مقسمة إلى سطرين بواسطة محرف‬
‫السطر الجديد‪ .‬املثال التالي يوضح كيفية إنشاء سطر جديد في لغة بايثون‪:‬‬
‫'!‪>>> stuff = 'Hello\nWorld‬‬
‫‪>>> stuff‬‬
‫'!‪'Hello\nWorld‬‬
‫)‪>>> print(stuff‬‬
‫‪Hello‬‬
‫!‪World‬‬
‫'‪>>> stuff = 'X\nY‬‬
‫)‪>>> print(stuff‬‬
‫‪X‬‬
‫‪Y‬‬
‫)‪>>> len(stuff‬‬
‫‪3‬‬
‫ُ‬
‫ً‬
‫مالحظة أن طول السلسلة ‪ X \nY‬هو ثالثة؛ َّ‬
‫يجدر بك ً‬
‫ألن حرف السطر الجديد ‪ُ \n‬يعتبر محرفا‬
‫أيضا‬
‫ً‬
‫واحدا‪.‬‬
‫ً‬
‫محرفا ًّ‬
‫خاصا َ‬
‫غير مرئي ُيسمى‬
‫لذلك عندما ننظر إلى السطور في ملف ما‪ ،‬علينا أن نتخيل أن ثمة‬
‫محرف السطر الجديد في نهاية كل سطر ُيمثل نهاية السطر‪ .‬أي أن محرف السطر الجديد يفصل‬
‫املحارف في امللف إلى سطور‪.‬‬
‫‪ 4.7‬قراءة ا ِّمللفات‬
‫على الرغم من أن معرف امللف ال يحتوي على بيانات امللف‪َّ ،‬‬
‫فإن من السهل ًّ‬
‫َ‬
‫إنشاء حلقة ‪for‬‬
‫جدا‬
‫الفصل السابع‪ :‬امللفات‬
‫‪106‬‬
‫لقراءة كل سطر وعده‪ ،‬من سطور امللف‪:‬‬
‫)'‪fhand = open('mbox-short.txt‬‬
‫‪count = 0‬‬
‫‪for line in fhand:‬‬
‫‪count = count + 1‬‬
‫)‪print('Line Count:', count‬‬
‫‪# Code: http://www.py4e.com/code3/open.py‬‬
‫ً‬
‫سلسلة َّ‬
‫للتكرار في حلقة ‪ for‬حيث تحسب حلقة ‪ for‬بسهولة َ‬
‫عدد‬
‫يمكننا استخدام معرف امللف‬
‫األسطر في امللف وتطبعها‪ .‬بمعنى آخر‪ ،‬يمكن تلخيص عمل حلقة ‪ for‬كالتالي‪ :‬لكل سطر في امللف‬
‫املمثل بمعرف امللف‪ ،‬أضف ً‬
‫واحدا إلى املتغير ‪.count‬‬
‫كبيرا ًّ‬
‫يعود السبب في أن تابع فتح امللفات ‪ open‬ال يقرأ امللف بالكامل إلى أن امللف قد يكون ً‬
‫جدا وقد‬
‫يصل ُ‬
‫حجمه إلى أكثر من واحد غيغابايت‪ .‬تستغرق تعليمة ‪َ open‬‬
‫نفس القدر من الوقت بغض النظر‬
‫عن حجم امللف وتعمل حلقة ‪ for‬على قراءة البيانات من امللف‪.‬‬
‫ُ‬
‫َ‬
‫ُ‬
‫حين ُيقرأ امللف باستخدام حلقة ‪ for‬بهذه الطريقة؛ تقسم لغة بايثون البيانات املوجودة في امللف إلى‬
‫أسطر منفصلة باستخدام محرف إنشاء السطر الجديد ‪ .\n‬تقرأ لغة بايثون كل سطر عن طريق‬
‫َ‬
‫ٌ‬
‫َ‬
‫محرف إنشاء السطر الجديد وتضيف هذا املحرف على أنه محرف أخير في املتغير ‪ line‬لكل تكرار‬
‫للحلقة ‪.for‬‬
‫َ‬
‫سطرا ً‬
‫ُ‬
‫ً‬
‫ً‬
‫وحسابها‬
‫واحدا في كل مرة‪ ،‬فمن ثم يمكنها قراءة األسطر‬
‫نظرا إلى أن حلقة ‪ for‬تقرأ البيانات‬
‫بكفاءة في امللفات الكبيرة ًّ‬
‫َ‬
‫للبرنامج أعاله‬
‫جدا دون نفاد الذاكرة الرئيسة لتخزين البيانات‪ .‬يمكن‬
‫حساب األسطر في أي ملف بأي حجم باستخدام ذاكرة ذات حجم صغير ًّ‬
‫ُ‬
‫جدا؛ إذ ُيقرأ كل سطر ويعد‬
‫ثم نتخلص منه‪.‬‬
‫إذا كنت تعلم أن امللف صغير ًّ‬
‫نسبيا موازنة بحجم ذاكرتك الرئيسة‪ ،‬فيمكنك قراءة امللف بأكمله في‬
‫سلسلة واحدة باستخدام تابع القراءة ‪.read‬‬
‫)'‪>>> fhand = open('mbox-short.txt‬‬
‫)(‪>>> inp = fhand.read‬‬
‫))‪>>> print(len(inp‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪107‬‬
‫‪94626‬‬
‫)]‪>>> print(inp[:20‬‬
‫‪From stephen.marquar‬‬
‫ُ‬
‫ً‬
‫ً‬
‫في املثال أعاله‪ ،‬قرئت محتويات امللف ‪ mbox-short.txt‬بالكامل ‪ 94626-‬محرفا‪ -‬مباشرة في املتغير‬
‫ً‬
‫‪ .inp‬كما يوضح املثال استخدام تعليمة تجزئة السالسل النصية لطباعة َّأول ‪ 20‬حرفا من بيانات‬
‫السلسلة املخزنة في املتغير ‪.inp‬‬
‫عند قراءة امللف بهذه الطريقة‪ ،‬فإن جميع املحارف‪ ،‬بما في ذلك جميع األسطر ومحارف إنشاء‬
‫ُ‬
‫السطر الجديد‪ ،‬تعتبر سلسلة واحدة كبيرة ضمن املتغير ‪ .inp‬تجدر اإلشارة إلى أنه من الجيد تخزين‬
‫ناتج القراءة ضمن متغير وذلك ألن كل استدعاء للقراءة يستنفد املورد وهذا ما يوضحه املثال التالي‪:‬‬
‫)'‪>>> fhand = open('mbox-short.txt‬‬
‫)))(‪>>> print(len(fhand.read‬‬
‫‪94626‬‬
‫)))(‪>>> print(len(fhand.read‬‬
‫‪0‬‬
‫كما عليك أن تضع في الحسبان أنه يجب استخدام هذه الصيغة لتابع فتح امللفات ‪ open‬فقط إذا‬
‫كبيرا ًّ‬
‫كانت بيانات امللف مناسبة بشكل مريح للذاكرة الرئيسة لحاسوبك‪َّ .‬أما إذا كان امللف ً‬
‫جدا‬
‫َ‬
‫البرنامج لقراءة محتويات امللف في أجزاء‬
‫بحيث ال يتسع للذاكرة الرئيسة‪ ،‬فيجب عليك كتابة‬
‫باستخدام حلقة ‪ for‬أو ‪.while‬‬
‫‪ 5.7‬البحث خالل ِّملف‬
‫عندما تبحث عن بيانات في ملف‪ ،‬من الشائع ًّ‬
‫جدا تجاهل معظم السطور والتركيز في معالجة األسطر‬
‫َ‬
‫التي تفي بشرط ُمعين فقط‪ .‬يمكننا دمج نمط قراءة ملف مع التوابع املستخدمة مع السالسل النصية‬
‫إلنشاء آليات بحث سهلة‪.‬‬
‫على سبيل املثال‪ ،‬إذا أردنا قراءة ملف وطباعة األسطر التي بدأت بالبادئة "‪ ":From‬فقط‪ ،‬فيمكننا‬
‫استخدام التابع ‪ startswith‬لتحديد تلك األسطر التي تحتوي على البادئة املطلوبة فقط كما في املثال‬
‫التالي‪:‬‬
‫)'‪fhand = open('mbox-short.txt‬‬
‫‪count = 0‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪108‬‬
‫‪for line in fhand:‬‬
‫‪if line.startswith('From: '):‬‬
‫)‪print(line‬‬
‫‪# Code: http://www.py4e.com/code3/search1.py‬‬
‫َ‬
‫البرنامج‪ ،‬نحصل على املخرجات التالية‪:‬‬
‫عندما ُينفذ هذا‬
‫‪From: stephen.marquard@uct.ac.za‬‬
‫‪From: louis@media.berkeley.edu‬‬
‫‪From: zqian@umich.edu‬‬
‫‪From: rjlowe@iupui.edu‬‬
‫‪...‬‬
‫تبدو هذه املخرجات رائعة ألن األسطر الوحيدة التي نراها هي تلك التي تبدأ بـ ‪ ،from:‬ولكن ملاذا نرى‬
‫األسطر الفارغة اإلضافية؟ ُيعزى ذلك إلى استخدام محرف إنشاء السطر الجديد الذي ال ُي َ‬
‫طبع بل‬
‫يظهر تأثيره َ‬
‫فحسب‪ .‬ينتهي كل سطر بمحرف إنشاء السطر الجديد‪ ،‬لذا فإن تعليمة الطباعة التي‬
‫ً‬
‫سطرا‬
‫تطبع السلسلة في املتغير ‪ line‬الذي يتضمن محرف سطر جديد ثم تضيف تعليمة الطباعة‬
‫ً‬
‫جديدا آخر‪ ،‬مما يؤدي إلى وجود تباعد أو مسافة مزدوجة بين األسطر‪.‬‬
‫َ‬
‫يمكننا استخدام طريقة تجزئة األسطر لطباعة كل املحارف ما عدا املحرف األخير‪ ،‬ولكن الطريقة‬
‫األنسب هي استخدام التابع ‪ rstrip‬الذي يحذف املسافات البيضاء (‪ )white spaces‬الواقعة بين‬
‫األسطر كما في املثال التالي‪:‬‬
‫)'‪fhand = open('mbox-short.txt‬‬
‫‪for line in fhand:‬‬
‫)(‪line = line.rstrip‬‬
‫‪if line.startswith('From: '):‬‬
‫)‪print(line‬‬
‫‪# Code: http://www.py4e.com/code3/search2.py‬‬
‫َ‬
‫البرنامج‪ ،‬نحصل على املخرجات التالية‪:‬‬
‫وعند تنفيذ هذا‬
‫‪From: stephen.marquard@uct.ac.za‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪109‬‬
‫‪From: louis@media.berkeley.edu‬‬
‫‪From: zqian@umich.edu‬‬
‫‪From: rjlowe@iupui.edu‬‬
‫‪From: zqian@umich.edu‬‬
‫‪From: rjlowe@iupui.edu‬‬
‫‪From: cwen@iupui.edu‬‬
‫…‬
‫ً‬
‫ً‬
‫تعقيدا‪ ،‬فقد ترغب في تنظيم حلقات البحث‬
‫نظرا إلى أن برامج معالجة ملفاتك‪ ،‬تصبح أكثر‬
‫باستخدام التعليمة ‪ .continue‬الفكرة األساسية لحلقة البحث هي أنك تبحث عن األسطر “املهمة"‬
‫مثيرا لالهتمام؛ نفعل ً‬
‫سطرا ً‬
‫ً‬
‫شيئا ما به‪ .‬يمكننا هيكلة‬
‫وتتخطى األسطر "غير املهمة"‪ .‬ثم عندما نجد‬
‫الحلقة لتتبع َنمط تخطي السطور غير املهمة على النحو التالي‪:‬‬
‫)'‪fhand = open('mbox-short.txt‬‬
‫‪for line in fhand:‬‬
‫)(‪line = line.rstrip‬‬
‫'‪# Skip 'uninteresting lines‬‬
‫‪if not line.startswith('From:'):‬‬
‫‪continue‬‬
‫‪# Process our 'interesting' line‬‬
‫)‪print(line‬‬
‫‪# Code: http://www.py4e.com/code3/search3.py‬‬
‫َ‬
‫البرنامج؛ ستحصل على نفس املخرجات السابقة‪ .‬بمعنى آخر‪ ،‬األسطر ُ‬
‫غير املهمة هي‬
‫عند تنفيذ هذا‬
‫تلك األسطر التي ال تبدأ بـ ‪ ، :From‬وهي التي نتخطاها باستخدام التعليمة ‪ . continue‬فيما يعالج‬
‫ُ‬
‫السطور "املهمة" (أي تلك التي تبدأ بـ ‪ .):From‬يمكننا استخدام التابع ‪ find‬ملحاكاة أداة البحث في‬
‫محرر نصوص التي تعثر على السطور حيث تكون سلسلة البحث في أي جزأ من السطر‪ً .‬‬
‫نظرا إلى أن‬
‫تعليمة ‪ find‬تبحث عن تواجد سلسلة داخل سلسلة أخرى وتقوم َّإما بإرجاع موضع السلسلة َّ‬
‫وإما‬
‫ُ‬
‫طباعة ‪ .1-‬إذا لم تعثر على السلسلة‪ ،‬فيمكننا كتابة الحلقة التالية إلظهار األسطر التي تحتوي على‬
‫السلسلة "‪( "@uct.ac.za‬أي أنهم ينتمون إلى جامعة كيب تاون في جنوب إفريقيا) كما في املثال التالي‪:‬‬
‫)'‪fhand = open('mbox-short.txt‬‬
‫‪for line in fhand:‬‬
‫)(‪line = line.rstrip‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪110‬‬
‫‪if line.find ('@uct.ac.za') == -1: continue‬‬
‫)‪print(line‬‬
‫‪# Code: http://www.py4e.com/code3/search4.py‬‬
‫ُ‬
‫َ‬
‫البرنامج‪ ،‬نحصل على املخرجات التالية وهي عناوين البريد اإللكتروني ملنتمين إلى‬
‫عند تنفيذ هذا‬
‫جامعة كيب تاون في جنوب أفريقيا‪:‬‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫‪X-Authentication-Warning: set sender to stephen.marquard@uct.ac.za using -f‬‬
‫‪From: stephen.marquard@uct.ac.za‬‬
‫‪Author: stephen.marquard@uct.ac.za‬‬
‫‪From david.horwitz@uct.ac.za Fri Jan 4 07:02:32 2008‬‬
‫‪X-Authentication-Warning: set sender to david.horwitz@uct.ac.za using -f‬‬
‫‪From: david.horwitz@uct.ac.za‬‬
‫‪Author: david.horwitz@uct.ac.za‬‬
‫…‬
‫نستخدم هنا ً‬
‫َ‬
‫الشكل املختصر لجملة ‪ if‬الشرطية‪ ،‬إذ نضع تعليمة ‪ continue‬على نفس السطر‬
‫أيضا‬
‫ُّبرفقة تعليمة ‪ if‬الشرطية‪ .‬يعمل هذا الشكل من جملة ‪ if‬الشرطية كما لو كانت تعليمة ‪continue‬‬
‫في السطر التالي ومسبوقة بمسافة بادئة‪.‬‬
‫‪ 6.7‬السماح للمستخدم باختيارا ِّمللف‬
‫ال نريد ً‬
‫أبدا أن ُن َّ‬
‫ضطر إلى تعديل شيفرة لغة بايثون في كل مرة نريد فيها معالجة ملف مختلف‪ .‬سيكون‬
‫َ‬
‫َ‬
‫البرنامج حتى يتمكن‬
‫إدخال اسم امللف في كل مرة يتم فيها تشغيل‬
‫من األفضل أن تطلب من املستخدم‬
‫من استخدام َ‬
‫برنامجنا على ملفات مختلفة دون تغيير الشيفرة‪ .‬يمكن تنفيذ هذا األمر بسهولة من‬
‫خالل قراءة اسم امللف من املستخدم باستخدام التابع ‪ input‬على النحو التالي‪:‬‬
‫)' ‪fname = input('Enter the file name:‬‬
‫)‪fhand = open(fname‬‬
‫‪count = 0‬‬
‫‪for line in fhand:‬‬
‫‪if line.startswith('Subject:'):‬‬
‫‪count = count + 1‬‬
‫)‪print('There were', count, 'subject lines in', fname‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪111‬‬
‫‪# Code: http://www.py4e.com/code3/search6.py‬‬
‫ُ‬
‫َ‬
‫البرنامج األعلى أن اسم امللف يدخله املستخدم‪ .‬ونضعه في متغير ُيسمى ‪ fname‬ونفتح هذا‬
‫نلحظ من‬
‫ً‬
‫َ‬
‫ً‬
‫متكررا على ملفات مختلفة كما هو موضح أدناه‪:‬‬
‫البرنامج تشغيال‬
‫امللف‪ .‬اآلن يمكننا تشغيل‬
‫‪python search6.py‬‬
‫‪Enter the file name: mbox.txt‬‬
‫‪There were 1797 subject lines in mbox.txt‬‬
‫‪python search6.py‬‬
‫‪Enter the file name: mbox-short.txt‬‬
‫‪There were 27 subject lines in mbox-short.txt‬‬
‫َ‬
‫البرنامج األعلى واسأل نفسك‪«،‬ما الخطأ‬
‫قبل إلقاء نظرة خاطفة إلى القسم التالي‪ ،‬ألق نظرة إلى‬
‫املحتمل هنا؟» أو «ما الذي يمكن أن يفعله مستخدمنا الودود ليجعل َ‬
‫ُ‬
‫برنامجنا الصغير اللطيف ال‬
‫ً‬
‫ُينفذ بل تظهر رسالة خطأ بدال من ذلك‪ ،‬مما يجعلنا نبدو مبرمجين غير محترفين في أعين‬
‫مستخدمينا؟»‪.‬‬
‫‪ 7.7‬استخدام ‪ try‬و‪ except‬و‪open‬‬
‫أخبرتك للتو بأال تختلس النظر إلى هذا القسم قبل اإلجابة على االسئلة السابقة‪ ،‬هذه هي فرصتك‬
‫األخيرة‪.‬‬
‫ماذا لو كتب مستخدمنا ً‬
‫شيئا ما غير اسم امللف؟ تمعن في حاالت التنفيذ التالية‪ ،‬ما الذي تلحظه؟‬
‫‪python search6.py‬‬
‫‪Enter the file name: missing.txt‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "search6.py", line 2, in <module‬‬
‫)‪fhand = open(fname‬‬
‫'‪FileNotFoundError: [Errno 2] No such file or directory: 'missing.txt‬‬
‫‪python search6.py‬‬
‫‪Enter the file name: na na boo boo‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪112‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "search6.py", line 2, in <module‬‬
‫)‪fhand = open(fname‬‬
‫'‪FileNotFoundError: [Errno 2] No such file or directory: 'na na boo boo‬‬
‫ً‬
‫حسنا‪ ،‬ال تضحك‪ .‬سيفعل املستخدمون في النهاية كل ما يمكنهم فعله لتفشيل َ‬
‫برنامجك‪َّ ،‬إما عن‬
‫شخصا أو ً‬
‫وإما بنية سيئة‪ .‬في واقع األمر‪َّ ،‬‬
‫ً‬
‫قصد َّ‬
‫فريقا‬
‫إن أي فريق تطوير برمجيات يجب أن يتضمن‬
‫ً‬
‫مسؤوال عما ُيسمى بضمان الجودة‪ ،‬وتتمثل مهمة هذا الفريق في القيام بأكثر األشياء ً‬
‫جنونا في محاولة‬
‫ً‬
‫ُ‬
‫َ‬
‫البرنامج الذي أنشأه املبرمج أو فريق البرمجة‪ .‬يعتبر فريق ضمان الجودة مسؤوال عن اكتشاف‬
‫لكسر‬
‫ُّ‬
‫َ‬
‫َ‬
‫البرنامج أو يدفعون رواتب‬
‫البرنامج للمستخدمين الذين قد يشترون‬
‫العيوب في البرامج قبل تسلم‬
‫ُ‬
‫أفضل صديق للمبرمج‪.‬‬
‫املبرمجين‪ .‬لذا‪ ،‬فريق ضمان الجودة هو‬
‫َ‬
‫البرنامج‪ ،‬يمكننا إصالحه بأناقة باستخدام بنية ‪ .try / except‬نحتاج إلى‬
‫واآلن بعد أن رأينا الخلل في‬
‫ُ‬
‫افتراض أن عملية استدعاء التابع ‪ open‬قد تخفق‪ ،‬لذا سنقوم بإضافة شيفرة استعادة ‪(recovery‬‬
‫)‪code‬عند فشل عملية استدعاء التابع ‪ open‬على النحو التالي‪:‬‬
‫)' ‪fname = input('Enter the file name:‬‬
‫‪try:‬‬
‫)‪fhand = open(fname‬‬
‫‪except:‬‬
‫)‪print('File cannot be opened:', fname‬‬
‫)(‪exit‬‬
‫‪count = 0‬‬
‫‪for line in fhand:‬‬
‫‪if line.startswith('Subject:'):‬‬
‫‪count = count + 1‬‬
‫)‪print('There were', count, 'subject lines in', fname‬‬
‫‪# Code: http://www.py4e.com/code3/search7.py‬‬
‫َ‬
‫َ‬
‫التابع وال يعود بأي قيمة‪ .‬اآلن عندما يكتب‬
‫البرنامج؛ إذ نستدعي هذا‬
‫يعمل التابع ‪ exit‬على إنهاء‬
‫الفصل السابع‪ :‬امللفات‬
‫‪113‬‬
‫املستخدم (أو فريق ضمان الجودة) أسماء للملفات غير أسمائها الحقيقية‪ ،‬فإننا "نستدرك الوضع"‬
‫بأمان كما هو موضح أدناه‪:‬‬
‫‪python search7.py‬‬
‫‪Enter the file name: mbox.txt‬‬
‫‪There were 1797 subject lines in mbox.txt‬‬
‫‪python search7.py‬‬
‫‪Enter the file name: na na boo boo‬‬
‫‪File cannot be opened: na na boo boo‬‬
‫ً‬
‫تعد حماية استدعاء التابع ‪ open‬مثاال جي ًدا على االستخدام الصحيح لبنية ‪ try‬و ‪ except‬في البرامج‬
‫املكتوبة بلغة بايثون‪ .‬نستخدم مصطلح "بايثوني" "‪ "Pythonic‬عندما نفعل ً‬
‫شيئا بأسلوب محترف في‬
‫لغة بايثون‪ .‬يمكننا القول‪ :‬إن املثال السابق هو "طريقة بايثونية" لفتح ملف‪.‬‬
‫بمجرد أن تصبح أكثر مهار ًة في لغة بايثون‪ ،‬يمكنك املشاركة في اقتراح حل بديل مع مبرمجي بايثون‬
‫اآلخرين لتحديد أي من الحلين املتكافئين ملشكلة ما هو "أكثر بايثونية"‪ .‬الهدف من أن تكون "أكثر‬
‫جزء من الهندسة وجزء من الفن‪ .‬لسنا مهتمين ً‬
‫بايثونية" يجسد فكرة أن البرمجة ٌ‬
‫دائما فقط بإنجاح‬
‫أيضا أن يكون حلنا ً‬
‫ش يء ما‪ ،‬بل نريد ً‬
‫أنيقا وأن يحظى بتقدير الجميع‪.‬‬
‫‪ 8.7‬كتابة ا ِّمللفات‬
‫ثان للتابع ‪ open‬كما في املثال التالي‪:‬‬
‫لكتابة ملف‪ ،‬عليك فتحه باستخدام الوضع "‪ "w‬كمعامل ٍ‬
‫)'‪>>> fout = open ('output.txt', 'w‬‬
‫)‪>>> print(fout‬‬
‫>'‪<_io.TextIOWrapper name='output.txt' mode='w' encoding='cp1252‬‬
‫ً‬
‫موجودا بالفعل‪ ،‬فإن فتحه في وضع الكتابة يؤدي إلى مسح البيانات القديمة ويبدأ من‬
‫إذا كان امللف‬
‫ُ َ‬
‫ٌ‬
‫جديد‪ ،‬لذا كن ً‬
‫فسينشأ ملف جديد‪.‬‬
‫حذرا! أما إذا كان امللف غير موجود‪،‬‬
‫يعمل تابع الكتابة ‪ write‬الخاص بكائن معرف امللف على وضع البيانات في امللف وإرجاع عدد األحرف‬
‫ُ‬
‫ُ‬
‫القيمة ‪ 24‬التي تمثل َ‬
‫عدد الحروف املوجودة في‬
‫املكتوبة كما نلحظ في املثال األدنى؛ إذ أرجعت‬
‫السلسلة النصية املجودة بين عالمتي التنصيص " "‪ .‬إن الوضع االفتراض ي هو ملف نص ي في حالتي‬
‫الفصل السابع‪ :‬امللفات‬
‫‪114‬‬
‫كتابة السالسل النصية وقراءتها‪.‬‬
‫"‪>>> line1 = "This here's the wattle,\n‬‬
‫)‪>>> fout.write(line1‬‬
‫‪24‬‬
‫مرة أخرى‪ ،‬يحفظ كائن امللف مكانه‪ ،‬لذلك إذا استدعيت تابع الكتابة ‪ write‬مرة أخرى‪ ،‬فإن البيانات‬
‫الجديدة ُ‬
‫ستضاف إلى النهاية‪.‬‬
‫يجب أن نتأكد من إدارة نهايات األسطر في أثناء الكتابة على امللف عن طريق إدراج حرف إنشاء‬
‫ُ‬
‫ً‬
‫السطر الجديد ‪ \n‬إدر ً‬
‫صريحا عندما نريد إنهاء السطر‪ .‬من هنا ينبغي أن نعرف أن تعليمة ‪print‬‬
‫اجا‬
‫ُ‬
‫ً‬
‫ًّ‬
‫ًّ‬
‫تلقائيا ً‬
‫تلقائيا‪.‬‬
‫جديدا‪ ،‬لكن استعمال التابع ‪ write‬ال يضيف السطر الجديد‬
‫سطرا‬
‫تضيف‬
‫'‪>>> line2 = 'the emblem of our land.\n‬‬
‫)‪>>> fout.write(line2‬‬
‫‪24‬‬
‫عند االنتهاء من عملية الكتابة‪ ،‬يجب عليك إغالق امللف كما في الشيفرة أدناه للتأكد من كتابة آخر‬
‫جزء من البيانات ً‬
‫فعليا على القرص حتى ال يضيع هذا الجزء إذا انقطع التيار الكهربائي‪.‬‬
‫)(‪>>> fout.close‬‬
‫يمكننا إغالق امللفات التي نفتحها للقراءة ً‬
‫أيضا‪ ،‬ولكن يمكن أن نكون مهملين بعض الش يء إذا كنا‬
‫َ‬
‫البرنامج‪ .‬أما‬
‫نفتح بعض امللفات فقط ألن ُمفسر بايثون يغلق جميع امللفات املفتوحة عند انتهاء‬
‫ً‬
‫ً‬
‫ً‬
‫تفاديا من أي ش يء قد‬
‫قاطعا وذلك‬
‫عندما نكتب على امللفات‪ ،‬فيجب علينا إغالق امللفات إغالقا‬
‫يحدث‪.‬‬
‫‪ 9.7‬التنقيح‬
‫عند قراءة امللفات أو الكتابة عليها‪ ،‬قد تواجه مشكالت في الفراغات أو ما يسمى املسافات البيضاء‪.‬‬
‫قد يكون من الصعب تصحيح هذه األخطاء ألن املسافات واإلزاحات واألسطر الجديدة عادة ما تكون‬
‫َ‬
‫غير مرئية كما في املثال التالي‪:‬‬
‫'‪>>> s = '1 2\t 3\n 4‬‬
‫)‪>>> print(s‬‬
‫‪3‬‬
‫‪12‬‬
‫‪4‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪115‬‬
‫يمكن أن يساعد التابع الجاهز ‪ repr‬في حل هذه املشكالت؛ إذ يأخذ أي كائن كوسيط ويعيد سلسلة‬
‫نصية تمثل الكائن‪ .‬فيما يخص السالسل النصية‪ ،‬إن ذلك التابع ُيمثل رموز املسافات البيضاء‬
‫بسلسلة من الشرطات العكسية‪:‬‬
‫))‪>>> print(repr(s‬‬
‫'‪'1 2\t 3\n 4‬‬
‫ً‬
‫مفيدا‪ ،‬ولكن ثمة مشكلة أخرى قد تواجهها‪ ،‬وهي أن األنظمة املختلفة‬
‫يمكن أن يكون التنقيح‬
‫ً‬
‫تستخدم محارفا مختلفة لإلشارة إلى نهاية السطر؛ إذ تستخدم بعض األنظمة الرمز ‪ \n‬إلنشاء سطر‬
‫جديد‪ ،‬في حين تستخدم أنظمة أخرى الرمز ‪ ،\r‬وتستخدم بعض األنظمة كال الرمزين‪ .‬عند نقل‬
‫امللفات بين أنظمة مختلفة‪ ،‬فقد تتسبب هذه التناقضات في حدوث مشكالت‪.‬‬
‫ُّ‬
‫يخص معظم األنظمة‪ ،‬ثمة تطبيقات للتحويل من تنسيق إلى آخر‪ .‬يمكنك العثور عليها (وقراءة‬
‫فيما‬
‫املزيد عن هذه املشكلة) على الرابط‪https://www.wikipedia.org/wiki/Newline. :‬‬
‫أو‪ ،‬بالطبع‪ ،‬يمكنك إنشاء تطبيق بنفسك‪.‬‬
‫‪ 10.7‬فهرس املصطلحات‬
‫ُ‬
‫َ‬
‫البرنامج باستخدام‬
‫• التقاط االستثناء (‪ :)catch‬طريقة تستخدم ملنع استثناء من إنهاء‬
‫عبارات ‪ try‬و‪.except‬‬
‫ُ‬
‫محرف إنشاء السطر الجديد (‪ :)newline‬محرف َم ٌّ‬
‫عني يستخدم في امللفات والسالسل‬
‫•‬
‫النصية لإلشارة إلى نهاية السطر‪.‬‬
‫• البايثونية (‪ :)Pythonic‬هي إسلوب برمجي خاص بلغة بايثون‪ ،‬على سبيل املثال "استخدام‬
‫‪ try‬و‪ except‬هي طريقة بايثونية في حالة كانت امللفات التي ُ‬
‫َ‬
‫البرنامج مفقودة"‪.‬‬
‫استدعيت في‬
‫ٌ‬
‫شخص أو فريق يتركز عمله على ضمان الجودة‬
‫• ضمان الجودة (‪ :)Quality Assurance‬هو‬
‫َ‬
‫ً‬
‫وغالبا ما يشارك فريق ضمان الجودة في اختبار املنتج وتحديد‬
‫البرنامج‬
‫الشاملة ملنتج‬
‫َ‬
‫البرنامج قبل طرحه للبيع‪.‬‬
‫املشكالت في‬
‫• ملف نص ي (‪ :)Text File‬عبارة عن سلسلة من األحرف املخزنة بوحدة تخزين دائم َ‬
‫مثل‬
‫ِّ‬
‫القرص الصلب‪.‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪116‬‬
‫‪ 11.7‬تمارين‬
‫• التمرين األول‪ :‬اكتب َ‬
‫ً‬
‫(سطرا بسطر) كلها بأحرف‬
‫برنام ًجا لقراءة ملف وطباعة محتوياته‬
‫َ‬
‫البرنامج على النحو التالي‪:‬‬
‫كبيرة بحيث يبدو تنفيذ‬
‫‪python shout.py‬‬
‫‪Enter a file name: mbox-short.txt‬‬
‫‪FROM STEPHEN.MARQUARD@UCT.AC.ZA SAT JAN 5 09:14:16 2008‬‬
‫>‪RETURN-PATH: <POSTMASTER@COLLAB.SAKAIPROJECT.ORG‬‬
‫)]‪RECEIVED: FROM MURDER (MAIL.UMICH.EDU [141.211.14.90‬‬
‫;‪BY FRANKENSTEIN.MAIL.UMICH.EDU (CYRUS V2.3.8) WITH LMTPA‬‬
‫‪SAT, 05 JAN 2008 09:14:16 -0500‬‬
‫بإمكانك تنزيل امللف من خالل الرابط التالي‪:‬‬
‫‪www.py4e.com/code3/mbox-short.txt‬‬
‫• التمرين الثاني‪ :‬اكتب َ‬
‫برنام ًجا ملطالبة املستخدم باسم امللف‪ ،‬ثم اقرأ محتويات امللف‬
‫وابحث عن السطور التي تحتوي على الصيغة التالية‪X-DSPAM-Confidence: 0.8475 :‬‬
‫ً‬
‫سطرا يبدأ بـ "‪ ،":X-DSPAM-Confidence‬افصل السطر الستخراج الرقم‬
‫وحينما تصادف‬
‫ذي الفاصلة العشرية من السطر‪.‬‬
‫واحسب عدد هذه السطور ثم احسب إجمالي القيم ذات الفواصل العشرية في هذه السطور‬
‫َ‬
‫(‪ )Average spam confidence‬وعندما تصل إلى نهاية امللف‪ ،‬اطبع متوسطهم ‪.‬‬
‫َ‬
‫البرنامج سيبدو على الشكل التالي‪:‬‬
‫الحظ أن تنفيذ‬
‫‪Enter the file name: mbox.txt‬‬
‫‪Average spam confidence: 0.894128046745‬‬
‫‪Enter the file name: mbox-short.txt‬‬
‫‪Average spam confidence: 0.750718518519‬‬
‫اختبر َ‬
‫برنامجك على ملف ‪ mbox.txt‬وملف ‪.mbox-short.txt‬‬
‫الفصل السابع‪ :‬امللفات‬
‫‪117‬‬
‫• التمرين الثالث‪ :‬عندما يشعر املبرمجون ً‬
‫أحيانا بامللل أو يرغبون في الحصول على القليل من‬
‫َ‬
‫املرح‪ ،‬فإنهم يضيفون بعض املفاجئات إلى َ‬
‫البرنامج الذي يطالب‬
‫برنامجهم‪ .‬قم بتعديل‬
‫املستخدم باسم امللف بحيث يطبع رسالة مضحكة عندما يكتب املستخدم اسم امللف‬
‫ً‬
‫َ‬
‫ًّ‬
‫طبيعيا مع جميع امللفات‬
‫البرنامج عمال‬
‫بالشكل التالي"‪ ."na na boo boo‬يجب أن يعمل‬
‫َ‬
‫البرنامج‪:‬‬
‫األخرى املوجودة وغير املوجودة‪ .‬فيما يلي نموذج لتنفيذ‬
‫‪python egg.py‬‬
‫‪Enter the file name: mbox.txt‬‬
‫‪There were 1797 subject lines in mbox.txt‬‬
‫‪python egg.py‬‬
‫‪Enter the file name: missing.tyxt‬‬
‫‪File cannot be opened: missing.tyxt‬‬
‫‪python egg.py‬‬
‫‪Enter the file name: na na boo boo‬‬
‫!‪NA NA BOO BOO TO YOU - You have been punk'd‬‬
‫ُ‬
‫مجرد تمرين‪ ،‬فنحن ال نشجعك على ترك مفاجآت في برامجك!‬
‫تذكر بأن هذا‬
‫الفصل الثامن‬
‫القوائم‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪119‬‬
‫‪ 8‬القوائم‬
‫‪ 1.8‬القائمة هي سلسلة‬
‫إن القائمة )‪ (List‬هي سلسلة من القيم‪ ،‬كما هي السالسل النصية )‪ ،(string‬حيث تكون القيم في‬
‫السلسلة النصية عبارة عن محارف‪ ،‬بينما يمكن أن تكون القيم في القائمة أي نوع بيانات‪.‬‬
‫ُ‬
‫تسمى القيم في القائمة بـالعناصر (‪ elements‬أو ‪.)items‬‬
‫يوجد العديد من الطرق إلنشاء قائمة جديدة‪ .‬الطريقة األسهل هي حصر العناصر ضمن قوسين‬
‫ُمربعين ("]" و"[")‪:‬‬
‫]‪[10, 20, 30, 40‬‬
‫]'‪['crunchy frog', 'ram bladder', 'lark vomit‬‬
‫يبين املثال األول قائمة مؤلفة من ‪ 4‬أعداد صحيحة‪ .‬بينما الثاني عبارة عن قائمة مؤلفة من ثالث‬
‫سالسل نصية‪.‬‬
‫ليس بالضرورة أن تكون عناصر القائمة من النوع ذاته‪ ،‬حيث تحتوي القائمة التالية على سلسلة‬
‫نصية وعدد ذي فاصلة عشرية وعدد صحيح‪ .‬كما أن بإمكانها احتواء قائمة أخرى‪.‬‬
‫]]‪['spam', 2.0, 5, [10, 20‬‬
‫إن وجود قائمة ضمن قائمة أخرى يعني أنها ُمتداخلة (‪ (nested‬أما القائمة التي ال تحتوي عناصر‬
‫فتسمى بالقائمة الفارغة )‪.(empty list‬‬
‫بإمكانك إسناد قيم القائمة إلى ُمتغيرات‪:‬‬
‫]'‪>>> cheeses = ['Cheddar', 'Edam', 'Gouda‬‬
‫]‪>>> numbers = [17, 123‬‬
‫][ = ‪>>> empty‬‬
‫)‪>>> print(cheeses, numbers, empty‬‬
‫][ ]‪['Cheddar', 'Edam', 'Gouda'] [17, 123‬‬
‫‪ 2.8‬القوائم قابلة للتعديل‬
‫ُ‬
‫إن القاعدة أو الطريقة املتبعة في الوصول إلى عناصر قائمة هي ذاتها املستخدمة في الوصول إلى‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪120‬‬
‫املحارف في السلسلة النصية‪ ،‬أي عامل القوس (‪ .(bracket operator‬حيث يحدد التعبير داخل‬
‫األقواس الفهرس املطلوب‪ .‬تذكر أن الفهارس تبدأ من الـصفر‪.‬‬
‫)]‪>>> print(cheese[0‬‬
‫‪cheddar‬‬
‫ً‬
‫خالفا للسالسل النصية‪ ،‬فإن القوائم قابلة للتعديل‪ ،‬حيث بإمكانك تغيير ترتيب عناصر قائمة ما‪،‬‬
‫أو إعادة تعيين عنصر فيها‪.‬‬
‫عندما يظهر عامل القوس في الجانب األيسر من عملية اإلسناد‪ ،‬فهو يحدد ُع ً‬
‫نصرا في القائمة‬
‫ُ‬
‫ست َ‬
‫سند قيمة إليه‪.‬‬
‫]‪>>> numbers = [17, 123‬‬
‫‪>>> numbers[1] = 5‬‬
‫)‪>>> print(numbers‬‬
‫]‪[17, 5‬‬
‫في املثال السابق‪ُ ،‬‬
‫العنصر األول من القائمة املتضمنة األعداد‪ ،‬والذي كان ذا قيمة ‪ ،123‬أصبح اآلن‬
‫‪.5‬‬
‫َ‬
‫بإمكانك أن تعد القائمة عبارة عن عالقة بين الفهارس والعناصر‪ ،‬وتسمى هذه العالقة بالربط‬
‫(‪ ،)mapping‬حيث إن كل فهرس ُمرتبط بأحد العناصر‪.‬‬
‫تعمل فهارس القوائم بنفس طريقة عمل فهارس السالسل النصية‪:‬‬
‫• أي تعبير يمثل عدد صحيح ُيمكن أن ُيستخدم كفهرس‪.‬‬
‫• إذا حاولت أن تقرأ أو تكتب ُع ً‬
‫نصرا غير موجود‪ ،‬ستحصل على خطأ فهرسة (‪.(IndexError‬‬
‫ً‬
‫ابتداء من نهاية القائمة‪.‬‬
‫• إذا كان لفهرس ما قيمة سالبة‪ ،‬فإنه يبدأ العد بشكل عكس ي‬
‫ُيمكن للعامل ‪ in‬التعامل مع القوائم ً‬
‫أيضا‪.‬‬
‫]'‪>>> cheeses = ['Cheddar', 'Edam', 'Gouda‬‬
‫‪>>> 'Edam' in cheeses‬‬
‫‪True‬‬
‫‪>>> 'Brie' in cheeses‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪121‬‬
‫‪False‬‬
‫‪ 3.8‬املرورعلى عناصرقائمة‬
‫ُيعد استخدام حلقة ‪ for‬الطريقة األكثر ُش ً‬
‫يوعا للمرور على عناصر قائمة‪ ،‬وبشكل مماثل للتعامل‬
‫مع السالسل النصية‪:‬‬
‫‪for cheese in cheeses:‬‬
‫)‪print(cheese‬‬
‫هذا ُمفيد إذا َ‬
‫أردت فقط قراءة عناصر من القائمة‪ ،‬لكن إن أردت كتابة أو تحديث العناصر‪ ،‬فإن َك‬
‫بحاجة إلى الفهارس‪ .‬من الشائع استخدام كال التابعين ‪َ range‬و‪ len‬لهذا الغرض‪:‬‬
‫‪for i in range(len(numbers)):‬‬
‫‪numbers[i] = numbers[i] * 2‬‬
‫ُتحدث هذه الحلقة قيمة كل عنصر في القائمة لدى ُمرورها على العناصر ً‬
‫تباعا‪.‬‬
‫ُيعيد التابع ‪ len‬عدد العناصر في القائمة‪ .‬بينما ُيعيد التابع ‪ range‬قائمة من الفهارس من ‪ 0‬حتى‬
‫‪ ،n-1‬حيث ‪ n‬هي عدد العناصر في القائمة‪.‬‬
‫ُ‬
‫ُ‬
‫َ‬
‫ستخدم قيمة ‪ i‬من قبل تعليمة اإلسناد في جسم الحلقة‪ ،‬حيث‬
‫في كل مرة ندخل في الحلقة‪ ،‬ت‬
‫تستخد َم ُه لقراءة القيمة القديمة للعنصر‪ ،‬وإسناد القيمة الجديدة إليه‪ ،‬ويأخذ ‪ i‬قيمة فهرس‬
‫العنصر التالي‪.‬‬
‫ُ‬
‫ال تنفذ حلقة ‪ for‬التعليمات في جسم الحلقة في حالة القائمة الفارغة‪:‬‬
‫‪for x in empty:‬‬
‫)'‪print ('This never happens.‬‬
‫أن تلك القائمة تعد كعنصر ُمنفرد‪ .‬لذا‪َّ ،‬‬
‫بالرغم من أن بإمكان القائمة احتواء قائمة أخرى‪ ،‬إال َّ‬
‫فإن‬
‫طول القائمة التالية هو ‪.4‬‬
‫]]‪['spam', 1, ['Brie', 'Roquefort', 'Pol le Veq'], [1, 2, 3‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪122‬‬
‫ّ‬
‫العمليات على القوائم‬
‫‪4.8‬‬
‫َ‬
‫يجمع عامل الجمع ‪ +‬القوائم (يضعها جنبا إلى جنب بشكل متسلسل)‪.‬‬
‫]‪>>> a = [1, 2, 3‬‬
‫]‪>>> b = [4, 5, 6‬‬
‫‪>>> c = a + b‬‬
‫)‪>>> print(c‬‬
‫]‪[1, 2, 3, 4, 5, 6‬‬
‫بشكل ُمشابه‪ُ ،‬يكرر عامل النجمة ‪-‬الضرب‪ * -‬القائمة بمقدار عدد معلوم من املرات‪.‬‬
‫‪>>> [0] * 4‬‬
‫]‪[0, 0, 0, 0‬‬
‫‪>>> [1, 2, 3] * 3‬‬
‫]‪[1, 2, 3, 1, 2, 3, 1, 2, 3‬‬
‫ُيكرر املثال األول السلسلة ‪ 4‬مرات‪ .‬بينما في املثال الثاني‪ ،‬تتكرر السلسلة ‪ 3‬مرات‪.‬‬
‫‪ 5.8‬تجزئة القوائم‬
‫يعمل عامل التجزئة ً‬
‫أيضا مع القوائم‪:‬‬
‫]'‪>>> t = ['a', 'b', 'c', 'd', 'e', 'f‬‬
‫]‪>>> t[1:3‬‬
‫]'‪['b', 'c‬‬
‫]‪>>> t[:4‬‬
‫]'‪['a', 'b', 'c', 'd‬‬
‫]‪>>> t[3:‬‬
‫]'‪['d', 'e', 'f‬‬
‫إذا تجاهلت الفهرس األول‪ ،‬فإن التجزئة تبدأ من بداية القائمة‪ .‬أما إذا تجاهلت الفهرس الثاني‪،‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪123‬‬
‫تستمر التجزئة حتى النهاية‪ .‬بينما إذا تجاهلت االثنين ً‬
‫معا ] ‪ ،[ :‬فإن التجزئة هي عبارة عن نسخة‬
‫ُمطابقة للقائمة بأكملها‪.‬‬
‫]‪>>> t[:‬‬
‫]'‪['a', 'b', 'c', 'd', 'e', 'f‬‬
‫نظرا إلى أن القوائم قابلة للتعديل‪ ،‬فمن املفيد ً‬
‫ً‬
‫غالبا نسخ القائمة قبل إجراء عمليات عليها‪.‬‬
‫ُيمكن لعامل التجزئة على يسار عملية اإلسناد أن ُيحدث قيم عدة عناصر في نفس الوقت‪:‬‬
‫]'‪>>> t = ['a', 'b', 'c', 'd', 'e', 'f‬‬
‫]'‪>>> t[1:3] = ['x', 'y‬‬
‫)‪>>> print(t‬‬
‫]'‪['a', 'x', 'y', 'd', 'e', 'f‬‬
‫‪ 6.8‬توابع ّ‬
‫خاصة بالقوائم‬
‫ً‬
‫ً‬
‫مثال‪ ،‬يضيف التابع ‪ُ append‬ع ً‬
‫جديدا إلى‬
‫نصرا‬
‫تتضمن لغة بايثون عدة توابع للعمل على القوائم‪.‬‬
‫نهاية قائمة‪.‬‬
‫]'‪>>> t = ['a', 'b', 'c‬‬
‫)'‪>>> t.append('d‬‬
‫)‪>>> print(t‬‬
‫]'‪['a', 'b', 'c', 'd‬‬
‫في املثال التالي‪ ،‬يأخذ التابع ‪ extend‬قائمة كوسيط‪ ،‬ثم يضيف جميع عناصرها لقائمة أخرى دفعة‬
‫واحدة‪:‬‬
‫]'‪>>> t1 = ['a', 'b', 'c‬‬
‫]'‪>>> t2 = ['d', 'e‬‬
‫)‪>>> t1.extend(t2‬‬
‫)‪>>> print(t1‬‬
‫]'‪['a', 'b', 'c', 'd', 'e‬‬
‫لم يطرأ على ‪ t2‬في هذا املثال أي تعديل‪.‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪124‬‬
‫ًّ‬
‫تصاعديا‪:‬‬
‫يرتب التابع ‪ sort‬عناصر القائمة‬
‫]'‪>>> t = ['d', 'c', 'e', 'b', 'a‬‬
‫)(‪>>> t.sort‬‬
‫)‪>>> print(t‬‬
‫]'‪['a', 'b', 'c', 'd', 'e‬‬
‫َّ‬
‫إن ُمعظم توابع القوائم من النوع ‪ ،void‬حيث إنها تعدل على القائمة‪ ،‬وتعيد ‪ ،None‬لذا إذا حدث‬
‫َ‬
‫وكتبت )(‪ ،t = t.sort‬ستحصل على نتيجة مخيبة لآلمال‪.‬‬
‫‪ 7.8‬حذف العناصر‬
‫ُ‬
‫ُ‬
‫ُ‬
‫هناك عدة طرق لحذف العناصر من القائمة‪ .‬إذا كنت تعلم فهرس العنصر املراد حذفه‪ ،‬بإمكانك‬
‫عندئذ استعمال التابع ‪.pop‬‬
‫ٍ‬
‫]'‪>>> t = ['a', 'b', 'c‬‬
‫)‪>>> x = t.pop(1‬‬
‫)‪>>> print(t‬‬
‫]'‪['a', 'c‬‬
‫)‪>>> print(x‬‬
‫‪b‬‬
‫ُ‬
‫ً‬
‫ُ‬
‫ُ‬
‫تجري التعليمة ‪ pop‬تعديال على القائمة‪ ،‬وتعيد العنصر الذي أزيل‪.‬‬
‫في حال لم ُتحدد ً‬
‫فهرسا معي ًنا‪ ،‬عندها تحذف ‪ pop‬العنصر األخير في القائمة‪ ،‬وتخزنه كقيمة ُمرجعة‪.‬‬
‫بإمكانك استخدام العامل ‪ del‬إذا لم تكن بحاجة لالحتفاظ بالقيمة املحذوفة‪:‬‬
‫]'‪>>> t = ['a', 'b', 'c‬‬
‫]‪>>> del t[1‬‬
‫)‪>>> print(t‬‬
‫]'‪['a', 'c‬‬
‫إذا كنت على علم بالعنصر الذي ترغب بإزالته‪ ،‬لكنك ال تعلم الفهرس الخاص به‪ ،‬عندها بإمكانك‬
‫استعمال ‪.remove‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪125‬‬
‫]'‪>>> t = ['a', 'b', 'c‬‬
‫)'‪>>> t.remove('b‬‬
‫)‪>>> print(t‬‬
‫]'‪['a', 'c‬‬
‫القيمة التي تعيدها ‪ remove‬هي ‪.None‬‬
‫إلزالة أكثر من عنصر‪ ،‬بإمكانك استخدام ‪ del‬مع فهرس التجزئة‪:‬‬
‫]'‪>>> t = ['a', 'b', 'c', 'd', 'e', 'f‬‬
‫]‪>>> del t[1:5‬‬
‫)‪>>> print(t‬‬
‫]'‪['a', 'f‬‬
‫كالعادة‪ ،‬التجزئة تشمل كل العناصر املحددة من الفهرس األول حتى الفهرس الذي يسبق الفهرس‬
‫الثاني‪ ،‬أي ال تتضمن العنصر ذا الفهرس الثاني‪.‬‬
‫‪ 8.8‬القوائم والتوابع‬
‫يوجد عدد من التوابع الجاهزة التي باإلمكان استخدامها على القوائم‪ ،‬والتي تمنحك سالسة البحث‬
‫في القائمة دون الحاجة إلى استخدام الحلقات‪:‬‬
‫]‪>>> nums = [3, 41, 12, 9, 74, 15‬‬
‫))‪>>> print(len(nums‬‬
‫‪6‬‬
‫))‪>>> print(max(nums‬‬
‫‪74‬‬
‫))‪>>> print(min(nums‬‬
‫‪3‬‬
‫))‪>>> print(sum(nums‬‬
‫‪154‬‬
‫))‪>>> print(sum(nums)/len(nums‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪126‬‬
‫‪25‬‬
‫ً‬
‫أعدادا‪ .‬أما التوابع األخرى‪ ،‬مثل )(‪max‬‬
‫يعمل تابع الجمع )(‪ sum‬فقط عندما تكون عناصر القائمة‬
‫َو)(‪ len‬وغيرها‪ ،‬تعمل مع قوائم ذات عناصر من نوع سالسل نصية وأنواع البيانات األخرى القابلة‬
‫للمقارنة‪.‬‬
‫بإمكاننا إعادة كتابة البرنامج السابق الذي يـحسب املتوسط الحسابي لألعداد عبر استخدام القوائم‪.‬‬
‫في البداية‪ ،‬تمعن في البرنامج الذي يحسب املتوسط دون استخدام القوائم‪:‬‬
‫‪total = 0‬‬
‫‪count = 0‬‬
‫‪while (True):‬‬
‫)' ‪inp = input('Enter a number:‬‬
‫‪if inp == 'done': break‬‬
‫)‪value = float(inp‬‬
‫‪total = total + value‬‬
‫‪count = count + 1‬‬
‫‪average = total / count‬‬
‫)‪print('Average:', average‬‬
‫‪# Code: http://www.py4e.com/code3/avenum.py‬‬
‫في هذا البرنامج‪ ،‬لدينا ٌّ‬
‫كل من املتغيرين ‪َ count‬و‪ ،total‬حيث ُيخزن املتغير ‪ count‬تعداد األعداد‪ ،‬بينما‬
‫َ‬
‫يحفظ ‪ total‬القيمة التراكمية لألعداد التي يدخلها املستخدم‪.‬‬
‫بإمكاننا ببساطة تخزين كل عدد عند إدخاله من قبل املستخدم‪ ،‬واستخدام توابع جاهزة لحساب‬
‫تعداد األعداد واملجموع في النهاية‪.‬‬
‫)(‪numlist = list‬‬
‫‪while (True):‬‬
‫)' ‪inp = input('Enter a number:‬‬
‫‪if inp == 'done': break‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪127‬‬
‫)‪value = float(inp‬‬
‫)‪numlist.append(value‬‬
‫)‪average = sum(numlist) / len(numlist‬‬
‫)‪print('Average:', average‬‬
‫‪# Code: http://www.py4e.com/code3/avelist.py‬‬
‫أنشأنا قائمة فارغة قبل أن تبدأ الحلقة‪ ،‬وبعد ذلك في كل مرة يكون لدينا عدد جديد نضيفه إلى‬
‫القائمة‪ .‬في نهاية البرنامج‪ ،‬نحسب مجموع األعداد في القائمة ببساطة‪ ،‬ثم نقسمه على عدد األعداد‬
‫لنحصل على املتوسط الحسابي (املعدل)‪.‬‬
‫ّ‬
‫النص ّية‬
‫‪ 9.8‬القوائم والسالسل‬
‫إن السلسلة النصية هي سلسلة من املحارف‪ ،‬بينما القائمة هي سلسلة من القيم‪ ،‬ولكن القائمة‬
‫ُ‬
‫املؤلفة من مجموعة محارف ال تعتبر سلسلة نصية‪.‬‬
‫للتحويل من سلسلة نصية إلى قائمة من املحارف‪ ،‬بإمكانك استخدام التابع ‪:list‬‬
‫'‪>>> s = 'spam‬‬
‫)‪>>> t = list(s‬‬
‫)‪>>> print(t‬‬
‫]'‪['s', 'p', 'a', 'm‬‬
‫وألن ‪ list‬هو اسم لتابع جاهز‪ ،‬عليك ُّ‬
‫تجنب استخدامه كاسم ملُتغير‪ .‬وقد تجنبت ً‬
‫أيضا استخدام‬
‫الحرف ‪( I‬الحرف األول من كلمة ‪ )list‬وذلك لشبهه بالعدد ‪ ،1‬لذلك استخدمت الحرف ‪. t‬‬
‫يقسم التابع ‪ list‬السلسلة النصية إلى أحرف منفصلة‪ .‬أما إذا َ‬
‫أردت تقسيم السلسلة النصية إلى‬
‫كلمات‪ ،‬بإمكانك استخدام التابع ‪.split‬‬
‫'‪>>> s = 'pining for the fjords‬‬
‫)(‪>>> t = s.split‬‬
‫)‪>>> print(t‬‬
‫]'‪['pining', 'for', 'the', 'fjords‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪128‬‬
‫)]‪>>> print(t[2‬‬
‫‪the‬‬
‫بمجرد أن تستعمل ‪ split‬لتقسيم السلسلة النصية إلى كلمات‪ ،‬يكون بإمكانك استعمال عامل‬
‫الفهرس (القوس القائم الزاوية) الختيار كلمة محددة من القائمة‪.‬‬
‫يمكنك استدعاء ‪ split‬مع وسيط اختياري ُيسمى ُمحدد (‪ ،(delimiter‬والذي ُيحدد املحرف الذي‬
‫َ‬
‫ُ‬
‫ست َّ‬
‫الشرطة )‪ُ (hyphen‬‬
‫كمحدد‪:‬‬
‫قسم السلسلة وفقه‪ .‬املثال التالي يستخدم‬
‫'‪>>> s = 'spam-spam-spam‬‬
‫'‪>>> delimiter = '-‬‬
‫)‪>>> s.split(delimiter‬‬
‫]'‪['spam', 'spam', 'spam‬‬
‫يعمل ‪ join‬عكس عمل ‪ ،split‬فهو يأخذ قائمة من السالسل النصية‪ ،‬ويجمع العناصر‪.‬‬
‫إن ‪ join‬تابع خاص بالسلسلة النصية‪ .‬لذلك‪ ،‬الستخدامه‪ ،‬عليك استدعاءه باستخدام محدد‪،‬‬
‫ُ‬
‫وتمرر القائمة كمعامل‪.‬‬
‫]'‪>>> t = ['pining', 'for', 'the', 'fjords‬‬
‫' ' = ‪>>> delimiter‬‬
‫)‪>>> delimiter.join(t‬‬
‫'‪'pining for the fjords‬‬
‫ُ‬
‫ً‬
‫وفي هذه الحالة يكون املحدد هو محرف املسافة الفارغة ’ ‘‪ ،‬وبالتالي فإن تعليمة ‪ join‬تضع فراغا بين‬
‫الكلمات‪ .‬لكي ترتب السالسل النصية دون فراغات‪ ،‬يمكنك استخدام السلسلة الخالية "" ُ‬
‫كمحدد‪.‬‬
‫‪ 10.8‬التعامل مع األسطرفي امللفات‬
‫َ‬
‫عادة‪ ،‬عند قراءتنا مللف‪ ،‬فنحن نرغب بالتعديل على األسطر أكثر ما نرغب بمجرد عرض السطر‬
‫بأكمله‪.‬‬
‫في أكثر األحيان‪ ،‬نرغب بإيجاد "األسطر املهمة"‪ ،‬ومن َّ‬
‫ثم تحليل السطر نفسه إليجاد أجزاء مهمة منه‪.‬‬
‫على سبيل املثال‪ ،‬ماذا لو أردنا طباعة اختصار اسم يوم من أيام األسبوع الواردة في هذه األسطر التي‬
‫تبدأ بكلمة "‪"From‬؟‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪129‬‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫يعد تابع ‪ split‬فع ًاال ًّ‬
‫جدا عندما نواجه هذا النوع من املسائل‪.‬‬
‫بإمكاننا كتابة برنامج صغير يبحث عن األسطر التي تبدأ بـ ‪ ،From‬ويفصل هذه األسطر‪ ،‬ومن ثم‬
‫طباعة الكلمة الثالثة في السطر‪.‬‬
‫)'‪fhand = open('mbox-short.txt‬‬
‫‪for line in fhand:‬‬
‫)(‪line = line.rstrip‬‬
‫‪if not line.startswith('From '): continue‬‬
‫)(‪words = line.split‬‬
‫)]‪print(words[2‬‬
‫‪# Code: http://www.py4e.com/code3/search5.py‬‬
‫ُينتج البرنامج الخرج التالي‪:‬‬
‫‪Sat‬‬
‫‪Fri‬‬
‫‪Fri‬‬
‫‪Fri‬‬
‫‪...‬‬
‫ً‬
‫ات ُمتقدمة النتقاء األسطر التي ُنريد العمل عليها‪ ،‬وكيف نفرق‬
‫الحقا‪ ،‬سنتعلم بشكل مفصل تقني ٍ‬
‫هذه األسطر إليجاد املعلومة التي نبحث عنها بدقة‪.‬‬
‫َ‬
‫والقيم‬
‫‪ 11.8‬الكائنات‬
‫إذا َّنفذنا تعليمات اإلسناد التالية‪:‬‬
‫'‪a = 'banana‬‬
‫'‪b = 'banana‬‬
‫نعلم أن كل من ‪َ a‬و‪ُ b‬يشيران إلى سلسلة نصية‪ ،‬لكننا ال نعلم ما إذا كانا ُيشيران إلى نفس السلسة‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪130‬‬
‫النصية‪ .‬هناك حالتان ممكنتان‪:‬‬
‫الشكل ‪ :12‬القيم والكائنات‬
‫في الحالة األولى‪ a :‬و‪ُ b‬يشيران إلى كائنين ُمختلفين لهما نفس القيمة‪.‬‬
‫في الحالة الثانية‪ a :‬و‪ُ b‬يشيران إلى الكائن نفسه‪.‬‬
‫لنختبر ما إذا كان ُهناك ُمتغيران ُيشيران إلى نفس الكائن‪ .‬باإلمكان استخدام املعامل ‪.is‬‬
‫'‪>>> a = 'banana‬‬
‫'‪>>> b = 'banana‬‬
‫‪>>> a is b‬‬
‫‪True‬‬
‫ُ‬
‫في هذا املثال‪ ،‬تنش ئ بايثون كائن واحد لسلسلة نصية‪ ،‬حيث ُيشير إليه كل من ‪ a‬و ‪.b‬‬
‫ُ‬
‫لكن عندما تنش ئ قائمتين فإنك تحصل على كائنين‪.‬‬
‫]‪>>> a = [1, 2, 3‬‬
‫]‪>>> b = [1, 2, 3‬‬
‫‪>>> a is b‬‬
‫‪False‬‬
‫في هذه الحالة‪ ،‬نقول إن القائمتين متكافئتان )‪ ،(equivalent‬ألن لديهما نفس العناصر‪ ،‬لكنهما غير‬
‫متطابقتين )‪ ،(identical‬ألنهما ليسا الكائن ذاته‪.‬‬
‫إذا كان لدينا كائنان متطابقان‪ ،‬فهذا يعني أنهما متكافئان (متساويان)‪ ،‬ولكن كونهما متكافئين ال يعني‬
‫بالضرورة أنهما متطابقان‪.‬‬
‫إلى حد اآلن‪ ،‬نحن نستخدم "الكائن" (‪ )object‬و"القيمة" (‪ )value‬بالتبادل‪ ،‬ولكن لتوخي الدقة نقول‬
‫إن للكائن قيمة خاصة به‪.‬‬
‫إذا نفذت ]‪ُ ،a = [1,2,3‬تشير ‪ a‬إلى كائن لقائمة‪ ،‬والتي َ‬
‫قيمها هي سلسلة محددة من العناصر‪.‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪131‬‬
‫إذا امتلكت قائمة أخرى نفس العناصر‪ ،‬نقول إن لها نفس القيمة‪.‬‬
‫‪ 12.8‬التسمية البديلة‬
‫إذا كان ‪ُ a‬يشير إلى كائن‪ ،‬وأجريت عملية إسناد ‪ ،b = a‬عندها كال املُتغيرين ُ‬
‫سيشيران إلى نفس الكائن‪:‬‬
‫]‪>>> a = [1, 2, 3‬‬
‫‪>>> b = a‬‬
‫‪>>> b is a‬‬
‫‪True‬‬
‫ُ‬
‫ُيسمى ارتباط املتغير بالكائن بـ املرجع (‪ ،(reference‬في هذا املثال‪ ،‬يوجد مرجعين لنفس الكائن‪.‬‬
‫يكون للكائن الذي لديه أكثر من مرجع واحد أكثر من اسم واحد‪ ،‬لذلك نقول يملك هذا الكائن ً‬
‫اسما‬
‫ً‬
‫ً‬
‫بديال (‪ .)aliased‬إذا كان الكائن ذو االسم البديل قابال للتعديل‪ ،‬فإن التغيرات التي تحدث مع البديل‬
‫تؤثر على اآلخر‪:‬‬
‫‪>>> b[0] = 17‬‬
‫)‪>>> print(a‬‬
‫]‪[17, 2, 3‬‬
‫على الرغم من أن هذا السلوك ُيمكن أن يكون ُم ً‬
‫فيدا‪ ،‬إال أنه مسبب للخطأ‪.‬‬
‫تجنب التسمية البديلة ُي َع ُّد أكثر ً‬
‫بشكل عام‪ ،‬إن ُّ‬
‫أمانا عند عملنا مع كائنات قابلة للتعديل‪.‬‬
‫ُ‬
‫من أجل الكائنات غير القابلة للتعديل‪ ،‬مثل السالسل النصية‪ ،‬ال تعد التسمية البديلة مشكلة‪.‬‬
‫كما في املثال‪:‬‬
‫'‪a = 'banana‬‬
‫'‪b = 'banana‬‬
‫ُ‬
‫ً‬
‫تقريبا ال يوجد فرق فيما إذا كانت ‪ a‬أو ‪ b‬تشير إلى نفس السلسلة النصية‪ ،‬أم ال‪.‬‬
‫‪ 13.8‬وسائط القائمة‬
‫ُ‬
‫عندما تمرر قائمة إلى تابع‪ ،‬يحصل التابع على مرجع للقائمة‪ .‬إذا عدل التابع على ُمعامل القائمة‪،‬‬
‫ُ‬
‫تالحظ التغيير عند االستدعاء‪ .‬على سبيل املثال‪ ،‬يحذف التابع ‪ delete_head‬العنصر األول من‬
‫القائمة‪:‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪132‬‬
‫‪def delete_head(t):‬‬
‫]‪del t[0‬‬
‫إليك كيفية استخدامه‪:‬‬
‫]'‪>>> letters = ['a', 'b', 'c‬‬
‫)‪>>> delete_head(letters‬‬
‫)‪>>> print(letters‬‬
‫]'‪['b', 'c‬‬
‫ُ‬
‫املعامل ‪َ t‬واملتغير ‪ letters‬هما أسماء بديلة لنفس الكائن‪.‬‬
‫ً‬
‫ُ‬
‫ُ‬
‫ُ‬
‫من املهم أن نميز بين العمليات التي تعدل القوائم‪ ،‬والعمليات التي تنش ئ قوائم جديدة‪ .‬مثال‪ ،‬تعدل‬
‫‪ append‬على القائمة‪ ،‬بينما ينشأ عامل الجمع ‪ +‬قائمة جديدة‪.‬‬
‫]‪>>> t1 = [1, 2‬‬
‫)‪>>> t2 = t1.append(3‬‬
‫)‪>>> print(t1‬‬
‫]‪[1, 2, 3‬‬
‫)‪>>> print(t2‬‬
‫‪None‬‬
‫]‪>>> t3 = t1 + [3‬‬
‫)‪>>> print(t3‬‬
‫]‪[1, 2, 3‬‬
‫‪>>> t2 is t3‬‬
‫‪False‬‬
‫ُ‬
‫ُ‬
‫يكون هذا االختالف ًّ‬
‫مهما عندما تكتب توابع من املفترض بها أن تعدل القوائم‪.‬‬
‫ً‬
‫مثال‪ ،‬هذا التابع ال يحذف أول عنصر في القائمة‪:‬‬
‫‪def bad_delete_head(t):‬‬
‫!‪# WRONG‬‬
‫]‪t = t[1:‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪133‬‬
‫ُ‬
‫ُ‬
‫ألي من هذا تأثير على القائمة‬
‫ينش ئ عامل التجزئة قائمة جديدة‪ ،‬بحيث تشير ‪ t‬إلى القائمة‪ .‬ولكن ليس ٍ‬
‫التي ُمر َرت كوسيط‪.‬‬
‫البديل هو إنشاء تابع ينش ئ قيمة جديدة ُويعيدها‪ .‬على سبيل املثال‪ُ :‬يعيد التابع ‪ tail‬جميع العناصر‬
‫عدا العنصر األول من القائمة‪:‬‬
‫‪def tail(t):‬‬
‫]‪return t[1:‬‬
‫يترك هذا التابع القائمة األصلية بال أي تعديل‪ .‬إليك كيفية استخدامه‪:‬‬
‫]'‪>>> letters = ['a', 'b', 'c‬‬
‫)‪>>> rest = tail(letters‬‬
‫)‪>>> print(rest‬‬
‫]'‪['b', 'c‬‬
‫التمرين األول‪ :‬أنش ئ ً‬
‫تابعا باسم ‪ ،chop‬بحيث يأخذ قائمة ُويعدل عليها عن طريق إزالة العنصرين‬
‫ثم أنش ئ ً‬
‫األول واألخير‪ُ ،‬ويعيد ‪َّ ،none‬‬
‫تابعا باسم ‪ middle‬يأخذ قائمة ُويعيد قائمة جديدة تحوي‬
‫جميع العناصر عدا األول واألخير‪.‬‬
‫‪ 14.8‬التنقيح‬
‫إن سوء استخدام القوائم (والكائنات األخرى القابلة للتعديل) قد يقود إلى ساعات طويلة من عملية‬
‫التنقيح‪ .‬إليك بعض َ‬
‫الحيل واألساليب لتجنب ذلك‪:‬‬
‫ُ‬
‫ُ‬
‫َ‬
‫‪ 1‬ال َ‬
‫عكس عمل‬
‫تنس أن ُمعظم توابع القوائم تعدل الوسيط وتعيد ‪( None‬ال ش يء)‪ُ .‬يعد هذا‬
‫ُ‬
‫توابع السالسل النصية التي تعيد سلسلة نصية جديدة‪ ،‬وتتغاض ى عن السلسلة األصلية‪.‬‬
‫إذا َ‬
‫كنت ُم ً‬
‫عتادا على كتابة شيفرة السلسلة النصية على الشكل التالي‪:‬‬
‫(‪word = word.strip‬‬
‫قد تكتب شيفرة القائمة على الشكل التالي‪:‬‬
‫!‪# WRONG‬‬
‫)(‪t = t.sort‬‬
‫ُ‬
‫وألن التابع ‪ُ sort‬يعيد ‪ ،None‬فإن العملية التالية التي تجريها مع ‪ t‬مصيرها الفشل‪.‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪134‬‬
‫قبل استخدام توابع وعوامل القوائم‪ ،‬عليك قراءة ملفات التوثيق بعناية‪ ،‬واختبارها في‬
‫الوضع التفاعلي‪.‬‬
‫ُ‬
‫تصفح ملفات توثيق التوابع والعوامل التي تشاركها القوائم مع سالسل أخرى (كالسالسل‬
‫النصية) في‪:‬‬
‫‪docs.python.org/library/stdtypes.html#common-sequence-operations‬‬
‫ُ‬
‫والتوابع والقوائم التي تطبق فقط على السالسل القابلة للتغيير هنا‪:‬‬
‫‪docs.python.org/library/stdtypes.html#mutable-sequence-types‬‬
‫َ‬
‫ً‬
‫صطلحا‪ ،‬والتزم به‪:‬‬
‫‪ 2‬اختر ُم‬
‫ً‬
‫إن جزء من املشكلة مع القوائم ُ‬
‫يكمن في تعدد األساليب للقيام باألشياء‪ .‬مثال‪ ،‬إلزالة عنصر من‬
‫ُ‬
‫القائمة‪ُ ،‬يمكنك استخدام كل من ‪َ ،pop‬و‪َ ،remove‬و‪ ،del‬وحتى التجزئة‪.‬‬
‫إلضافة ُعنصر‪ ،‬يمكنك استخدام طريقة ‪ ،append‬أو عامل الجمع ‪ .+‬لكن‪ ،‬ال َ‬
‫تنس أن ما يلي‬
‫ً‬
‫صحيحا‪:‬‬
‫ُيعد‬
‫)‪t.append(x‬‬
‫]‪t = t + [x‬‬
‫أما ما يلي‪ ،‬فهو خاطئ‪:‬‬
‫!‪# WRONG‬‬
‫!‪# WRONG‬‬
‫!‪# WRONG‬‬
‫!‪# WRONG‬‬
‫)]‪t.append([x‬‬
‫)‪t = t.append(x‬‬
‫]‪t + [x‬‬
‫‪t=t+x‬‬
‫نفذ هذه األمثلة في الوضع التفاعلي لتضمن أنك تفهم آلية عملهم‪.‬‬
‫انتبه إلى أن السطر األخير فقط ُيسبب خطأ تشغيل (‪ ،(runtime error‬بينما الثالث أسطر‬
‫الباقية مسموحة‪ ،‬لكنها تنفذ ً‬
‫أمورا خاطئة‪.‬‬
‫‪ 3‬انسخ لتجنب التسمية البديلة‪:‬‬
‫ُ ُ‬
‫إذا كنت تريد استخدام تابع كـ ‪ sort‬الذي ُيعدل على الوسيط‪ ،‬ولكنك تريد االحتفاظ‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪135‬‬
‫بالقائمة األصلية على أية حال‪ ،‬يمكنك عمل نسخة‪.‬‬
‫]‪orig = t[:‬‬
‫)(‪t.sort‬‬
‫ُيمكنك في هذا املثال ً‬
‫أيضا استخدام التابع الجاهز ‪ ،sorted‬والذي ُيعيد قائمة جديدة‬
‫ُمرتبة‪ ،‬ويترك القائمة األصلية على حالها‪ .‬لكن‪ ،‬في تلك الحالة‪ ،‬احرص على ُّ‬
‫تجنب استخدام‬
‫ُ‬
‫‪ sorted‬كاسم ملتغير‪.‬‬
‫‪ 4‬استخدام القوائم والتابع ‪ split‬مع امللفات‪:‬‬
‫عندما نقرأ ونحلل امللفات‪ ،‬هناك احتمالية أن إحدى املدخالت قد توقف برنامجنا‪ .‬لذا‪،‬‬
‫ً‬
‫ً‬
‫فإن إعادة النظر في نمط الحماية ُيعد فكرة جيدة عند كتابة البرامج التي تبحث في امللف‬
‫َ‬
‫"كالبحث عن إبرة في كومة قش"‪.‬‬
‫ُ‬
‫دعونا نعد النظر في برنامجنا الذي يبحث عن يوم من أيام األسبوع من السطور املوجودة في‬
‫ملف‪.‬‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫ُبمجرد تقسيمنا السطر إلى كلمات‪ ،‬بإمكاننا االستغناء عن استخدام تعليمة ‪،startswith‬‬
‫ُ‬
‫والنظر ببساطة إلى الكلمة األولى من السطر لتحديد ما إذا كنا ُمهتمين في السطر ككل‪ .‬كما‬
‫بإمكاننا استخدام ‪ continue‬لتخطي السطور التي ال تحتوي الكلمة ‪ From‬ككلمة أولى على‬
‫النحو التالي‪:‬‬
‫)'‪fhand = open('mbox-short.txt‬‬
‫‪for line in fhand:‬‬
‫)(‪words = line.split‬‬
‫‪if words[0] != 'From' : continue‬‬
‫)]‪print(words[2‬‬
‫يبدو هذا أكثر سهولة‪ .‬باإلضافة إلى أننا ال نحتاج حتى إلى تنفيذ التابع ‪ rstrip‬إلزالة محرف‬
‫السطر الجديد في نهاية امللف‪ .‬لكن هل هذا أفضل؟‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪136‬‬
‫‪python search8.py‬‬
‫‪Sat‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "search8.py", line 5, in <module‬‬
‫‪if words[0] != 'From' : continue‬‬
‫‪IndexError: list index out of range‬‬
‫ً‬
‫ً‬
‫صحيحا‪ ،‬بحيث أننا نحصل على اليوم من السطر األول (السبت ‪ .)sat‬لكن‪ ،‬بعد‬
‫قد يبدو هذا عمال‬
‫ذلك يفشل البرنامج مع وجود خطأ‪ .‬ما الخطأ الذي حصل؟‬
‫ما هي البيانات التالفة التي تسببت بفشل برنامج بايثون األنيق والذكي الخاص بنا؟‬
‫ً‬
‫ُ‬
‫قد تفكر مطوال في البرنامج‪ ،‬وتتملك َك الحيرة‪ ،‬أو يمكن أن تسأل شخص ما ملساعدتك‪.‬‬
‫َّ‬
‫ولكن النهج األذكى واألسرع هو إضافة تعليمة ‪ .print‬إن املكان األفضل إلضافة تعليمة ‪ print‬هو‬
‫بالتحديد قبل السطر الذي أخفق به البرنامج‪ ،‬ثم طباعة البيانات التي تبدو ُمسببة للفشل‪.‬‬
‫قد يؤدي هذا النهج إلى عرض الكثير من األسطر في الخرج‪ ،‬لكن على األقل ستكون قد كشفت ً‬
‫فورا‬
‫ُ‬
‫على طرف الخيط لحل املشكلة‪ ،‬لذلك أضفنا تعليمة طباعة املتغير ‪ words‬قبل السطر الخامس‬
‫ُ‬
‫ً‬
‫ُمباشرة‪ .‬حتى أننا أضفنا البادئة "‪ "Debug:‬إلى السطر البرمجي‪ ،‬بحيث نتمكن من املحافظة على خرج‬
‫ً‬
‫البرنامج ُمنفصال عن خرج عملية التنقيح‪.‬‬
‫‪for line in fhand:‬‬
‫)(‪words = line.split‬‬
‫)‪print('Debug:', words‬‬
‫‪if words[0] != 'From' : continue‬‬
‫)]‪print(words[2‬‬
‫ُ‬
‫عندما نشغل البرنامج‪ ،‬تعرض الكثير من السطور على الشاشة‪ .‬لكن‪ ،‬في النهاية‪ ،‬نرى خرج التنقيح‬
‫الخاص بنا‪ ،‬وخطأ التتبع‪ ،‬لذا ُندرك ما حدث بالضبط قبل خطأ ُّ‬
‫التتبع‪.‬‬
‫]'‪Debug: ['X-DSPAM-Confidence:', '0.8475‬‬
‫]'‪Debug: ['X-DSPAM-Probability:', '0.0000‬‬
‫][ ‪Debug:‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪137‬‬
‫‪Traceback (most recent call last):‬‬
‫>‪File "search9.py", line 6, in <module‬‬
‫‪if words[0] != 'From' : continue‬‬
‫‪IndexError: list index out of range‬‬
‫كل سطر من عملية التنقيح يطبع قائمة من الكلمات‪ ،‬والتي نحصل عليها عند تفرقة السطر إلى‬
‫كلمات‪.‬‬
‫عندما يفشل البرنامج‪ ،‬تكون قائمة الكلمات فارغة ][‪ .‬إذا فتحنا امللف في ُمحرر النصوص‬
‫وتفحصناه‪ ،‬سيظهر على الشكل التالي‪:‬‬
‫‪X-DSPAM-Result: Innocent‬‬
‫‪X-DSPAM-Processed: Sat Jan 5 09:14:16 2008‬‬
‫‪X-DSPAM-Confidence: 0.8475‬‬
‫‪X-DSPAM-Probability: 0.0000‬‬
‫‪Details: http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772‬‬
‫يظهر الخطأ عندما يصطدم برنامجنا بسطر فارغ‪.‬‬
‫ُ‬
‫بالطبع‪ ،‬ال يحتوي السطر الفارغ على كلمات‪ .‬ملاذا لم نفكر بذلك عند كتابة البرنامج؟‬
‫ُ‬
‫عندما تبحث الشيفرة عن الكلمة األولى ]‪ word[0‬للتحقق منها ملعرفة ما إذا كانت تطابق ‪،From‬‬
‫نحصل على خطأ فهرس خارج النطاق )‪. (index out of range error‬‬
‫بالطبع‪ ،‬هذا هو املكان املثالي إلضافة البعض من شيفرات الحماية – ‪guardian code‬‬
‫ُّ‬
‫لتجنب عملية التحقق من الكلمة األولى في حال لم تكن الكلمة األولى موجودة‪.‬‬
‫يوجد العديد من األساليب لحماية هذه الشيفرة‪ .‬سنلجأ إلى التحقق من عدد الكلمات التي لدينا قبل‬
‫البحث عن الكلمة األولى‪:‬‬
‫)'‪fhand = open('mbox-short.txt‬‬
‫‪count = 0‬‬
‫‪for line in fhand:‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪138‬‬
‫)(‪words = line.split‬‬
‫)‪# print('Debug:', words‬‬
‫‪if len(words) == 0 : continue‬‬
‫‪if words[0] != 'From' : continue‬‬
‫)]‪print(words[2‬‬
‫ً‬
‫في البداية‪ ،‬تجاهلنا تعليمة التنقيح بدال من إزالتها‪ ،‬والسبب أنه في حال فشل التعديل الذي قمنا به‪،‬‬
‫فنحن بحاجة إلى التنقيح ُمجد ًدا‪.‬‬
‫ثم أضفنا تعليمة حماية تتحقق من حالة عدم وجود كلمات‪ .‬وفي هذه الحالة‪ ،‬نستعمل التعليمة‬
‫‪ continue‬لتخطي السطر التالي في امللف‪.‬‬
‫ُ‬
‫ُ‬
‫ُيمكننا اعتبار أن تعليمتي ‪ continue‬تساعداننا في تنقيح بعض األسطر البرمجية "املهمة" بالنسبة‬
‫ُ‬
‫ُ‬
‫لنا‪ ،‬والتي نريد أن نخضعها ملزيد من املعالجة‪.‬‬
‫إن السطر الذي ال يحوي كلمات ُيعد "غير مهم"‪ ،‬لذلك نتخطاه إلى السطر الذي يليه‪ً .‬‬
‫أيضا السطر‬
‫الذي ال يحوي كلمة ‪ From‬ككلمة أولى غير مهم‪ ،‬ويمكن تخطيه‪.‬‬
‫إن البرنامج ‪-‬كما ُعد َل‪ -‬يعمل بنجاح‪ ،‬لذا من املمكن أن يكون صحيح‪.‬‬
‫ً‬
‫كاف‪ ،‬ألننا عندما‬
‫إن تعليمة الحماية تحرص على أن ]‪ words[0‬لن تفشل أبدا‪ .‬لكن‪ ،‬ربما هذا غير ٍ‬
‫ُنبرمج نتساءل ً‬
‫دوما‪" ،‬ما الخطأ الذي قد يحدث"؟‬
‫محمي بشكل كامل‪.‬‬
‫التمرين الثاني‪ :‬اكتشف أي سطر من البرنامج أعاله ال يزال غير‬
‫ٍ‬
‫تحقق من إمكانية إنشاء ملف نص ي يؤدي إلى فشل البرنامج‪ًّ ،‬‬
‫ثم عدل البرنامج بحيث تؤمن حماية‬
‫ُ‬
‫اختبره للتأكد من تعامله السليم مع ملفك النص ي الجديد‪.‬‬
‫للسطر البرمجي‪ .‬بعد ذلك‪،‬‬
‫ً‬
‫التمرين الثالث‪ :‬أعد كتابة شيفرة الحماية في املثال أعاله دون استعمال تعليمتي ‪ if‬فبدال من ذلك‪،‬‬
‫ُ‬
‫استخدم التعبير املنطقي املركب باستخدام العامل املنطقي ‪ or‬مع عبارة ‪ if‬واحدة‪.‬‬
‫‪ 15.8‬فهرس املصطلحات‬
‫• التسمية البديلة (‪ :)Aliasing‬الحالة التي يكون فيها ُمتغيران أو أكثر ُيشيران إلى نفس‬
‫الكائن‪.‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪139‬‬
‫ُ‬
‫ُ‬
‫امل ّ‬
‫حد ْد (‪ :)Delimiter‬محرف أو سلسلة نصية‪ ،‬تستعمل لإلشارة إلى املكان الذي يجب أن‬
‫•‬
‫ِّ‬
‫ُ‬
‫تفصل به السلسلة النصية‪.‬‬
‫العنصر(‪ :)Element‬واحد من القيم في القائمة (أو سلسلة أخرى)‪ ،‬يمكن أن نسميه أي ً‬
‫• ُ‬
‫ضا‬
‫‪.item‬‬
‫ُ‬
‫كافئ (‪ُ :)Equivalent‬له القيمة ذاتها‪.‬‬
‫• م ِّ‬
‫ُ‬
‫• الفهرس (‪ :)index‬قيمة صحيحة تشير إلى عنصر في القائمة‪.‬‬
‫ُ‬
‫التطابق (‪ُ :)Identical‬مطابق لنفس الكائن (بما يعني التكافؤ)‪.‬‬
‫•‬
‫• القائمة (‪ :)List‬سلسلة من القيم‪.‬‬
‫• املرورعلى عناصرقائمة (‪ :)List traversal‬الوصول التسلسلي إلى كل عنصر في القائمة‪.‬‬
‫ُ‬
‫• القائمة املتداخلة (‪ :)Nested list‬القائمة التي تكون ُع ً‬
‫نصرا ضمن قائمة أخرى‪.‬‬
‫• الكائن (‪ :)Object‬ش يء أو ُمتغير ُيمكن اإلشارة إليه‪ ،‬بحيث يكون للكائن نوع وقيمة‪.‬‬
‫ُ‬
‫• املرجع (‪ :)Reference‬يمثل االرتباط بين املتغير وقيمته‪.‬‬
‫‪ 16.8‬تمارين‬
‫• التمرين الرابع‪ :‬حمل نسخة من امللف من الرابط التالي‪:‬‬
‫‪www.py4e.com/code3/romeo.txt‬‬
‫ً‬
‫برنامجا لفتح امللف ‪ romeo.txt‬وقراءته ً‬
‫سطرا بسطر‪.‬‬
‫اكتب‬
‫ً‬
‫َ‬
‫ُ‬
‫ُ‬
‫من أجل كل سطر‪ ،‬فرق السطر إلى كلمات ُمستعمال التابع ‪ .split‬ومن أجل كل كلمة‪ ،‬تحقق ما‬
‫إذا كانت موجودة ُم ً‬
‫سبقا في القائمة‪ .‬في حال لم تكن موجودة‪ ،‬أضفها إلى القائمة‪.‬‬
‫ً‬
‫عند اكتمال البرنامج‪ ،‬رتب واطبع الكلمات الناتجة ً‬
‫أبجديا‪.‬‬
‫ترتيبا‬
‫‪Enter file: romeo.txt‬‬
‫‪['Arise', 'But', 'It', 'Juliet', 'Who', 'already',‬‬
‫‪'and', 'breaks', 'east', 'envious', 'fair', 'grief',‬‬
‫‪'is', 'kill', 'light', 'moon', 'pale', 'sick', 'soft',‬‬
‫‪'sun', 'the', 'through', 'what', 'window',‬‬
‫الفصل الثامن‪ :‬القوائم‬
‫‪140‬‬
‫]'‪'with', 'yonder‬‬
‫ً‬
‫برنامجا لقراءة بيانات امللف‪ . mail box‬عندما تجد ً‬
‫سطرا يبدأ‬
‫• التمرين الخامس‪ :‬اكتب‬
‫مستخدما التابع ‪ُ .split‬‬
‫ً‬
‫نحن ُّ‬
‫نهتم ُبمرسل الرسالة‪،‬‬
‫بـ ‪ ،From‬قسم السطر إلى كلمات‬
‫والتي هي الكلمة الثانية من السطر‪.‬‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫ُ‬
‫ستحلل السطر الذي يبدأ بـ ‪ ،From‬ثم تطبع الكلمة الثانية من كل سطر يبدأ بـ ‪.From‬‬
‫باإلضافة إلى ذلك‪ ،‬ستحص ي عدد السطور التي تبدأ بـ ‪ ،From‬وتطبع العدد في النهاية‪.‬‬
‫فيما يلي خرج لعينة محذوف منها بضعة أسطر‪:‬‬
‫‪python fromcount.py‬‬
‫‪Enter a file name: mbox-short.txt‬‬
‫‪stephen.marquard@uct.ac.za‬‬
‫‪louis@media.berkeley.edu‬‬
‫‪zqian@umich.edu‬‬
‫]‪[...some output removed...‬‬
‫‪ray@media.berkeley.edu‬‬
‫‪cwen@iupui.edu‬‬
‫‪cwen@iupui.edu‬‬
‫‪cwen@iupui.edu‬‬
‫‪There were 27 lines in the file with From as the first word‬‬
‫• التمرين السادس‪ :‬أعد كتابة البرنامج الذي يطلب من املستخدم قائمة مكونة من‬
‫ُ‬
‫أعداد‪ ،‬ث َّم يطبع العدد األعظمي واألصغري من األعداد عندما ُيدخل املستخدم "‪"done‬‬
‫في نهاية البرنامج‪.‬‬
‫اكتب البرنامج لتخزين األعداد التي أدخلها املستخدم إلى القائمة‪ .‬واستخدم التابعين‬
‫ القوائم‬:‫الفصل الثامن‬
141
.‫ لحساب القيمة األعظمية واألصغرية لألعداد بعد اكتمال الحلقة‬min()‫ َو‬max()
Enter a number: 6
Enter a number: 2
Enter a number: 9
Enter a number: 3
Enter a number: 5
Enter a number: done
Maximum: 9.0
Minimum: 2.0
‫الفصل التاسع‬
‫القواميس‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪143‬‬
‫‪ 9‬القواميس‬
‫يشابه القاموس (‪ )dictionary‬القوائم (‪ )list‬إال أنه أكثر شمولية‪ ،‬ففي القوائم تكون فهارس املواقع‬
‫أعداد صحيحة ‪ int‬على عكس القواميس حيث قد تكون من أي نوع‪ ،‬حيث يمكنك تخيل القاموس‬
‫وكأنه يربط بين مجموعة فهارس والتي تدعى باملفاتيح )‪ )keys‬ومجموعة من القيم )‪ ،(values‬حيث‬
‫يدعى ارتباط املفتاح مع القيمة بزوج مفتاح‪-‬قيمة (‪ (key-value pair‬أو ً‬
‫أحيانا يدعى بالعنصر )‪.(item‬‬
‫لتوضيح ما سبق‪ ،‬سننش ئ قاموس يربط كلمات باإلنكليزية مع ترجماتها في اللغة اإلسبانية بالتالي هنا‬
‫كال املفاتيح والقيم هما من نوع البيانات سالسل نصية‪.‬‬
‫ً‬
‫ً‬
‫قاموسا فارغا بدون أي عناصر‪ .‬لذا‪ ،‬يجب عليك تجنب تسمية متغيراتك بهذا‬
‫ينش ئ التابع ‪dict‬‬
‫االسم‪ ،‬ألنه اسم تابع في لغة بايثون‪:‬‬
‫)(‪>>> eng2sp = dict‬‬
‫)‪>>> print(eng2sp‬‬
‫}{‬
‫ً‬
‫تمثل أقواس املجموعة {} قامو ًسا فارغا وإلضافة عناصر لهذا القاموس يجب استخدام األقواس‬
‫القائمة []‪:‬‬
‫'‪>>> eng2sp['one'] = 'uno‬‬
‫حيث يضيف هذا السطر البرمجي عنصر يرتبط فيه املفتاح '‪ 'one‬بالقيمة "‪ "uno‬فإذا أظهرنا محتوى‬
‫القاموس ينتج لدينا زوج مفتاح‪-‬قيمة يفصل بينهما عالمة النقطتين‪:‬‬
‫)‪>>> print(eng2sp‬‬
‫}'‪{'one' : 'uno‬‬
‫تماثل صيغة الدخل صيغة الخرج في املثال السابق‪ ،‬لكن في حال إنشاء قاموس بثالثة عناصر قد‬
‫تتفاجأ عند طباعة ‪ eng2sp‬حيث يظهر ما يلي‪:‬‬
‫}'‪>>> eng2sp = {'one': 'uno', 'two': 'dos', 'three': 'tres‬‬
‫)‪>>> print(eng2sp‬‬
‫}'‪{'one': 'uno', 'three': 'tres', 'two': 'dos‬‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪144‬‬
‫حيث ترتيب العناصر ال يكون نفسه في كل مرة وال يمكن التنبؤ به في القواميس‪ ،‬حتى إن جربت كتابة‬
‫نفس املثال على حاسوبك فقد تحصل على نتيجة مختلفة‪ ،‬إال أن هذا ال يشكل مشكلة ألن فهارس‬
‫ُ‬
‫العناصر في القواميس ليست عبارة عن أرقام صحيحة بل تستخدم املفاتيح إلظهار القيمة املوافقة‬
‫لها‪:‬‬
‫)]'‪>>> print(eng2sp['two‬‬
‫'‪'dos‬‬
‫فاملفتاح '‪ 'two‬مرتبط بالقيمة '‪ً 'dos‬‬
‫دائما‪ .‬فيكون ترتيب العناصر غير مهم‪ ،‬وستحصل على رسالة‬
‫خطأ إن كان القاموس ال يحوي املفتاح املطلوب‪:‬‬
‫)]'‪>>> print(eng2sp['four‬‬
‫'‪KeyError: 'four‬‬
‫ويمكن استخدام التابع ‪ len‬مع القواميس ليظهر عدد العناصر في القاموس‪:‬‬
‫)‪>>> len(eng2sp‬‬
‫‪3‬‬
‫كما يمكن استخدام العامل ‪ in‬معها حيث يؤكد وجود مفتاح معين في القاموس من عدمه (ال يتعامل‬
‫مع القيم)‪:‬‬
‫‪>>> 'one' in eng2sp‬‬
‫‪True‬‬
‫‪>>> 'uno' in eng2sp‬‬
‫‪False‬‬
‫أما للبحث عن قيمة ما ضمن القاموس‪ ،‬يمكن استخدام تابع يدعى ‪ values‬يعيد القيم كقائمة ثم‬
‫نستخدم العامل ‪:in‬‬
‫))(‪>>> vals = list(eng2sp.values‬‬
‫‪>>> 'uno' in vals‬‬
‫‪True‬‬
‫لكل من القوائم والقواميس‪ ،‬ففي‬
‫مع األخذ بعين االعتبار أن العامل ‪ in‬يستخدم خوارزميات مختلفة ٍ‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪145‬‬
‫القوائم‪ ،‬يعتمد على خوارزمية بحث خطية‪ ،‬مما يزيد الوقت الالزم للبحث في قيم القائمة كلما زاد‬
‫طولها‪ .‬بينما تستخدم بايثون للقواميس خوارزمية تدعى "‪ "hash table‬والتي تتميز بأن العامل ‪in‬‬
‫قاموس ما بغض النظر عن عدد عناصره‪ .‬وال يمكننا‬
‫سيستغرق نفس الوقت في البحث ضمن‬
‫ٍ‬
‫الحديث هنا عن ميزات هذه الخوارزمية الرائعة ولكن بإمكانك أن تقرأ القليل عنها من هنا‪:‬‬
‫‪www.wikipedia.org/wiki/Hash_table‬‬
‫التمرين األول‪ :‬حمل نسخة من امللف املوجود على الرابط اآلتي‪:‬‬
‫‪www.py4e.com/code3/words.txt‬‬
‫ً‬
‫قاموس ما بغض النظر عما‬
‫برنامجا يقرأ الكلمات املوجود في هذا امللف ثم يخزنها كمفاتيح في‬
‫اكتب‬
‫ٍ‬
‫ستكون عليه القيم‪ ،‬ثم استخدم العامل ‪ in‬للتحقق من وجود كلمة معينة‪.‬‬
‫‪ 1.9‬استخدام القواميس في العد‬
‫ُ‬
‫نص أمامك تريد أن تستخرج منه عدد مرات تكرار كل حرف‪ ،‬توجد عدة طرق لحل‬
‫افترض وجود ٍ‬
‫هذا‪:‬‬
‫‪ .1‬بإمكانك إنشاء ‪ 26‬متغير حيث يقابل كل متغير أحد األحرف األبجدية اإلنكليزية‪ ،‬ثم تمر على‬
‫ً‬
‫مستخدما سلسلة من العبارات‬
‫كل محرف على حدى لتزيد قيمة العداد املوافقة لكل متغير‬
‫الشرطية‪.‬‬
‫‪ .2‬تستطيع إنشاء قائمة ذات ‪ 26‬عنصر ثم تحويل كل محرف إلى رقم بواسطة التابع ‪ord‬‬
‫الستخدامه كفهرس في القائمة وزيادة العداد املوافق له‪.‬‬
‫‪ .3‬يمكن إنشاء قاموس حيث تشكل األحرف املفاتيح فيه‪ ،‬وتشكل عددها القيم املوافقة للمفاتيح‪.‬‬
‫ُ‬
‫فعند اكتشاف املحرف ألول مرة‪ُ ،‬‬
‫سيدخل عنصر جديد للقاموس بينما في املرات التالية ستزاد‬
‫قيمة هذا العنصر فقط‪.‬‬
‫تحل كل طريقة من هذه الطرق املشكلة بأسلوب مختلف‪ ،‬ونجد هنا مفهوم التنفيذ ويعني أسلوب‬
‫حل مسألة ما‪ ،‬وتكون بعض هذه االساليب أفضل من غيرها‪ ،‬فعلى سبيل املثال تكمن فائدة تطبيق‬
‫مسبقا بل نخصص لها ً‬
‫ً‬
‫مكانا ً‬
‫معينا‬
‫استخدام القاموس في عدم حاجتنا ملعرفة األحرف التي ستظهر‬
‫بعد ظهورها‪ ،‬وسيبدو البرنامج كما يأتي‪:‬‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪146‬‬
‫'‪word = 'brontosaurus‬‬
‫)(‪d = dict‬‬
‫‪for c in word:‬‬
‫‪if c not in d:‬‬
‫‪d[c] = 1‬‬
‫‪else:‬‬
‫‪d[c] = d[c] + 1‬‬
‫)‪print(d‬‬
‫أي أننا ً‬
‫علميا حسبنا الهيستوغرام )‪ )histogram‬وهو مصطلح إحصائي يدل على مجموعة من‬
‫العدادات (أو التكرارات) للعناصر‪ .‬وكما نرى فإن الحلقة ‪ for‬تمر على محارف النص‪ ،‬وفي كل مرة ال‬
‫نجد املحرف ضمن القاموس ننش ئ عنصر جديد فيه مفتاحه ‪ c‬وقيمته االبتدائية ‪( 1‬بما أن املحرف‬
‫ً‬
‫ً‬
‫مسبقا فنكتفي بزيادة قيمة ]‪ d[c‬ليكون خرج‬
‫موجودا ضمنه‬
‫ظهر ملرة واحدة)‪ ،‬لكن إن كان املفتاح ‪c‬‬
‫البرنامج كاآلتي‪:‬‬
‫}‪{'a': 1, 'b': 1, 'o': 2, 'n': 1, 's': 2, 'r': 2, 'u': 2, 't': 1‬‬
‫أي‪ ،‬يبين الهيستوغرام أن األحرف ‪ a‬و‪ b‬قد ظهرت مرة واحدة في حين تكرر ‪ o‬مرتين وهكذا دواليك‪،‬‬
‫كما تملك القواميس تابع يدعى ‪ get‬يتطلب هذا التابع معاملين هما املفتاح وقيمة معينة يعيدها في‬
‫حال عدم وجود املفتاح ضمن القاموس وإال يعيد القيمة املوافقة للمفتاح واملوجودة ضمن‬
‫القاموس‪ ،‬وتمثل هذه التعليمة كما يأتي‪:‬‬
‫}‪counts = { 'chuck': 1 , 'annie': 42, 'jan': 100‬‬
‫))‪>>> print ( counts.get ( ‘jan’, 0‬‬
‫‪100‬‬
‫))‪>>> print ( counts.get (‘tim’, 0‬‬
‫‪0‬‬
‫وهذا يمكننا من كتابة برنامجنا بأسلوب مختصر أكثر فالتابع ‪ get‬يحل مسألة عدم وجود املفتاح‬
‫ً‬
‫تلقائيا مما يؤدي إلى اختصار أربعة أسطر برمجية إلى واحد واالستعاضة عن تعليمة‬
‫ضمن القاموس‬
‫‪:if‬‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪147‬‬
‫'‪word = 'brontosaurus‬‬
‫)(‪d = dict‬‬
‫‪for c in word:‬‬
‫‪d[c] = d.get(c,0) + 1‬‬
‫)‪print(d‬‬
‫إن اتباع هذا األسلوب شائع في بايثون وسنستعمله عدة مرات في بقية الكتاب‪ ،‬لذلك قد تحتاج بعض‬
‫الوقت لتقارن بين األسلوبين حيث استخدمنا ‪ get‬لالستعاضة عن تعليمة ‪ if‬والعامل ‪ in‬في الحلقة‬
‫ً‬
‫اختصارا‪.‬‬
‫فكالهما يؤديان نفس الوظيفة إال أن أحدهما أكثر‬
‫‪ 2.9‬القواميس وامللفات‬
‫ً‬
‫ً‬
‫شائعا‪،‬‬
‫استخداما‬
‫إن استخدام القواميس لعد عدد مرات تكرار الكلمات في امللفات النصية يعد‬
‫لذلك سنبدأ بتوضيح هذا بمثال صغير مأخوذ من امللف النص ي "‪ "Romeo and Juliet‬حيث في‬
‫األمثلة األولى سنستخدم نسخة مبسطة ومختصرة من النص بدون عالمات ترقيم كما يأتي‪:‬‬
‫‪But soft what light through yonder window breaks‬‬
‫‪It is the east and Juliet is the sun‬‬
‫‪Arise fair sun and kill the envious moon‬‬
‫‪Who is already sick and pale with grief‬‬
‫سنكتب اآلن برنامج بلغة بايثون يقرأ أسطر النص ويجزئها إلى قائمة من الكلمات ثم يمر على كل منها‬
‫ً‬
‫باستخدام حلقة ليعد مرات تكرارها حافظا النتيجة في قاموس‪ .‬كما ستالحظ أننا استخدمنا حلقتي‬
‫‪ for‬حيث تقرأ األولى أسطر النص‪ ،‬بينما تمر الثانية على كلمات كل سطر‪ .‬ويدعى هذا النمط‬
‫بالحلقات املتداخلة (‪ (nested loops‬وسبب التسمية يرجع لوجود حلقة خارجية وأخرى داخلية‬
‫ضمنها‪ .‬وتنفذ الحلقة الداخلية جميع تكراراتها من أجل كل تكرار للحلقة الخارجية‪ ،‬فيبدو وكأن‬
‫الحلقة الداخلية تعمل بشكل سريع بينما تكون الخارجية أبطأ منها‪ ،‬و ً‬
‫أيضا يضمن لنا هذا النمط‬
‫املرور على كل كلمة في كل سطر من النص املدخل‪:‬‬
‫) ‘ ‪fname = input(‘Enter the file name:‬‬
‫‪try:‬‬
‫)‪fhand = open(fname‬‬
‫ القواميس‬:‫الفصل التاسع‬
148
except:
print(‘File cannot be opened: ‘, fname)
exit()
counts = dict()
for line in fhand:
words = line.split()
for word in words:
if word not in counts:
counts[word] = 1
else:
counts[word] += 1
print(counts)
# Code: http://www.py4e.com/code3/count1.py
counts[word]+=1 ‫ التعليمة البديلة املختصرة للزيادة العددية حيث‬else ‫لقد استخدمنا في تعليمة‬
‫أي منهما لتغيير القيمة العددية بأي‬
ٍ ‫ ويمكن استخدام‬counts[word]=counts[word]+1 ‫تكافئ‬
‫ وعند تنفيذ البرنامج سنحصل على سطر‬/= ‫ و =* و‬-= ‫قيمة مطلوبة حيث توجد بدائل شبيهة مثل‬
‫ من‬romeo.txt ‫من العدادات بصيغة غير مرتبة كما يأتي (يمكن الحصول على امللف‬
:)www.py4e.com/code3/romeo.txt
python count1.py
Enter the file name: romeo.txt
{'and': 3, 'envious': 1, 'already': 1, 'fair': 1, 'is': 3, 'through': 1, 'pale': 1, 'yonder': 1, 'what':
1, 'sun': 2, 'Who': 1, 'But': 1, 'moon': 1, 'window': 1, 'sick': 1, 'east': 1, 'breaks': 1, 'grief':
1, 'with': 1, 'light': 1, 'It': 1, 'Arise': 1, 'kill': 1, 'the': 3, 'soft': 1, 'Juliet': 1}
‫ لذلك سنضيف بعض التعليمات‬،‫ولكنه من غير املريح البحث عن أكثر الكلمات تكر ًارا في القاموس‬
.‫البرمجية للحصول على الخرج املطلوب‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪149‬‬
‫‪ 3.9‬الحلقات والقواميس‬
‫إن حلقة ‪ for‬تمر على مفاتيح القاموس وفي مثالنا اآلتي فإنها ستطبع املفتاح مع القيمة املوافقة له‪:‬‬
‫}‪counts = { 'chuck': 1 , 'annie': 42, 'jan': 100‬‬
‫‪for key in counts:‬‬
‫)]‪print(key, counts[key‬‬
‫فيكون الخرج‪:‬‬
‫‪jan 100‬‬
‫‪chuck 1‬‬
‫‪annie 42‬‬
‫وكما ذكرنا ً‬
‫بترتيب معين‪ ،‬ويمكننا استخدام هذا النمط لتنفيذ ما تعلمناه‬
‫سابقا فاملفاتيح غير مرتبة‬
‫ٍ‬
‫ً‬
‫سابقا‪ ،‬فعلى سبيل املثال سنكتب البرنامج اآلتي للحصول على عناصر القاموس ذات قيمة أكبر من‬
‫عشرة‪:‬‬
‫}‪counts = { 'chuck': 1 , 'annie': 42, 'jan': 100‬‬
‫‪for key in counts:‬‬
‫‪if counts[key] > 10 :‬‬
‫)]‪print(key, counts[key‬‬
‫ستمر الحلقة على مفاتيح القاموس لذلك نستخدم عامل الفهرس الستدعاء القيمة املوافقة‬
‫للمفتاح ويكون الخرج‪:‬‬
‫‪jan 100‬‬
‫‪annie 42‬‬
‫أي أننا حصلنا فقط على العناصر ذات القيم األكبر من عشرة‪ ،‬أما لعرض املفاتيح بترتيب أبجدي‬
‫ً‬
‫فيجب علينا أوال إنشاء قائمة من مفاتيح القاموس باستخدام التابع ‪ keys‬ثم ترتيبها‪ ،‬ثم طباعة‬
‫األزواج مفتاح‪-‬قيمة بالترتيب األبجدي‪:‬‬
‫}‪counts = { 'chuck': 1 , 'annie': 42, 'jan': 100‬‬
‫))(‪lst = list(counts.keys‬‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪150‬‬
‫)‪print(lst‬‬
‫)(‪lst.sort‬‬
‫‪for key in lst:‬‬
‫)]‪print(key, counts[key‬‬
‫ويكون الخرج‪:‬‬
‫]'‪['jan', 'chuck', 'annie‬‬
‫‪annie 42‬‬
‫‪chuck 1‬‬
‫‪jan 100‬‬
‫ً‬
‫نرى أوال قائمة املفاتيح غير املرتبة التي حصلنا عليها باستخدام التابع ‪ keys‬ثم نرى األزواج مفتاح‪-‬‬
‫قيمة املرتبة‪.‬‬
‫‪ 4.9‬التعامل مع النصوص‬
‫لقد جعلنا النص في املثال السابق بأبسط شكل بإزالة كل عالمات الترقيم منه‪ ،‬إال أن النص األصلي‬
‫يحتوي على العديد من عالمات الترقيم كما نالحظ‪:‬‬
‫?‪But, soft! what light through yonder window breaks‬‬
‫‪It is the east, and Juliet is the sun.‬‬
‫‪Arise, fair sun, and kill the envious moon,‬‬
‫‪Who is already sick and pale with grief,‬‬
‫وبما أن التابع ‪ split‬يعامل الكلمات كرموز تفصل بينها فراغات فستعامل "!‪ "soft‬و"‪ "soft‬ككلمتين‬
‫مختلفتين وسيتم إنشاء مكان منفرد لكل منهما ضمن القاموس‪ .‬و ً‬
‫أيضا سنعامل "‪ "who‬و"‪"Who‬‬
‫ٍ‬
‫ككلمتين مختلفتين باعتبار أن النص يحوي حروف كبيرة وصغيرة‪ ،‬ولكن نستطيع حل املشكلتين‬
‫باستخدام التوابع النصية ‪ lower‬و‪ punctuation‬و‪ translate‬حيث أن األخيرة هي األفضل وتوصيفها‬
‫كما يأتي‪:‬‬
‫))‪line.translate(str.maketrans(fromstr, tostr, deletestr‬‬
‫والتي تعني‪ :‬استبدل املحارف في ‪ fromstr‬باملحارف ذات املوقع نفسه في ‪ tostr‬واحذف جميع املحارف‬
‫ القواميس‬:‫الفصل التاسع‬
151
.deletestr ‫ سالسل نصية فارغة مع إهمال‬tostr‫ و‬fromstr ‫ ويمكن أن يكون‬،deletestr ‫في‬
‫ لحذف عالمات الترقيم كما سنطلب من بايثون‬deletestr ‫ ولكن سنستخدم معامل‬tostr ‫لن نعرف‬
:‫أن تخبرنا بمجموعة املحارف التي تعتبرها كعالمات ترقيم وذلك كما يأتي‬
>>> import string
>>> string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
‫ ثم نطبق‬،python 2.0 ‫ كانت مختلفة في‬translate ‫ويجب اإلشارة إلى أن املعامالت املستخدمة مع‬
:‫التعديالت اآلتية على برنامجنا‬
import string
fname = input('Enter the file name: ' )
try:
fhand = open(fname)
except:
print( ' File cannot be opened: ' , fname)
exit()
counts = dict()
for line in fhand:
line = line.rstrip()
line = line.translate(line.maketrans(' ', ' ', string.punctuation))
line = line.lower()
words = line.split()
for word in words:
if word not in counts:
counts[word] = 1
else:
counts[word] += 1
print(counts)
# Code: http://www.py4e.com/code3/count2.py
‫الفصل التاسع‪ :‬القواميس‬
‫‪152‬‬
‫إن جزء من تعلم فن بايثون أو التفكير بطريقة بايثون هو إدراك أن بايثون تحتوي على قدرات (توابع‬
‫جاهزة) لحل العديد من مشاكل تحليل البيانات‪ ،‬وسترى مع مرور الزمن أمثلة كافية وستقرأ ما يكفي‬
‫من التوصيفات التي تجعلك تجيد البحث وتستفيد من البرامج املكتوبة من قبل مبرمجين آخرين مما‬
‫يسهم في تسهيل عملك‪.‬‬
‫يكون الخرج املختصر للبرنامج السابق كما يأتي‪:‬‬
‫‪Enter the file name: romeo-full.txt‬‬
‫‪{'swearst': 1, 'all': 6, 'afeard': 1, 'leave': 2, 'these': 2, 'kinsmen': 2, 'what': 11, 'thinkst': 1,‬‬
‫‪'love': 24, 'cloak': 1, 'a': 24, 'orchard': 2, 'light': 5, 'lovers': 2, 'romeo': 40, 'maiden': 1,‬‬
‫}‪'whiteupturned': 1, 'juliet': 32, 'gentleman': 1, 'it': 22, 'leans': 1, 'canst': 1, 'having': 1, ...‬‬
‫ولكن البحث عما نريد ضمن هذا الخرج ما يزال غير عملي وبإمكاننا استخدام بايثون للحصول ما‬
‫ً‬
‫نريد بالضبط إال أننا سنحتاج للحديث عن الصفوف )‪ (tuples‬أوال وسنعود بعدها إلى هذا املثال‪.‬‬
‫‪ 5.9‬التنقيح‬
‫مع زيادة حجم البيانات يصبح من الصعب التنقيح عبر طباعة الخرج والتحقق من البيانات ً‬
‫يدويا لذا‬
‫َ‬
‫هاك بعض املقترحات لحل هذا‪:‬‬
‫‪ .1‬تقليل حجم الدخل‪ :‬إن أمكن‪ ،‬فعلى سبيل املثال إذا كان البرنامج يقرأ ملف نص ي فابدأ‬
‫بأول عشرة أسطر أو بأصغر مثال يمكنك إيجاده حيث تستطيع التعديل على امللفات‬
‫ً‬
‫مباشرة أو تعديل البرنامج ليقرأ أول عدد ما من السطور وهذا محبذ أكثر‪ ،‬وفي حال وجود‬
‫ً‬
‫تدريجيا مع‬
‫خطأ فيمكنك تقليل عدد األسطر إلى عدد أقل حتى يظهر الخطأ ثم قم بزيادته‬
‫تصحيح األخطاء‪.‬‬
‫ً‬
‫‪ .2‬تفقد موجزالبيانات و أنواعها‪ :‬اطبع موجز عن البيانات بدال من طباعتها وتفقدها‬
‫بأكملها‪ .‬مثل عدد عناصر قاموس ما أو مجموع قيم قائمة من األرقام‪ .‬و ً‬
‫أيضا السبب األكثر‬
‫ً‬
‫شيوعا لألخطاء أثناء التشغيل (‪ )runtime errors‬هو وجود قيمة معينة من نوع خاطئ‪،‬‬
‫ً‬
‫ويكفي عادة طباعة نوع هذه القيمة لتنقيح هذا النوع من األخطاء‪.‬‬
‫‪ .3‬اكتب حاالت اختبار‪ً :‬‬
‫ً‬
‫تلقائيا‪ ،‬كحالة حساب‬
‫أحيانا يمكنك أن تكتب برنامج لتفقد األخطاء‬
‫متوسط قيم قائمة ما‪ ،‬حيث يمكن التحقق ما إذا كان الناتج أصغر من أعظم قيمة فيها أو‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪153‬‬
‫أكبر من أصغر قيمة ويدعى هذا باالختبار املنطقي فهو يكشف األخطاء غير املنطقية على‬
‫اإلطالق‪ ،‬كما يوجد اختبار آخر يسمى باختبار االتساق أي يقارن بين ناتجي عمليتين‬
‫حسابيتين للتأكد من توافقهما‪.‬‬
‫‪ .4‬اطبع الخرج‪ :‬إن طباعة خرج عملية التنقيح يسهل كشف األخطاء‪.‬‬
‫وللتذكير فإن الوقت الذي تقضيه في كتابة وبناء أساس البرنامج بشكل صحيح يقلل الوقت الذي‬
‫تقضيه في التنقيح‪.‬‬
‫‪ 6.9‬فهرس املصطلحات‬
‫• القاموس (‪ :)dictionary‬يربط بين مجموعة من املفاتيح مع القيم املقابلة لها‪.‬‬
‫• خوارزمية الهاش (‪ :)hashtable‬خوارزمية مستخدمة في القواميس ضمن بايثون‪.‬‬
‫• تابع هاش (‪ :)hash function‬تابع تستخدمه الخوارزمية ‪ hashtable‬لتحديد موقع مفتاح‬
‫ما‪.‬‬
‫• الهيستوغرام (‪ :)histogram‬لتمثيل التكرارات أو التعدادات‪.‬‬
‫• عملية التنفيذ )‪ :(implementation‬طريقة تنفيذ عملية حسابية ما‪.‬‬
‫• عنصر )‪ :(item‬اسم آخر لزوج املفتاح‪-‬قيمة‪.‬‬
‫• مفتاح )‪ :(key‬كائن يظهر في القاموس كأول جزء من زوج املفتاح‪-‬قيمة‪.‬‬
‫• زوج مفتاح‪-‬قيمة )‪ :(key-value pair‬تمثيل العالقة بين املفتاح والقيمة املوافقة في‬
‫قاموس ما‪.‬‬
‫• البحث في القاموس )‪ :(lookup‬عملية تنفذ في القواميس إليجاد القيمة املوافقة ملفتاح ما‪.‬‬
‫• الحلقات املتداخلة )‪ :(nested loops‬وهذا عند وجود حلقة أو أكثر ضمن حلقة أخرى‬
‫حيث تنهي الحلقة الداخلية تنفيذ جميع دوراتها من أجل كل دورة للحلقة الخارجية‪.‬‬
‫• قيمة )‪ :(value‬غرض في القاموس يمثل الجزء الثاني من الزوج مفتاح‪-‬قيمة وهي تختلف‬
‫هنا عن االستعماالت السابقة لكلمة ‪.value‬‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪154‬‬
‫‪ 7.9‬تمارين‪:‬‬
‫ً‬
‫برنامجا يصنف رسائل البريد االلكتروني بحسب يوم إرسالها‪ .‬ولتنفيذ‬
‫• التمرين الثاني‪ :‬اكتب‬
‫هذا‪ ،‬ابحث عن األسطر التي تبدأ بكلمة ‪ From‬ثم ابحث عن الكلمة الثالثة وأنش ئ عداد تكرار‬
‫أليام اإلرسال ثم اطبع محتوى قاموسك (الترتيب غير مهم)‪.‬‬
‫مثال‪:‬‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫مثال عن الخرج‪:‬‬
‫‪python dow.py‬‬
‫‪Enter a file name: mbox-short.txt‬‬
‫}‪{'Fri': 20, 'Thu': 6, 'Sat': 1‬‬
‫ً‬
‫برنامجا لقراءة سجل بريد إلكتروني معين وأنش ئ هيستوغرام‬
‫• التمرين الثالث‪ :‬اكتب‬
‫باستخدام القواميس لتبيان عدد الرسائل الواصلة له من كل إيميل ثم اطبع عناصر‬
‫القاموس‪.‬‬
‫‪Enter file name: mbox-short.txt‬‬
‫‪{'gopal.ramasammycook@gmail.com': 1, 'louis@media.berkeley.edu': 3,‬‬
‫‪'cwen@iupui.edu': 5, 'antranig@caret.cam.ac.uk': 1, 'rjlowe@iupui.edu': 2,‬‬
‫‪'gsilver@umich.edu': 3, 'david.horwitz@uct.ac.za': 4, 'wagnermr@iupui.edu': 1,‬‬
‫}‪'zqian@umich.edu': 4, 'stephen.marquard@uct.ac.za': 2, 'ray@media.berkeley.edu': 1‬‬
‫• التمرين الرابع‪ :‬أضف بعض التعليمات لبرنامجك السابق إليجاد الشخص الذي أرسل أكبر‬
‫عدد من الرسائل اإللكترونية‪ ،‬أي ابحث في القاموس عن القيمة العظمى باستخدام‬
‫الحلقات بعد قراءة البيانات وإنشاء القاموس (راجع الفصل الخامس‪ :‬حلقات القيم العظمى‬
‫والصغرى)‪ ،‬ثم اطبع عنوان البريد املطلوب مع عدد الرسائل التي أرسلت منه‪.‬‬
‫‪Enter a file name: mbox-short.txt‬‬
‫‪cwen@iupui.edu 5‬‬
‫‪Enter a file name: mbox.txt‬‬
‫الفصل التاسع‪ :‬القواميس‬
‫‪155‬‬
‫‪zqian@umich.edu 195‬‬
‫ً‬
‫ً‬
‫برنامجا يسجل اسم النطاق (‪ )domain‬فقط بدال من العنوان‬
‫• التمرين الخامس‪ :‬اكتب‬
‫الكامل للبريد اإللكتروني‪ .‬أي‪ ،‬من أين أرسلت الرسالة‪ ،‬ال من أرسلها‪ ،‬مع عدد مرات تكرارها‬
‫ثم اطبع عناصر القاموس‪.‬‬
‫‪python schoolcount.py‬‬
‫‪Enter a file name: mbox-short.txt‬‬
‫‪{'media.berkeley.edu': 4, 'uct.ac.za': 6, 'umich.edu': 7, 'gmail.com': 1, 'caret.cam.ac.uk': 1,‬‬
‫‪'iupui.edu': 8‬‬
‫الفصل العاشر‬
‫الصفوف‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪157‬‬
‫‪ 10‬الصفوف‬
‫‪ 1.10‬الصفوف غيرقابلة للتعديل‬
‫الصفوف عبارة عن سالسل من القيم‪ ،‬وكما هو الحال مع القوائم‪ ،‬يمكن أن نخزن في الصفوف قيم‬
‫من كافة األنواع‪ ،‬كما أن هذه القيم تفهرس باستخدام األعداد الصحيحة‪ ،‬ويكمن االختالف املهم‬
‫الذي تمتاز به الصفوف في كونها غير قابلة للتعديل‪ .‬كما أن الصفوف قابلة للمقارنة‪ ،‬ويمكن تطبيق‬
‫خوارزمية الهاش (‪ )Hash‬عليها‪ ،‬مما يسمح بترتيب قائمة من الصفوف أو استخدام الصفوف‬
‫كمفاتيح في قواميس بايثون‪.‬‬
‫عند كتابة صف نجد أنه عبارة عن قائمة تتكون من سلسلة قيم يتخللها فواصل‪:‬‬
‫'‪>>> t = 'a', 'b', 'c', 'd', 'e‬‬
‫وعلى الرغم من عدم الحاجة لوضع الصف بين قوسين يشيع ذلك لتسهيل عملية تمييز الصفوف في‬
‫البرنامج‪:‬‬
‫)'‪>>> t = ('a', 'b', 'c', 'd', 'e‬‬
‫وعند إنشاء صف مكون من عنصر واحد يجب أن تضيف فاصلة إلى نهاية هذا الصف‪:‬‬
‫) ‪>>> t1 = ('a' ,‬‬
‫)‪>>> type(t1‬‬
‫>'‪<type 'tuple‬‬
‫وفي حال عدم إضافة هذه الفاصلة سيعامل الصف على أنه سلسلة نصية‪:‬‬
‫)'‪>>> t2 = ('a‬‬
‫)‪>>> type(t2‬‬
‫>'‪<type 'str‬‬
‫ويمكن إنشاء صف باستخدام التابع الجاهز‪ ،tuple‬وبدون استخدام أي وسائط سنحصل على صف‬
‫فارغ‪:‬‬
‫)(‪>>> t = tuple‬‬
‫)‪>>> print(t‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪158‬‬
‫)(‬
‫وفي حال كون الوسيط املستخدم مع التابع سلسلة من نوع ما (سلسلة نصية أو قائمة أو صف) فإن‬
‫النتيجة ستكون ً‬
‫صفا من عناصر هذه السلسلة‪:‬‬
‫)'‪>>> t = tuple('lupins‬‬
‫)‪>>> print(t‬‬
‫)'‪('l', 'u', 'p', 'i', 'n', 's‬‬
‫ً‬
‫محجوزا كتابع جاهز إلنشاء‬
‫ينبغي تجنب استخدام كلمة ‪ tuple‬كاسم للمتغيرات‪ ،‬وذلك باعتباره‬
‫الصفوف‪.‬‬
‫تعمل غالبية عوامل القوائم على الصفوف‪ .‬على سبيل املثال‪ ،‬فإن عامل القوس القائم يستدعي‬
‫العناصر في الصف كما هو الحال مع القوائم‪:‬‬
‫)'‪>>> t = ('a', 'b', 'c', 'd', 'e‬‬
‫)]‪>>> print(t[0‬‬
‫'‪'a‬‬
‫ً‬
‫نطاقا من العناصر ً‬
‫أيضا‪:‬‬
‫و يحدد عامل التجزئة‬
‫)]‪>>> print(t[1:3‬‬
‫)'‪('b', 'c‬‬
‫ولكن إذا حاولت أن تعدل قيمة أحد العناصر في الصف فستحصل على رسالة خطأ‪:‬‬
‫'‪>>> t[0] = 'A‬‬
‫‪TypeError: object doesn't support item assignment‬‬
‫ً‬
‫ً‬
‫عنصرا بآخر‪:‬‬
‫عوضا عن ذلك يمكن أن تغير‬
‫]‪>>> t = ('A',) + t[1:‬‬
‫)‪>>> print(t‬‬
‫)'‪('A', 'b', 'c', 'd', 'e‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪159‬‬
‫‪ 2.10‬مقارنة الصفوف‬
‫يعمل عامل املقارنة مع الصفوف وغيرها من السالسل‪ ،‬حيث تبدأ املقارنة بالعنصر األول من كل‬
‫سلسلة‪ ،‬وفي حال تكافأ الطرفان فتنتقل املقارنة إلى العنصر التالي‪ ،‬وهكذا حتى العثور على عنصرين‬
‫مختلفين‪ .‬العناصر التي تتلو نقطة االختالف ال تؤخذ بعين االعتبار (حتى لو كانت كبيرة ً‬
‫جدا)‪:‬‬
‫)‪>>> (0, 1, 2) < (0, 3, 4‬‬
‫‪True‬‬
‫)‪>>> (0, 1, 2000000) < (0, 3, 4‬‬
‫‪True‬‬
‫يعمل التابع ‪ sort‬بنفس الطريقة السابقة‪ ،‬فيبدأ بالعنصر األول وفي حال التكافؤ ٌيرتب وفق العنصر‬
‫الثاني وهكذا‪.‬‬
‫ٌ‬
‫ً‬
‫اختصارا ‪)DSU‬‬
‫تستخدم هذه امليزة ضمن نمط العمليات املسمى (‪ Decorate, Sort, Undecorate‬أو‬
‫الذي يتألف من الخطوات الثالثة السابقة الذكر‪:‬‬
‫‪َ -1‬ميز (‪ )Decorate‬قيم سلسلة ما بإنشاء قائمة من الصفوف تحوي عنصر ترتيب واحد‬
‫عالمة التمييز‪ -‬أو أكثر يليه عنصر من السلسلة‪.‬‬‫‪ -2‬رتب (‪ )Sort‬الصفوف باستخدام التابع ‪.sort‬‬
‫‪ -3‬إ الة التمييز )‪ (Undecorate‬وذلك باستخراج عناصر السلسلة التي ٌرتبت ً‬
‫سابقا‪.‬‬
‫ز‬
‫ً‬
‫فلنفترض مثال حاجتنا لترتيب قائمة من الكلمات من الكلمة األطول إلى األقصر‪ ،‬فنكتب البرنامج‬
‫التالي‪:‬‬
‫'‪txt = 'but soft what light in yonder window breaks‬‬
‫)(‪words = txt.split‬‬
‫)(‪t = list‬‬
‫‪for word in words:‬‬
‫))‪t.append((len(word), word‬‬
‫)‪t.sort(reverse=True‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪160‬‬
‫)(‪res = list‬‬
‫‪for length, word in t:‬‬
‫)‪res.append(word‬‬
‫)‪print(res‬‬
‫‪# Code: http://www.py4e.com/code3/soft.py‬‬
‫مسبوقة بعدد أحرفها‪.‬‬
‫تنش ئ الحلقة األولى قائمة من الصفوف‪ ،‬بحيث يتكون كل صف من كلمة‬
‫ٍ‬
‫يقارن تابع الترتيب ‪ sort‬العنصر األول ‪-‬طول الكلمة‪ -‬وال يأخذ العنصر الثاني بعين االعتبار إال لحسم‬
‫التكافؤات‪ .‬نستخدم الوسيط )‪ (reverse=True‬لجعل التابع يرتب القيم تناز ًليا‪.‬‬
‫تمر الحلقة الثانية على قائمة الصفوف وتنش ئ قائمة من الكلمات تناز ًليا حسب طولها والكلمتين‬
‫املكونتين من أربعة أحرف تم ترتيبهما تناز ًليا حسب الحرف األول‪ ،‬ولذلك تظهر الكلمة ”‪ “what‬قبل‬
‫الكلمة ”‪ “soft‬في القائمة املرتبة‪ ،‬ويكون خرج البرنامج كالتالي‪:‬‬
‫]'‪['yonder', 'window', 'breaks', 'light', 'what', 'soft', 'but', 'in‬‬
‫‪ 3.10‬إسناد الصفوف‬
‫تعتبر إمكانية استخدام تعليمة إسناد متغيرها عبارة عن صف من امليزات الفريدة في بايثون‪ ،‬حيث‬
‫أنها تسمح بإسناد قيم ألكثر من متغير ً‬
‫معا‪ ،‬عندما تكون القيم عبارة عن سلسلة‪.‬‬
‫نرى في املثال التالي قائمة من عنصرين (سلسلة) نقوم بإسنادهما إلى املتغيرين ‪ x‬و‪ y‬بتعليمة واحدة‪.‬‬
‫] '‪>>> m = [ 'have', 'fun‬‬
‫‪>>> x, y = m‬‬
‫‪>>> x‬‬
‫'‪'have‬‬
‫‪>>> y‬‬
‫'‪'fun‬‬
‫تعامل لغة بايثون تعليمة اإلسناد السابقة ً‬
‫تقريبا كما يلي‪:‬‬
‫] '‪>>> m = [ 'have', 'fun‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪161‬‬
‫]‪>>> x = m[0‬‬
‫]‪>>> y = m[1‬‬
‫‪>>> x‬‬
‫'‪'have‬‬
‫‪>>> y‬‬
‫'‪'fun‬‬
‫ً‬
‫ً‬
‫حرفيا‪ ،‬ففي حال استخدمنا قاموس بدال عن‬
‫تجدر اإلشارة إلى أن لغة بايثون ال تترجم التعليمات‬
‫القائمة في املثال السابق فلن يتم تنفيذ البرنامج ‪-‬كما قد نتوقع‪.-‬‬
‫ً‬
‫عادة عندما نكتب تعليمة إسناد طرفها اليساري عبارة عن صف‪ ،‬فإننا نهمل األقواس‪ ،‬ولكن في حال‬
‫لم نفعل فإن ذلك مقبول وصحيح‪:‬‬
‫] '‪>>> m = [ 'have', 'fun‬‬
‫‪>>> (x, y) = m‬‬
‫‪>>> x‬‬
‫'‪'have‬‬
‫‪>>> y‬‬
‫'‪'fun‬‬
‫ومن التطبيقات العملية لهذه امليزة هو القدرة على تبديل قيم متغيرين فيما بينهما‪:‬‬
‫‪>>> a, b = b, a‬‬
‫هنا كل من طرفي التعليمة عبارة عن صف‪ ،‬القسم األيسر صف متغيرات‪ ،‬بينما القسم األيمن صف‬
‫ُ‬
‫من التعابير‪ .‬كل قيمة من الطرف األيمن تسند إلى املتغير املقابل لها من الطرف األيسر‪ .‬يتم حساب‬
‫كل التعابير في الطرف األيمن قبل أي اسناد‪.‬‬
‫ً‬
‫مساويا لعدد القيم في الطرف األيمن‪ ،‬وفي حال عدم‬
‫يجب أن يكون عدد املتغيرات في الطرف األيسر‬
‫تساوي الطرفين نحصل على رسالة خطأ‪:‬‬
‫‪>>> a, b = 1, 2, 3‬‬
‫‪ValueError: too many values to unpack‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪162‬‬
‫ويمكننا تعميم ذلك حيث أن الطرف األيمن يمكن أن يكون أي نوع من السالسل (نص أو قائمة أو‬
‫ً‬
‫صف)‪ .‬يمكننا مثال أن نقسم عنوان البريد اإللكتروني إلى قسمين ونسند كل قسم إلى متغير‪:‬‬
‫'‪>>> addr = 'monty@python.org‬‬
‫)'@'(‪>>> uname, domain = addr.split‬‬
‫تعطينا تعليمة التقسيم ‪ً split‬‬
‫خرجا على شكل قائمة بعنصرين‪ ،‬األول يسند إلى املتغير‪uname‬‬
‫والثاني إلى املتغير ‪:domain‬‬
‫)‪>>> print(uname‬‬
‫‪monty‬‬
‫)‪>>> print(domain‬‬
‫‪python.org‬‬
‫‪ 4.10‬القواميس والصفوف‬
‫ُيستخدم التابع ‪ items‬مع القواميس‪ ،‬ويعيد قائمة من الصفوف‪ ،‬كل صف عبارة عن زوج من مفتاح‬
‫وقيمة‪:‬‬‫}‪>>> d = {'a':10, 'b':1, 'c':22‬‬
‫))(‪>>> t = list(d.items‬‬
‫)‪>>> print(t‬‬
‫])‪[('b', 1), ('a', 10), ('c', 22‬‬
‫وبطبيعة الحال فإن قيم القاموس غير مرتبة‪ ،‬ولكن بما أننا حصلنا على قائمة من الصفوف وبما أن‬
‫الصفوف يمكن مقارنتها فيمكن أن نرتب هذه القائمة‪ .‬إن تحويل القاموس إلى قائمة من الصفوف‬
‫هي طريقة تسمح لنا بالحصول على محتويات القاموس مرتبة بطريقة ما‪:‬‬
‫}‪>>> d = {'a':10, 'b':1, 'c':22‬‬
‫))(‪>>> t = list(d.items‬‬
‫‪>>> t‬‬
‫])‪[('b', 1), ('a', 10), ('c', 22‬‬
‫)(‪>>> t.sort‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪163‬‬
‫‪>>> t‬‬
‫])‪[('a', 10), ('b', 1), ('c', 22‬‬
‫ً‬
‫وينتج لدينا قائمة مرتبة ً‬
‫أبجديا حسب قيمة املفتاح‪.‬‬
‫ترتيبا‬
‫‪ 5.10‬اإلسناد املتعدد مع القواميس‬
‫عند استخدام كل من التابع ‪ items‬وعملية اإلسناد للصفوف وحلقة ‪ ،for‬يمكن أن نحصل على‬
‫شيفرة نموذجية تستخدم للمرور على القيم واملفاتيح لقاموس باستخدام حلقة واحدة‪:‬‬
‫‪for key, val in list(d.items()):‬‬
‫)‪print(val, key‬‬
‫تحوي هذه الحلقة متغيري تكرار‪ ،‬ألن التابع ‪ items‬تعيد قائمة من الصفوف‪ ،‬واملتغيرين ‪ key‬و‪val‬‬
‫يشكالن تعليمة إسناد لصف يتكرر تنفيذ الحلقة عليه لكل زوج (مفتاح‪ ،‬قيمة) في القاموس‪ ،‬فينتقل‬
‫املتغيران في كل تكرار للحلقة إلى القيمتين التاليتين في القاموس‪ ،‬ويكون خرج الحلقة كالتالي‪:‬‬
‫‪10 a‬‬
‫‪22 c‬‬
‫‪1b‬‬
‫في حال دمجنا األسلوبين السابقين يمكن أن نحصل على محتويات القاموس مرتبة وفق القيمة‬
‫لألزواج (مفتاح‪ ،‬قيمة)‪.‬‬
‫ً‬
‫للقيام بهذه العملية يجب علينا أوال إنشاء قائمة مكونة من صفوف‪ ،‬يتكون كل صف منها من زوج‬
‫ً‬
‫(قيمة‪ ،‬مفتاح) ‪-‬بدال من (مفتاح‪ ،‬قيمة)‪ ،-‬حيث يعطينا التابع ‪ items‬قائمة من الصفوف كل منها‬
‫مكون من (مفتاح‪ ،‬قيمة) موافقة له‪ ،‬ولكننا نريد في هذا املثال أن نرتب القاموس حسب القيم وليس‬
‫حسب املفاتيح‪.‬‬
‫بمجرد حصولنا على قائمة مكونة من صفوف يحوي كل منها (قيمة‪ ،‬مفتاح)‪ ،‬يسهل علينا ترتيب هذه‬
‫ً‬
‫قاموسا بالترتيب املطلوب‪.‬‬
‫القائمة‪ ،‬ومن ثم ننش ئ منها‬
‫}‪>>> d = {'a':10, 'b':1, 'c':22‬‬
‫)(‪>>> l = list‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪164‬‬
‫‪>>> for key, val in d.items() :‬‬
‫) )‪... l.append( (val, key‬‬
‫‪...‬‬
‫‪>>> l‬‬
‫])'‪[(10, 'a'), (22, 'c'), (1, 'b‬‬
‫)‪>>> l.sort(reverse=True‬‬
‫‪>>> l‬‬
‫])'‪[(22, 'c'), (10, 'a'), (1, 'b‬‬
‫>>>‬
‫بترو‪ ،‬بحيث تكون القيمة في بداية كل صف من‬
‫نستطيع من خالل إنشاء قائمة الصفوف هذه ٍ‬
‫صفوفها‪ ،‬أن نرتب هذه القائمة‪ ،‬ومن ثم يمكن أن ننش ئ منها القاموس املطلوب‪.‬‬
‫‪ 6.10‬الكلمات األكثرتكر ًارا‬
‫بالعودة إلى التمرين السابق‪ ،‬الذي طبقناه على نص املشهد الثاني من الفصل الثاني من مسرحية‬
‫ً‬
‫برنامجا يستخدم الطريقة التالية‪ ،‬للحصول الكلمات العشر األكثر‬
‫روميو وجولييت‪ ،‬يمكن أن نكتب‬
‫تكر ًارا في النص‪:‬‬
‫‪import string‬‬
‫)'‪fhand = open('romeo-full.txt‬‬
‫)(‪counts = dict‬‬
‫‪for line in fhand:‬‬
‫))‪line = line.translate(str.maketrans(' ', ' ', string.punctuation‬‬
‫)(‪line = line.lower‬‬
‫)(‪words = line.split‬‬
‫‪for word in words:‬‬
‫‪if word not in counts:‬‬
‫‪counts[word] = 1‬‬
‫‪else:‬‬
‫‪counts[word] += 1‬‬
‫‪# Sort the dictionary by value‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪165‬‬
‫)(‪lst = list‬‬
‫‪for key, val in list(counts.items()):‬‬
‫))‪lst.append((val, key‬‬
‫)‪lst.sort(reverse=True‬‬
‫‪for key, val in lst[:10]:‬‬
‫)‪print(key, val‬‬
‫‪# Code: http://www.py4e.com/code3/count3.py‬‬
‫بقي القسم األول من البرنامج على حاله (القسم الذي يقرأ امللف النص ي وينش ئ القاموس الذي‬
‫يحص ي عدد الكلمات املوجودة فيه)‪ ،‬ولكن ً‬
‫عوضا عن طباعة أعداد الكلمات وإنهاء البرنامج ببساطة‪،‬‬
‫فسننش ئ قائمة من الصفوف لألزواج (قيمة‪ ،‬مفتاح) ثم سنرتب هذه القيم ً‬
‫ترتيبا تناز ًليا‪.‬‬
‫ً‬
‫بما أن القيم مذكورة أوال في الصفوف‪ ،‬سنستخدمها عند املقارنة‪ ،‬وعند وجود أكثر من صف بنفس‬
‫القيمة سيؤخذ العنصر الثاني (املفتاح) بعين االعتبار‪ ،‬ولذلك فإن الصفوف التي تبدأ بقيم متماثلة‬
‫ً‬
‫أبجديا حسب املفتاح‪.‬‬
‫سترتب‬
‫في نهاية البرنامج سنكتب حلقة ‪ for‬تقوم بعملية إسناد متعدد مع تكرار‪ ،‬لتقوم بطباعة الكلمات‬
‫العشر األكثر تكر ًارا عن طريق اجتزاء القائمة األساسية باستخدام األمر ]‪ ،lst [:10‬وستظهر الكلمات‬
‫األكثر ً‬
‫تكررا حسب التحليل الذي أجريناه‪:‬‬
‫‪61 i‬‬
‫‪42 and‬‬
‫‪40 romeo‬‬
‫‪34 to‬‬
‫‪34 the‬‬
‫‪32 thou‬‬
‫‪32 juliet‬‬
‫‪30 that‬‬
‫‪29 my‬‬
‫‪24 thee‬‬
‫ً‬
‫يوضح املثال السابق ً‬
‫جليا لم ُتعد بايثون ً‬
‫مناسبا كلغة برمجة مستخدمة الكتشاف املعلومات‬
‫خيارا‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪166‬‬
‫حيث استطعنا اجراء تحليل لبيانات معقدة عبر كتابة برنامج بسيط من ‪ً 19‬‬
‫سطرا‪.‬‬
‫‪ 7.10‬استخدام الصفوف كمفاتيح ضمن القواميس‬
‫تتميز الصفوف بإمكانية تطبيق خوارزمية الـهاش (‪ )Hash‬عليها على عكس القوائم‪ ،‬ولذلك فإنها الحل‬
‫املثالي عند الرغبة في إنشاء قاموس بمفاتيح مركبة‪.‬‬
‫سنتعامل مع املفاتيح املركبة في حال الرغبة في إنشاء دليل هاتف يستخدم االسم والكنية كمفتاح‬
‫ورقم الهاتف كقيمة‪ ،‬وإذا أردنا أن نكتب تعليمة إسناد إلنشاء قاموس‪ ،‬فيمكننا أن نستخدم‬
‫املتغيرين )‪ (first, last‬كمفتاح واملتغير ‪ number‬كقيمة‪ ،‬كما في التالي‪:‬‬
‫‪directory[last,first] = number‬‬
‫يمثل التعبير املكتوب بين األقواس القائمة ً‬
‫صفا‪ ،‬كما يمكن أن نستخدم تعليمة إسناد لصف ضمن‬
‫حلقة ‪ for‬لتبديل االسم بموضع الكنية والعكس في هذا القاموس‪:‬‬
‫‪for last, first in directory:‬‬
‫)]‪print (first, last, directory[last,first‬‬
‫تمر هذه الحلقة على املفاتيح (والتي هي عبارة عن صفوف) في القاموس‪ ،‬حيث أنها تسند عناصر كل‬
‫صف إلى املتغيرين ‪ last‬و‪ first‬ثم تطبع االسم ورقم الهاتف املقابل له‪.‬‬
‫‪ 8.10‬السالسل‪ :‬النصوص والقوائم والصفوف‬
‫ركزنا في هذا الفصل على استخدام قوائم من الصفوف‪ ،‬ولكن كل األمثلة التي طرحناها ً‬
‫تقريبا قابلة‬
‫ً‬
‫وتجنبا لتكرار وتعداد‬
‫للتطبيق على قوائم من القوائم‪ ،‬وصفوف من الصفوف‪ ،‬وصفوف من القوائم‪،‬‬
‫ً‬
‫كل التركيبات املمكنة‪ ،‬فسنشير إليها بسالسل من السالسل تبسيطا‪.‬‬
‫يمكن استخدام السالسل املختلفة (السالسل النصية والقوائم والصفوف) بشكل متبادل في غالب‬
‫ً‬
‫األحيان‪ ،‬ولذلك يطرح السؤال التالي‪ :‬كيف نختار أحد أنواع هذه السالسل بدال من البقية وملاذا؟‬
‫ً‬
‫ً‬
‫نالحظ بداية أن السالسل النصية أكثر السالسل محدودية ألن عناصرها يجب أن تكون محارفا‬
‫ً‬
‫فقط‪ ،‬كما أنها غير قابلة للتعديل فإذا أردت أن تعدل املحارف املوجودة في نص ما (بدال عن انشاء‬
‫نص جديد)‪ ،‬فيفضل أن تستخدم قائمة من املحارف ً‬
‫عوضا عن سلسلة نصية‪.‬‬
‫تستخدم القوائم بشكل أكثر شيوعا من الصفوف‪ ،‬ويعود ذلك بشكل أساس ي إلى كونها قابلة‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪167‬‬
‫للتعديل‪ ،‬ولكن هناك بعض الحاالت التي قد يكون استخدام الصفوف أفضل فيها‪:‬‬
‫ً ً‬
‫صفا بدال‬
‫‪ -1‬من األبسط في بعض الحاالت كما هو الحال مع تعليمة ‪ ،return‬أن ننش ئ‬
‫ُ‬
‫عن قائمة‪ ،‬ولكن هذا غير مطلق‪ ،‬فقد تفضل القائمة في بعض الحاالت‪.‬‬
‫ً‬
‫ً‬
‫قابل للتعديل‬
‫‪ -2‬إذا رغبت أن تستخدم تسلسال كمفتاح في قاموس‪ ،‬فستحتاج نوعا غير ٍ‬
‫كالسالسل النصية أو الصفوف‪.‬‬
‫‪ -3‬في حال كنت تستخدم سلسلة ما كوسيط لتابع ما‪ ،‬فإن استخدام الصفوف يقلل‬
‫احتمالية السلوك غير املتوقع بسبب مشكلة التسمية البديلة (‪ .)aliasing‬لن تستطيع‬
‫استخدام التوابع ‪ sort‬و‪ reverse‬مع الصفوف كونها غير قابلة للتعديل‪ ،‬وهذه التوابع‬
‫تستخدم لتعديل القوائم املوجودة مسب ًقا‪ ،‬لكن حال الرغبة بالحصول على نتائج هذه‬
‫ً‬
‫التوابع‪ ،‬فإن لغة بايثون توفر ً‬
‫توابعا جاهزة بديلة كالتابعين ‪ sorted‬و‪ reversed‬الذين‬
‫يأخذان أي سلسلة ُ‬
‫كمدخل‪ ،‬ويعيدان سلسلة جديدة بنفس العناصر ولكن بترتيب‬
‫آخر‪.‬‬
‫‪ 9.10‬التنقيح‬
‫ُيطلق اسم بنى البيانات (‪ )data structures‬على كل من القوائم والقواميس والصفوف بشكل عام‪،‬‬
‫ً‬
‫ً‬
‫وقوائما‬
‫وقد تناولنا بعض البنى املركبة كقوائم من الصفوف‪ ،‬والقواميس التي تحوي صفوفا كمفاتيح‬
‫كقيم‪ .‬تعد هذه البنى مفيدة في االستخدام‪ ،‬ولكنها عرضة ملا يسمى بأخطاء الشكل )‪،(shape errors‬‬
‫وهي األخطاء التي تحدث عندما تكون بنية البيانات املستخدمة ذات نوع أو حجم أو كالهما غير‬
‫مناسب؛ أو حتى من املمكن أن تحدث هذه األخطاء عند كتابة شيفرة ما ونسيانك لنوع البيانات التي‬
‫استخدمتها‪ .‬وكمثال عن ذلك‪ ،‬ففي حال كان لدينا برنامج يتوقع أن تكون البيانات املدخلة له عبارة‬
‫عن قائمة مكونة من رقم وحيد‪ ،‬وقمنا بتزويده برقم (غير محتوى ضمن قائمة) فسنحصل على هذا‬
‫النوع من األخطاء‪.‬‬
‫‪ 10.10‬فهرس املصطلحات‬
‫• قابل للمقارنة )‪ :(comparable‬نوع بيانات يمكن أن يحوي على مجموعة قيم نستطيع أن‬
‫نفحص فيما إذا كانت أكبر أو أصغر أو تساوي قيم أخرى ضمن نفس النوع‪ ،‬يمكن أن توضع‬
‫األنواع القابلة للمقارنة في قائمة ثم يتم ترتيبها بشكل ما‪.‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪168‬‬
‫• بنى البيانات (‪ :)data structure‬وهي مجموعة من القيم التي يتم ترتيبها عادة في قوائم أو‬
‫قواميس أو صفوف أو غيرها‪.‬‬
‫ً‬
‫اختصارا للتعبير(‪:)Decorate, Sort, Undecorate‬‬
‫• النمط ّميز‪ ،‬رتب‪ِّ ،‬أزل التمييز (‪)DSU‬‬
‫وهو نمط يستخدم لتشكيل قوائم من صفوف‪ ،‬ليتم ترتيبها واستخراج جزء من النتيجة التي‬
‫نحصل عليها‪.‬‬
‫• التجميع (‪ :)gather‬وهي العملية التي يتم فيها تجميع وسيط مكون من صف ذو طول متغير‪.‬‬
‫• خاضع لخوارزمية الهاش (‪ :)hashable‬أي نوع بيانات يمكن تنفيذ تابع الهاش (‪)hash‬‬
‫عليه‪ ،‬األنواع غير القابلة للتعديل مثل )‪ (float, integers, string‬تقبل هذا التابع‪ ،‬أما البنى‬
‫القابلة للتعديل ال تقبله‪.‬‬
‫• التفريق (‪ :)scatter‬وهي العملية التي يتم فيها التعامل مع سلسلة من البيانات على أنها قائمة‬
‫من الوسائط‪.‬‬
‫• شكل بنية البيانات (‪ :)shape‬ملخص يصف نوع وحجم وتركيب بنية معطيات ما‪.‬‬
‫ً‬
‫ً‬
‫• ذو العنصر الوحيد )‪ :(singleton‬قائمة (أو سلسلة من نوع آخر) تحوي‬
‫واحدا‬
‫عنصرا‬
‫فقط‪.‬‬
‫• الصف (‪ :)tuple‬سلسلة من العناصر غير القابلة للتعديل‪.‬‬
‫• إسناد الصفوف (‪ :)tuple assignment‬وهي تعليمة إسناد لسلسلة من القيم موجودة في‬
‫ً‬
‫طرفها األيمن‪ ،‬وصف من املتغيرات في طرفها األيسر‪ ،‬يتم حساب الطرف األيمن أوال‪ ،‬ثم يتم‬
‫إسناد العناصر املوجودة فيه إلى املتغيرات املوجودة في الطرف األيسر‪.‬‬
‫‪ 11.10‬تمارين‬
‫ً‬
‫برنامجا يقوم بقراءة وتجزئة السطور التي‬
‫• التمرين األول‪ :‬راجع تمريننا السابق‪ ،‬واكتب‬
‫تبدأ بكلمة ‪ ،From‬ويستخرج العنوان من كل سطر‪ ،‬ثم يقوم بحساب عدد الرسائل‬
‫الواردة من كل شخص باستخدام القاموس‪.‬‬
‫بعد قراءة كل البيانات اعرض اسم الشخص ذو عدد الرسائل األكبر‪ ،‬عن طريق إنشاء قائمة‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪169‬‬
‫ً‬
‫صفوفا (لعدد الرسائل‪ ،‬وعنوان البريد) من القاموس الذي تم إنشاؤه ً‬
‫سابقا‪ ،‬ثم رتب‬
‫تتضمن‬
‫القيم من األكبر إلى األصغر‪ ،‬واعرض عنوان البريد الذي ورد منه أكبر عدد من الرسائل‪.‬‬
‫مثال‪:‬‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫‪Enter a file name: mbox-short.txt‬‬
‫‪cwen@iupui.edu 5‬‬
‫‪Enter a file name: mbox.txt‬‬
‫‪zqian@umich.edu 195‬‬
‫• التمرين الثاني‪ :‬يعد البرنامج الذي سنكتبه في هذا التمرين تكرار الساعات التي وصلت‬
‫فيها رسائل البريد االلكتروني‪ ،‬حيث سنستخرج ساعة ورود الرسالة من السطر املبدوء‬
‫بالكلمة ‪ ،From‬عن طريق العثور على النص الذي يرمز ساعة الوصول‪ ،‬ومن ثم تجزئته‬
‫باستخدام عامل النقطتين ‪ ، :‬بمجرد القيام بعد جميع ساعات وصول الرسائل‪ ،‬اعرض‬
‫تكرار كل ساعة في سطر كالتالي‪:‬‬
‫‪python timeofday.py‬‬
‫‪Enter a file name: mbox-short.txt‬‬
‫‪04 3‬‬
‫‪06 1‬‬
‫‪07 1‬‬
‫‪09 2‬‬
‫‪10 3‬‬
‫‪11 6‬‬
‫‪14 1‬‬
‫‪15 2‬‬
‫‪16 4‬‬
‫الفصل العاشر‪ :‬الصفوف‬
‫‪170‬‬
‫‪17 2‬‬
‫‪18 1‬‬
‫‪19 1‬‬
‫برنامجا يقرأ ً‬
‫ً‬
‫ملفا ً‬
‫نصيا ليعرض عدد تكرار األحرف فيه بترتيب‬
‫• التمرين الثالث‪ :‬اكتب‬
‫تنازلي‪ .‬يجب أن يحول البرنامج كل األحرف إلى حالة الحرف الصغير‪ ،‬وأن يعد األحرف‬
‫من ‪ a‬إلى ‪ z‬فقط (أال يعد أي ش يء أخر عدا األحرف كاملسافات وعالمات الترقيم)‪ ،‬بعد‬
‫ذلك استخدم ملفات نصية من عدة لغات ُ‬
‫كمدخل للبرنامج‪ ،‬وقارن تباين األحرف األكثر‬
‫تكر ًارا بين هذه اللغات وقارن النتائج التي توصلت إليها مع الجدول املوجود في الرابط‬
‫التالي‪:‬‬
‫‪https://wikipedia.org/wiki/Letter_frequencies‬‬
‫الفصل الحادي عشر‬
‫التعابير النمطية‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪172‬‬
‫‪ 11‬التعابيرالنمطية‬
‫حتى اآلن كنا نقرأ امللفات ونبحث عن األنماط ونقوم باستخراج بيانات مهمة بالنسبة لنا من األسطر‪،‬‬
‫حيث كنا نستخدم توابع السالسل النصية مثل ‪ split‬و‪ ،find‬ونستخدم القوائم وتجزئة السالسل‬
‫النصية الستخراج أجزاء من األسطر‪.‬‬
‫جدا‪ ،‬لذلك تتوفر في لغة بايثون مكتبة برمجية فعالة ً‬
‫مهمة البحث واالستخراج هذه شائعة ً‬
‫جدا‬
‫تسمى مكتبة التعابير النمطية (‪ )regular expressions‬والتي تتعامل مع العديد من هذه املهام برتابة‬
‫مطلقة‪ ،‬وإن السبب في عدم طرح التعابير النمطية ً‬
‫سابقا في الكتاب هو أنه بالرغم من أن هذه‬
‫ً‬
‫ً‬
‫التعابير فعالة لكن بنفس الوقت معقدة قليال والقواعد الخاصة بها تتطلب ممارسة لالعتياد عليها‪.‬‬
‫يمكن أن نقول عن التعابير النمطية أنها لغة برمجة خاصة بعمليات البحث والتحليل في السالسل‬
‫النصية‪.‬‬
‫ٌ‬
‫لقد نشرت كتب كاملة عن التعابير النمطية لذلك سنغطي في هذا الفصل أساسيات التعابير‬
‫النمطية فقط‪ ،‬وللمزيد من التفاصيل حول التعابير النمطية راجع الرابطين التاليين‪:‬‬
‫‪https://en.wikipedia.org/wiki/Regular_expression‬‬
‫‪https://docs.python.org/library/re.html‬‬
‫ُ‬
‫يجب أن تستدعى مكتبة التعبير النمطي ‪ re‬ضمن برنامجك قبل استخدامها‪ ،‬وأبسط استخدام لها‬
‫هو التابع )(‪ search‬والبرنامج التالي يوضح أحد استخداماته‪:‬‬
‫'‪# Search for lines that contain 'From‬‬
‫‪import re‬‬
‫)'‪hand = open ('mbox-short.txt‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫)‪if re.search('From:', line‬‬
‫)‪print(line‬‬
‫‪# Code: http://www.py4e.com/code3/re01.py‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪173‬‬
‫نفتح امللف‪ ،‬ثم نمر على كل السطور باستخدام حلقة ‪ for‬ثم نستخدم التعبير النمطي )(‪search‬‬
‫فقط لطباعة األسطر التي تحوي السلسلة النصية "‪."From‬‬
‫هذا البرنامج ال يظهر الفعالية الحقيقية للتعابير النمطية حيث كان بإمكاننا الحصول على نفس‬
‫النتائج بالسهولة ذاتها باستخدام التابع )(‪ ،line.find‬وتظهر الفعالية الحقيقية للتعابير النمطية‬
‫عندما يمكننا إضافة الرموز الخاصة بالتعابير النمطية للسلسلة النصية والتي تسمح لنا بالتحكم‬
‫بدقة أكبر باألسطر التي تطابق سلسلة نصية ما‪.‬‬
‫تسمح إضافة هذه الرموز الخاصة لتعبيرنا النمطي بالقيام بعمليات مطابقة واستخراج متقدمة‬
‫باستخدام عدد قليل من السطور البرمجية‪ ،‬فعلى سبيل املثال الرمز ^ يستخدم في التعبير النمطي‬
‫ملطابقة بداية السطر بحيث بإمكاننا تغيير البرنامج السابق ملطابقة األسطر بحيث "‪ "From‬في بداية‬
‫السطر فقط كما يلي‪:‬‬
‫'‪# Search for lines that start with 'From‬‬
‫‪import re‬‬
‫)'‪hand = open('mbox-short.txt‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫‪if re.search('^From:', line):‬‬
‫)‪print(line‬‬
‫‪# Code: http://www.py4e.com/code3/re02.py‬‬
‫هكذا نكون حصلنا فقط على األسطر التي تبدأ ب "‪ "From:‬وهذا مثال بسيط ً‬
‫جدا كان باإلمكان‬
‫تنفيذه باستخدام التابع )(‪. startswith‬‬
‫لكنه يهدف لتوضيح حقيقة بأن التعابير النمطية تستخدم رموز خاصة ملنحنا املزيد من التحكم‬
‫بعمليات املطابقة‪.‬‬
‫‪ 1.11‬مطابقة املحارف في التعابيرالنمطية‬
‫ً‬
‫استخداما‬
‫هناك عدد من الرموز الخاصة التي تسمح لنا ببناء تعابير نمطية أكثر فعالية ومن أكثرها‬
‫ً‬
‫وشيوعا هي النقطة ‪ .‬والتي تمثل أي محرف‪.‬‬
‫في املثال التالي التعبير النمطي ‪ F..m:‬سيطابق أي من السالسل النصية ‪ From‬أو ‪ Fxxm‬أو ‪ F12m‬أو‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪174‬‬
‫‪ F!@m‬حيث النقط في التعبير النمطي تطابق أي محرف‪.‬‬
‫‪# Search for lines that start with 'F', followed by‬‬
‫'‪# 2 characters, followed by 'm:‬‬
‫‪import re‬‬
‫)'‪hand = open('mbox-short.txt‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫‪if re.search('^F..m:', line):‬‬
‫)‪print(line‬‬
‫‪# Code: http://www.py4e.com/code3/re03.py‬‬
‫تزداد أهمية هذه امليزة عندما يمكننا اإلشارة إلمكانية تكرار املحرف ً‬
‫عددا من املرات باستخدام رمز‬
‫النجمة * أو رمز الزائد ‪ +‬في تعبيرك النمطي حيث تدعى الرموز * و ‪ +‬بـ ( ‪ (wildcard‬تعني هذه املحارف‬
‫ً‬
‫الخاصة أنه بدال من مطابقة محرف واحد في السلسلة النصية فإنها تطابق في حال الرمز * صفر‬
‫محرف أو أكثر من املحارف‪ ،‬أما في حال الرمز ‪ +‬تطابق محرف واحد أو أكثر‪.‬‬
‫يمكننا تضييق نطاق األسطر التي نطابقها باستخدام الرموز السابقة في املثال التالي‪:‬‬
‫‪# Search for lines that start with From and have an at sign‬‬
‫‪import re‬‬
‫)'‪hand = open('mbox-short.txt‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫‪if re.search('^From:.+@', line):‬‬
‫)‪print(line‬‬
‫‪# Code: http://www.py4e.com/code3/re04.py‬‬
‫السلسلة النصية @‪ ^From:.+‬ستطابق األسطر التي تبدأ بـ ‪ From:‬متبوعة بمحرف أو أكثر ‪ .+‬ثم‬
‫بإشارة @‬
‫لذلك هذا سوف يطابق السطر التالي‪:‬‬
‫‪From: stephen.marquard@uct.ac.za‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪175‬‬
‫يمكننا بهذه الحالة أن نقول أن الرمز‪ .+‬يطابق جميع املحارف بين النقطتين ‪ :‬وإشارة @‬
‫@‪From:.+‬‬
‫يمكن االعتبار أن الرمزين * و ‪ +‬رموز متعدية (أي أنها تطابق أكبر قدر ممكن من املحارف)‪ ،‬فعلى‬
‫سبيل املثال إن السلسلة النصية أدناه التي تتضمن عدة محارف @ لكن سيكمل الرمز‪ .+‬املطابقة‬
‫حتى محرف @ األخير‪.‬‬
‫‪From: stephen.marquard@uct.ac.za, csev@umich.edu, and cwen @iupui.edu‬‬
‫ً‬
‫لكن من املمكن توظيف رمز * أو ‪ +‬بحيث ال يكون‬
‫متعديا في املطابقة عبر إضافة رمز خاص في التعبير‬
‫النمطي‪ ،‬لذا راجع ملفات توثيق هذا املكتبة للحصول على معلومات عن إيقاف تشغيل السلوك‬
‫الطماع لتلك الرموز‪.‬‬
‫‪ 2.11‬استخراج البيانات باستخدام التعابيرالنمطية‬
‫إذا أردنا استخراج البيانات من سلسلة نصية في لغة بايثون فبإمكاننا استخدام التابع )(‪findall‬‬
‫الستخراج السالسل النصية الجزئية )‪ )substrings‬التي تطابق التعبير النمطي‪.‬‬
‫على سبيل املثال الستخراج أي سلسلة نصية قد تبدو كبريد االلكتروني من كل من األسطر التالية‪:‬‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫>‪Return-Path: <postmaster@collab.sakaiproject.org‬‬
‫;>‪for <source@collab.sakaiproject.org‬‬
‫)‪Received: (from apache@localhost‬‬
‫‪Author: stephen.marquard@uct.ac.za‬‬
‫لن نرغب بكتابة شيفرة تتضمن تعليمات تجزئة وتقطيع مختلفة للتعامل مع كل سطر على حدة‪ ،‬بل‬
‫نستخدم تابع )(‪ findall‬إليجاد األسطر التي تحوي عناوين البريد اإللكتروني واستخراج واحد أو أكثر‬
‫من العناوين في كل األسطر‪.‬‬
‫‪import re‬‬
‫'‪s = 'A message from csev@umich.edu to cwen@iupui.edu about meeting @2PM‬‬
‫)‪lst = re.findall('\S+@\S+', s‬‬
‫)‪print(lst‬‬
‫‪# Code: http://www.py4e.com/code3/re05.py‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪176‬‬
‫يبحث التابع )(‪ findall‬في الوسيط الثاني للتابع – من نوع سلسلة نصية ‪ -‬ويعيد قائمة بكل سلسلة‬
‫نصية تبدو كالبريد االلكتروني أما الرمز ‪ \S‬فيستخدم للتعبير عن عدم وجود مسافات فارغة‪.‬‬
‫فيكون خرج البرنامج‪:‬‬
‫]'‪['csev@umich.edu', 'cwen@iupui.edu‬‬
‫وتفسير هذا التعبير النمطي يكون بأننا نبحث عن سلسلة نصية جزئية تحوي على األقل محرف واحد‬
‫ال يمثل مسافة فارغة متبوع بإشارة @ متبوعة على األقل برمز واحد ال يمثل مسافة فارغة حيث‬
‫الرمز ‪ \S+‬يعني مطابقة أي عدد من املحارف باستثناء املسافة الفارغة‪.‬‬
‫سيطابق التعبير النمطي مرتين مع )‪)csev@umich.edu , cwen@iupui.edu‬‬
‫ولكن لن يطابق ‪ @2PM‬بسبب وجود مسافة فارغة قبل إشارة @‬
‫بإمكاننا استخدام التعبير النمطي السابق في البرنامج لقراءة كل األسطر في امللف وطباعة أي ش يء‬
‫يشبه البريد اإللكتروني كما يلي‪:‬‬
‫‪# Search for lines that have an at sign between characters‬‬
‫‪import re‬‬
‫)'‪hand = open('mbox-short.txt‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫)‪x = re.findall('\S+@\S+', line‬‬
‫‪if len(x) > 0:‬‬
‫)‪print(x‬‬
‫‪# Code: http://www.py4e.com/code3/re06.py‬‬
‫إننا نقرأ كل سطر ثم نستخرج كل سلسلة نصية جزئية والتي تطابق تعبيرنا النمطي‪.‬‬
‫بما أن التابع )(‪ findall‬يعيد قائمة فيمكن ببساطة أن نتحقق إذا كان عدد العناصر في القائمة املعادة‬
‫أكبر من صفر‪.‬‬
‫إذا شغلنا البرنامج على امللف ‪ mbox.txt‬سنحصل على الخرج التالي‪:‬‬
‫]'‪['wagnermr@iupui.edu‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪177‬‬
‫]'‪['cwen@iupui.edu‬‬
‫]'>‪['<postmaster@collab.sakaiproject.org‬‬
‫]'>‪['<200801032122.m03LMFo4005148@nakamura.uits.iupui.edu‬‬
‫]';>‪['<source@collab.sakaiproject.org‬‬
‫]';>‪['<source@collab.sakaiproject.org‬‬
‫]';>‪['<source@collab.sakaiproject.org‬‬
‫]')‪['apache@localhost‬‬
‫]';‪['source@collab.sakaiproject.org‬‬
‫تحوي بعض عناوين البريد اإللكتروني رموز مثل > أو ; في بدايتها أو نهايتها‪ ،‬ولنوضح أننا فقط مهتمين‬
‫في الجزء الذي يبدأ أو ينتهي بحرف أو رقم‪ ،‬لذلك نستخدم ميزات أخرى من ميزات التعبير النمطي‪،‬‬
‫ُ‬
‫فاألقواس القائمة ] [ تستخدم لتوضيح مجموعة من الرموز املتعددة املقبولة والتي نرغب باعتبارها‬
‫ً‬
‫فسابقا تعلمنا أن ‪ \S‬تطابق أي محرف بخالف املسافات الفارغة‪ .‬اآلن سنكون أكثر دقة في‬
‫متطابقة‬
‫املحارف التي سنطابقها‪.‬‬
‫هنا هو تعبيرنا النمطي الجديد‪:‬‬
‫]‪[a-zA-Z0-9]\S*@\S*[a-zA-Z‬‬
‫ً‬
‫تعقيدا وقد تدرك ملاذا التعابير النمطية هي لغة خاصة بذاتها‪.‬‬
‫يصبح املوضوع أكثر‬
‫إن تفسير هذا التعبير النمطي هو أننا نبحث عن سلسلة نصية جزئية تبدأ بحرف صغير أو حرف‬
‫كبير أو رقم ]‪ ،[a-zA-Z0-9‬ثم متبوع بصفر أو أي عدد من املحارف بخالف املسافة الفارغة *‪ \S‬ثم‬
‫بإشارة @‪ ،‬ثم بصفر أو عدد أكبر من املحارف خالف املسافة الفارغة *‪ \S‬متبوع بحرف كبير أو‬
‫صغير‪.‬‬
‫الحظ أننا أبدلنا من ‪ +‬إلى * لنشير لصفر أو أكثر من املحارف خالف املسافة الفارغة حيث‬
‫]‪ [a-zA-Z0-9‬هي واحدة من املحارف خالف املسافة الفارغة‪.‬‬
‫تذكر أن رمزي * أو ‪ +‬تطبق للرمز مباشرة املوجود إلى يسارهما‪.‬‬
‫عندما نستخدم هذا التعبير في برنامجنا ستكون بياناتنا أكثر رتابة‪:‬‬
‫‪# Search for lines that have an at sign between characters‬‬
‫‪# The characters must be a letter or number‬‬
‫‪import re‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪178‬‬
‫)'‪hand = open('mbox-short.txt‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫)‪x = re.findall('[a-zA-Z0-9]\S+@\S+[a-zA-Z]', line‬‬
‫‪if len(x) > 0:‬‬
‫)‪print(x‬‬
‫‪# Code: http://www.py4e.com/code3/re07.py‬‬
‫‪...‬‬
‫]'‪['wagnermr@iupui.edu‬‬
‫]'‪['cwen@iupui.edu‬‬
‫]'‪['postmaster@collab.sakaiproject.org‬‬
‫]'‪['200801032122.m03LMFo4005148@nakamura.uits.iupui.edu‬‬
‫]'‪['source@collab.sakaiproject.org‬‬
‫]'‪['source@collab.sakaiproject.org‬‬
‫]'‪['source@collab.sakaiproject.org‬‬
‫]'‪['apache@localhost‬‬
‫الحظ في األسطر ‪ source@collab.sakaiproject.org‬إن تعبيرنا النمطي استبعد حرفين من نهاية‬
‫السلسة النصية ;> ‪ ،‬وذلك ألنه عندما نضيف ]‪ [a-zA-Z‬لنهاية التعبير النمطي فإننا نطلب أنه مهما‬
‫كانت السلسلة النصية فإن عليها أن تنتهي بحرف لذلك عندما توجد < في نهاية‬
‫";˃‪ "sakaiproject.org‬فستتوقف املطابقة عند أخر حرف‪.‬‬
‫الحظ ً‬
‫أيضا أن خرج البرنامج هو قائمة كل عنصر فيها هو من النوع سلسلة نصية‪.‬‬
‫َ‬
‫‪ 3.11‬تنفيذ عمليتي البحث واالستخراج معا‬
‫إذا أردنا الحصول على األرقام في األسطر التي تبدأ بسلسلة نصية "‪ "X-‬مثل‪:‬‬
‫‪X-DSPAM-Confidence: 0.8475‬‬
‫‪X-DSPAM-Probability: 0.0000‬‬
‫ال نريد فقط أي أعداد عشرية من أي سطر إنما نريد استخراج األرقام من األسطر ذات الصيغة‬
‫أعاله‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪179‬‬
‫لنستخدم التعبير النمطي التالي الختيار األسطر‪:‬‬
‫‪^X-.*: [0-9.]+‬‬
‫أي أننا نريد األسطر التي تبدأ بـ ‪ X-‬متبوعة بصفر أو أكثر من املحارف *‪ .‬ومتبوعة بنقطتين ‪ :‬ثم فراغ‬
‫وبعد الفراغ نبحث عن محرف أو مجموعة من املحارف والتي ممكن أن تكون أرقام بين صفر حتى‬
‫تسعة أو ذات فاصلة عشرية ‪[0-9.]+‬‬
‫الحظ داخل األقواس املربعة إن النقطة تطابق فاصلة عشرية (ليست رمز النقطة الخاص بالتعابير‬
‫النمطية)‪.‬‬
‫إن التعبير التالي دقيق ً‬
‫جدا وسيطابق ً‬
‫تماما األسطر املطلوبة‪:‬‬
‫‪# Search for lines that start with 'X' followed by any non‬‬
‫'‪# whitespace characters and ':‬‬
‫‪# followed by a space and any number.‬‬
‫‪# The number can include a decimal.‬‬
‫‪import re‬‬
‫)'‪hand = open('mbox-short.txt‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫‪if re.search('^X\S*: [0-9.]+', line):‬‬
‫)‪print(line‬‬
‫‪# Code: http://www.py4e.com/code3/re10.py‬‬
‫عندما نقوم بتشغيل البرنامج نرى البيانات تظهر بشكل واضح األسطر التي نبحث عنها فقط‪.‬‬
‫‪X-DSPAM-Confidence: 0.8475‬‬
‫‪X-DSPAM-Probability: 0.0000‬‬
‫‪X-DSPAM-Confidence: 0.6178‬‬
‫‪X-DSPAM-Probability: 0.0000‬‬
‫لحل مشكلة استخراج األرقام بإمكاننا استخدام التابع ‪ split‬أو نستطيع استخدام ميزة أخرى من‬
‫ميزات التعابير النمطية بحيث نقوم بعمليتي البحث وتحليل السطور في نفس الوقت‪.‬‬
‫إن إشارة القوسين () هي أحد رموز التعابير النمطية الخاصة لكنها ال تستخدم في عمليات املطابقة‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪180‬‬
‫بل مع التابع )(‪ findall‬حيث تشير إلى أنه بالرغم من سعيك ملطابقة كل التعبير لكنك فقط مهتم‬
‫باستخراج جزء محدد من السلسلة النصية الجزئية املطابقة‪.‬‬
‫لذا قم بإجراء التغيير التالي لبرنامجنا‪:‬‬
‫‪# Search for lines that start with 'X' followed by any‬‬
‫‪# non whitespace characters and ':' followed by a space‬‬
‫‪# and any number. The number can include a decimal.‬‬
‫‪# Then print the number if it is greater than zero.‬‬
‫‪import re‬‬
‫)'‪hand = open('mbox-short.txt‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫)‪x = re.findall('^X\S*: ([0-9.]+)', line‬‬
‫‪if len(x) > 0:‬‬
‫)‪print(x‬‬
‫‪# Code: http://www.py4e.com/code3/re11.py‬‬
‫ً‬
‫بدال من استدعاء )(‪ search‬بإمكاننا إضافة قوسين حول جزء من التعبير النمطي الذي يمثل عدد‬
‫عشري‪ ،‬ليوضح أننا فقط نريد من التابع )(‪ findall‬أن يعطينا العدد ذي الفاصلة العشرية من‬
‫السلسة النصية املطابقة‪.‬‬
‫يظهر خرج البرنامج كما يلي‪:‬‬
‫]'‪['0.8475‬‬
‫]'‪['0.0000‬‬
‫]'‪['0.6178‬‬
‫]'‪['0.0000‬‬
‫]'‪['0.6961‬‬
‫]'‪['0.0000‬‬
‫بالرغم أن األرقام خزنت في قائمة‪ ،‬علينا إجراء تحويل من النوع سلسلة نصية إلى نوع عدد ذي‬
‫الفاصلة العشرية‪ ،‬لكن يظهر املثال السابق فعالية التعابير النمطية لكل من عمليتي البحث‬
‫واالستخراج‪.‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪181‬‬
‫كمثال آخر عن هذه التقنية إذا ألقينا نظرة على امللف‪ ،‬نالحظ أنه يتضمن عدد من األسطر بالصيغة‬
‫ٍ‬
‫التالية‪:‬‬
‫‪Details: http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772‬‬
‫إذا أردنا استخراج كل أرقام املراجعة )‪( (rev‬العدد الصحيح في نهاية هذه األسطر) باستخدام نفس‬
‫الطريقة أعاله فبإمكاننا كتابة البرنامج التالي‪:‬‬
‫'=‪for lines that start with 'Details: rev‬‬
‫‪# Search‬‬
‫'‪# followed by numbers and '.‬‬
‫‪# Then print the number if it is greater than zero‬‬
‫‪import re‬‬
‫)'‪hand = open('mbox-short.txt‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫)‪x = re.findall('^Details:.*rev=([0-9.]+)', line‬‬
‫‪if len(x) > 0:‬‬
‫)‪print(x‬‬
‫‪# Code: http://www.py4e.com/code3/re12.py‬‬
‫لتفسير تعبيرنا النمطي فنحن نبحث عن أسطر والتي تبدأ بكلمة ‪ Details:‬متبوعة بأي عدد من‬
‫املحارف *‪ .‬متبوعة بـ =‪ rev‬وثم بواحد أو أكثر من األرقام‪ .‬وألننا ال نريد إيجاد األسطر التي تطابق كل‬
‫التعبير بل فقط نريد استخراج العدد الصحيح في نهاية السطر لذلك نحيط ‪ [0-9]+‬بقوسين‪.‬‬
‫عندما نقوم بتشغيل البرنامج فنحصل على الخرج التالي‪:‬‬
‫]'‪['39772‬‬
‫]'‪['39771‬‬
‫]'‪['39770‬‬
‫]'‪['39769‬‬
‫‪...‬‬
‫متعد أي سيحاول الحصول على أكبر سلسلة نصية ممكنة قبل‬
‫تذكر أن في التعبير ‪ [0-9]+‬رمز ‪ٍ +‬‬
‫استخراج األرقام‪ ،‬يفسر هذا السلوك ملاذا نحصل على خمس خانات لكل رقم‪.‬‬
‫انتبه إلى أن مكتبة التعابير النمطية تتوسع في كال االتجاهين حتى تقابل محرف غير الرقم‪ ،‬أي نحو‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪182‬‬
‫بداية ونهاية السطر‪.‬‬
‫اآلن يمكننا استخدام التعابير النمطية لحل تمارين سابقة حيث كان محط اهتمامنا هو الوقت‬
‫واليوم لكل رسالة بريدية‪:‬‬
‫حيث نظرنا سابقا إلى األسطر بالصيغة‪:‬‬
‫‪From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008‬‬
‫ً‬
‫فسابقا فعلنا ذلك باستدعاء التابع ‪ split‬مرتين‪:‬‬
‫وأردنا استخراج الوقت لكل سطر‪،‬‬
‫ً‬
‫ً‬
‫مجددا عبر عامل النقطتين‬
‫أوال عبر تجزئة السطر إلى كلمات ثم ُسحبت الكلمة الخامسة ثم جزأناه‬
‫‪ :‬لسحب املحرفين املهتمين بهما‪ ،‬ولقد نجح ذلك ولكن هذه الطريقة ليس عملية حيث تفترض أن‬
‫األسطر ذات صيغة قياسية‪.‬‬
‫إذا َ‬
‫أردت إضافة عملية تحقق من األخطاء (أو كتلة تعليمات لبنية ‪ ،)try/except‬لضمان عدم إخفاق‬
‫ً‬
‫ً‬
‫صحيحا فسيزداد حجم الشيفرة ‪ً 15-10‬‬
‫سطرا‬
‫تنسيقا‬
‫برنامجك عندما تدخل له أسطر غير منسقة‬
‫ً‬
‫برمجيا مما يجعل البرنامج صعب الفهم‪.‬‬
‫يمكن تبسيط ذلك باستخدام التعبير النمطي‪:‬‬
‫‪^From .* [0-9][0-9]:‬‬
‫ً‬
‫متبوعا بأي عدد‬
‫تفسير هذا التعبير النمطي أننا نبحث عن األسطر التي تبدأ بالكلمة ‪ From‬ثم فراغ‬
‫ً‬
‫ً‬
‫ً‬
‫متبوعا بنقطتين ‪:‬‬
‫متبوعا برقمين ]‪[0-9] [0-9‬‬
‫متبوعا بفراغ‬
‫من املحارف *‪.‬‬
‫هذا التعبير مناسب لألسطر التي نبحث عنها‪.‬‬
‫الستخراج الساعة فقط باستخدام )(‪ findall‬نضيف قوسين حول الرقمين كما يلي‪:‬‬
‫‪^From .* ([0-9][0-9]):‬‬
‫فيكون البرنامج كالتالي‪:‬‬
‫‪# Search for lines that start with From and a character‬‬
‫'‪# followed by a two digit number between 00 and 99 followed by ':‬‬
‫‪# Then print the number if it is greater than zero‬‬
‫‪import re‬‬
‫)'‪hand = open('mbox-short.txt‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪183‬‬
‫‪for line in hand:‬‬
‫)(‪line = line.rstrip‬‬
‫)‪x = re.findall('^From .* ([0-9][0-9]):', line‬‬
‫)‪print(x‬‬
‫‪if len(x) > 0:‬‬
‫‪# Code: http://www.py4e.com/code3/re13.py‬‬
‫وستعطي الخرج التالي عندما يتم تشغيل البرنامج‪:‬‬
‫]'‪['09‬‬
‫]'‪['18‬‬
‫]'‪['16‬‬
‫]'‪['15‬‬
‫‪...‬‬
‫‪ 4.11‬محرف الهروب‬
‫عند استخدامنا لرموز التعابير النمطية ملطابقة بداية أو نهاية السطر أو الرموز الخاصة كـ * و ‪+‬‬
‫فإننا نحتاج طريقة لتفريقها عن املحارف العادية والتي قد نريد مطابقتها كإشارة ‪ $‬أو ^‬
‫نضع رمز \ (الشرطة املائلة للخلف) لتبيان أننا نبحث عن مطابقة هذا املحرف وليس ً‬
‫رمزا من رموز‬
‫التعابير النمطية‪ .‬فعلى سبيل املثال بإمكاننا إيجاد قيم مالية في نص باستخدام التعبير النمطي التالي‪:‬‬
‫‪import re‬‬
‫'‪x = 'We just received $10.00 for cookies.‬‬
‫)‪y = re.findall('\$[0-9.]+',x‬‬
‫عندما نضع الشرطة املائلة للخلف قبل عالمة الدوالر ‪ $‬فإنها تبحث ً‬
‫حقا عن إشارة ‪ $‬في السلسلة‬
‫ً‬
‫النصية بدال من مطابقتها في "نهاية السطر"‪ ،‬ويطابق بقية التعبير النمطي رقم أو مجموعة أرقام‪.‬‬
‫الحظ أنه داخل األقواس القائمة‪ ،‬املحارف ليست خاصة بالتعبير النمطي‪ ،‬لذلك عندما نقول‬
‫]‪ [0-9.‬فهو يعني ً‬
‫حقا أرقام أو ذات فاصلة عشرية‪ ،‬أما خارج تلك األقواس تعد النقطة أحد رموز‬
‫التعبير النمطي وتطابق أي محرف‪ .‬أي أن النقطة داخل األقواس املربعة هي نقطة عادية تشير‬
‫لألرقام ذات الفاصلة العشرية‪.‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪184‬‬
‫‪ 5.11‬ملخص‬
‫ً‬
‫هذا الفصل هو ملحة عن التعابير النمطية فقد تعلمنا قليال عن لغة التعابير النمطية‪ .‬فهي طريقة‬
‫للبحث في السالسل النصية تعتمد على رموز خاصة تمكنك من التعبير عما تريد البحث عنه بلغة‬
‫التعابير النمطية وهذا ما يعرف باملطابقة وتمكنك من استخراج أجزاء محددة من تلك السالسل‬
‫النصية املطابقة‪.‬‬
‫إليك بعض الرموز الخاصة‪:‬‬
‫• ^ تطابق بداية السطر‬
‫• ‪ $‬تطابق نهاية السطر‬
‫• ‪ .‬تطابق أي محرف تسمى )‪)wildcard‬‬
‫• ‪ \s‬تطابق املسافات الفارغة ‪-‬انتبه حرف ‪ s‬هنا حرف صغير‪.-‬‬
‫• ‪ \S‬تطابق أي محرف خالف املسافات الفارغة (أي عكس ‪ )\s‬تطبق على املحرف أو‬
‫املحارف التي تسبقها بشكل مباشر وتشير ملطابقة صفر أو أكثر من املرات‬
‫• ?* تطبق على املحرف أو املحارف التي تسبقها بشكل مباشر وتشير ملطابقة صفر أو أكثر‬
‫من املرات (في الوضع غير املتعدي (أي غير الطماع))‬
‫• ‪ +‬تطبق على املحرف أو املحارف التي تسبقها بشكل مباشر وتشير ملطابقة مرة أو أكثر‬
‫من املرات‬
‫• ?‪ +‬تطبق على املحرف أو املحارف التي تسبقها بشكل مباشر وتشير ملطابقة مرة أو أكثر‬
‫من املرات (في الوضع غير املتعدي)‬
‫• ؟ تطبق على املحرف أو املحارف التي تسبقها بشكل مباشر وتشير ملطابقة صفر أو مرة‬
‫واحدة‬
‫• ؟؟ تطبق على املحرف أو املحارف التي تسبقها بشكل مباشر وتشير ملطابقة صفر أو مرة‬
‫واحدة (في الوضع غير املتعدي)‬
‫• ]‪ [aeiou‬تطابق حرف وحيد طاملا أن املحرف في مجموعة معينة في هذا املثال ستطابق‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪185‬‬
‫"‪ "a‬أو "‪ "e‬أو "‪ "I‬أو "‪ "o‬أو "‪ "u‬لكن لن تطابق أي محارف أخرى‪.‬‬
‫• ]‪ [a-z0-9‬بإمكانك تحديد نطاق املحارف باستخدام إشارة الناقص ‪ ، -‬وهذا املثال هو‬
‫محرف وحيد يجب أن يكون حرف صغير أو رقم‪.‬‬
‫• ]‪ [^A-Za-z‬عندما أول رمز في مجموعة الرموز هو ^ فهو يعكس الحالة‪ ،‬وهذا املثال‬
‫يطابق محرف وحيد مطابق ألي ش يء إال حرف كبير أو صغير‪.‬‬
‫ُ‬
‫• () حين تضاف األقواس للتعابير النمطية ال تكون بغرض املطابقة‪ ،‬بل الستخراج‬
‫مجموعة فرعية معينة من السلسة النصية التي تمت مطابقتها‪.‬‬
‫• ‪ \b‬تطابق سلسلة نصية فارغة‪ ،‬لكن فقط في بداية أو نهاية الكلمة‪.‬‬
‫• ‪ \B‬تطابق سلسلة نصية فارغة‪ ،‬لكن ليست في بداية أو نهاية الكلمة‪.‬‬
‫• ‪ \d‬تطابق أي رقم من أرقام النظام العشري‪ ،‬وهذا مماثل للتعبير ]‪[0-9‬‬
‫• ‪ \D‬تطابق أي محرف ليس رقم‪ ،‬وهذا مماثل ]‪[^0-9‬‬
‫‪ 6.11‬معلومات إضافية ملستخدمي نظامي ‪ Unix‬و ‪Linux‬‬
‫أضيف البحث عن امللفات باستخدام التعابير النمطية في نظام تشغيل ‪ Unix‬عام ‪ 1960‬وهو متاح‬
‫في أغلب لغات البرمجة بشكل أو بآخر‪.‬‬
‫في الواقع يوجد برنامج أوامر(‪ )command-line‬ضمن ‪ Unix‬ويسمى ‪( grep‬محلل التعابير النمطية‬
‫العام) والذي يعمل ً‬
‫تقريبا مثل األمثلة التي استخدمنا فيها تابع )(‪ search‬في هذا الفصل‪ ،‬لذا إذا كان‬
‫لديك نظام ‪ Macintosh‬أو ‪ Linux‬فبإمكانك تجربة األوامر التالية في نافذة برنامج األوامر‪:‬‬
‫‪$ grep '^From:' mbox-short.txt‬‬
‫‪From: stephen.marquard@uct.ac.za‬‬
‫‪From: louis@media.berkeley.edu‬‬
‫‪From: zqian@umich.edu‬‬
‫‪From: rjlowe@iupui.edu‬‬
‫يطلب األمر السابق من برنامج ‪ grep‬أن يظهر لك األسطر التي تبدأ بالسلسلة النصية ‪ From‬في امللف‬
‫‪mbox-short.txt.‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪186‬‬
‫ً‬
‫إذا جربت برنامج ‪ grep‬قليال وقرأت ملفات التوثيق الخاصة به سترى بعض االختالفات الدقيقة بين‬
‫ً‬
‫التعابير النمطية في لغة بايثون والتعابير النمطية في ‪ ،grep‬فمثال ‪ grep‬ال يدعم رمز ‪ \S‬فستحتاج إلى‬
‫ً‬
‫تعقيدا ] ^[ والذي يعني ببساطة مطابقة أي محرف عدا الفراغ‪.‬‬
‫مجموعة رموز أكثر‬
‫‪ 7.11‬التنقيح‬
‫تحوي لغة بايثون ملفات توثيق سهلة ومفيدة ً‬
‫جدا في حال احتجت منشط سريع لتحفيز ذاكرتك‬
‫السترجاع اسم تابع ما‪ ،‬حيث يمكن عرض هذه امللفات في مفسر لغة بايثون في الوضع التفاعلي‪.‬‬
‫يمكنك جلب نظام املساعدة التفاعلي باستخدام )(‪help‬‬
‫)(‪>>> help‬‬
‫‪help> modules‬‬
‫إذا كنت تعلم أي وحدة (‪ )module‬تريد استخدامها يمكنك استخدام أمر )(‪ dir‬إليجاد التوابع في‬
‫الوحدة كما يلي‪:‬‬
‫‪>>> import re‬‬
‫)‪>>> dir(re‬‬
‫‪[.. 'compile', 'copy_reg', 'error', 'escape', 'findall',‬‬
‫‪'finditer' , 'match', 'purge', 'search', 'split', 'sre_compile',‬‬
‫]'‪'sre_parse' , 'sub', 'subn', 'sys', 'template‬‬
‫بإمكانك أيضا الحصول على توثيق مختصر عن أحد التوابع باستخدام األمر ‪help‬‬
‫)‪>>> help (re.search‬‬
‫‪Help on function search in module re:‬‬
‫)‪search(pattern, string, flags=0‬‬
‫‪Scan through string looking for a match to the pattern, returning‬‬
‫‪a match object, or None if no match was found.‬‬
‫>>>‬
‫إن ملفات التوثيق ليست شاملة لكنها مفيدة في حال احتجت ملعلومة بسرعة أو عندما ال يكون لديك‬
‫وصول إلى متصفح ويب أو محرك بحث‪.‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪187‬‬
‫‪ 8.11‬فهرس املصطلحات‬
‫• الشيفرة الهشة (‪ :)brittle code‬هي الشيفرة التي تعمل عندما تكون بيانات الدخل في‬
‫صيغة معينة قياسية لكنها ضعيفة ً‬
‫جدا إذا كان هناك بعض التغيرات عن الصيغة‬
‫القياسية‪ ،‬ونسميها هشة ألنه من السهل كسرها‪.‬‬
‫• املطابقة الطماعة (‪ :)greedy matching‬الفكرة أن رموز ‪ +‬و * في التعبير النمطي تمتد‬
‫ملطابقة أكبر عدد ممكن من محارف السلسلة النصية‪.‬‬
‫• محلل التعابير النمطية العام (‪ :)grep‬أمر متاح في أنظمة ‪ Unix‬يبحث عبر امللفات‬
‫النصية إليجاد أسطر تطابق التعابير النمطية‪ ،‬وهو اختصار لجملة ‪(Generalized‬‬
‫)‪regular expression parser‬‬
‫• التعبيرالنمطي (‪ :)regular expression‬لغة للبحث في السالسل النصية‪ ،‬حيث يحوي‬
‫التعبير النمطي ً‬
‫رموزا خاصة تظهر أن البحث فقط سيطابق بداية ونهاية أسطر‬
‫باإلضافة العديد من امليزات املماثلة‪.‬‬
‫• الرموز البديلة (‪ :)Wildcard‬رمز خاص يطابق أي محرف‪ ،‬أحدها هو النقطة‪.‬‬
‫‪ 9.11‬تمارين‬
‫• التمرين األول‪ :‬اكتب برنامج بسيط ملحاكاة عملية أمر ‪ grep‬في نظام ‪ ،Unix‬واطلب من‬
‫املستخدم إدخال تعبير نمطي واحسب عدد األسطر التي تطابق التعبير النمطي‪.‬‬
‫‪$ python grep.py‬‬
‫‪Enter a regular expression: ^Author‬‬
‫‪mbox.txt had 1798 lines that matched ^Author‬‬
‫‪$ python grep.py‬‬
‫‪Enter a regular expression: ^X‬‬‫‪mbox.txt had 14368 lines that matched ^X-‬‬
‫الفصل الحادي عشر‪ :‬التعابير النمطية‬
‫‪188‬‬
‫‪$ python grep.py‬‬
‫‪Enter a regular expression: java$‬‬
‫‪mbox.txt had 4175 lines that matched java$‬‬
‫• التمرين الثاني‪ :‬اكتب برنامج ليبحث عن أسطر تحوي صيغة مشابهة ملا يلي‪:‬‬
‫‪New Revision: 39772‬‬
‫استخرج العدد من كل سطر باستخدام تعبير نمطي والتابع )(‪ findall‬واحسب متوسط األعداد‬
‫واطبع املتوسط كعدد صحيح‪.‬‬
‫‪Enter file:mbox.txt‬‬
‫‪38549‬‬
‫‪Enter file:mbox-short.txt‬‬
‫‪39756‬‬
‫الفصل الثاني عشر‬
‫البرامج املرتبطة بالشبكات‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪190‬‬
‫‪ 12‬البرامج املرتبطة بالشبكات‬
‫ركزنا في العديد من األمثلة الواردة في هذا الكتاب على قراءة امللفات والبحث عن بيانات ضمنها‪ ،‬إال‬
‫أن هناك العديد من مصادر املعلومات املختلفة كشبكة اإلنترنت‪.‬‬
‫في هذا الفصل‪ ،‬سنعمل عمل ُمتصفح اإلنترنت الذي يسترجع صفحات الويب باستخدام بروتوكول‬
‫ُ‬
‫نقل النص التشعبي )‪ ،(Hypertext Transfer Protocol‬بعد ذلك سنقرأ ونحلل بيانات تلك‬
‫الصفحات‪.‬‬
‫ّ‬
‫التشعبي ‪HTTP‬‬
‫‪ 1.12‬برتوكول نقل النص‬
‫إن بروتوكول الشبكة الذي يحكم عمل شبكة الويب بسيط للغاية‪ .‬كما تسهل املكتبة البرمجية‬
‫الجاهزة في بايثون ‪ socket‬عملية إنشاء اتصاالت عبر الشبكة واسترجاع البيانات عبر مآخذ الشبكة‬
‫(‪ )Sockets‬في برنامج بايثون‪.‬‬
‫ُ‬
‫تشبه مآخذ الشبكة امللف إلى حد ما‪ ،‬لكن يكمن االختالف في أنها تؤمن إمكانية اتصال ثنائي االتجاه‬
‫بين برنامجين‪ .‬حيث تستطيع القراءة والكتابة عبر مآخذ الشبكة ذاتها‪.‬‬
‫ُ‬
‫فإذا ُق َ‬
‫مت بكتابة ش يء ما إلى مآخذ الشبكة‪ ،‬فإنه ُي َ‬
‫رسل إلى التطبيق في الجانب اآلخر‪ .‬بينما إذا قمت‬
‫بالقراءة منه فإن البيانات الواردة إليك ُمرسلة من قبل تطبيق آخر‪.‬‬
‫يجب عليك االنتظار عند محاولة قراءة مآخذ الشبكة في حال لم يرسل البرنامج في الطرف اآلخر أي‬
‫بيانات‪ .‬إذا انتظرت البرامج في طرفي مآخذ الشبكة وصول بيانات بدون إرسال أي ش يء‪ ،‬فال شك أنها‬
‫ً‬
‫ً‬
‫ً‬
‫محددا‪.‬‬
‫ستنتظر طويال‪ .‬لذلك من املهم أن تتبع البرامج التي تتواصل عبر اإلنترنت بروتوكوال‬
‫ً‬
‫أوال وماذا ُ‬
‫البروتوكول‪ ،‬هو مجموعة من القواعد ُتحدد ُّ‬
‫سينفذان‪،‬‬
‫أي طرف سيبدأ في االتصال‬
‫ثم ما هي الردود لتلك الرسالة‪ ،‬ومن ُ‬
‫سيرسل ً‬
‫تاليا‪ ،‬وهكذا‪.‬‬
‫بمعنى أن التطبيقين على طرفي مآخذ الشبكة يتبعان خطوات متوافقة بدون أي تعارض‪.‬‬
‫تتوفر العديد من املستندات التي تشرح برتوكوالت الشبكة‪ .‬تجد بروتوكول نقل النص التشعبي‬
‫‪ُ HTTP‬موض ًحا في املستند التالي‪https://www.w3.org/Protocols/rfc2616/rfc2616.txt :‬‬
‫ُ‬
‫هذا املستند طويل ومعقد من ‪ 176‬صفحة مليء بالكثير من التفاصيل‪.‬‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪191‬‬
‫َ‬
‫وجدت أنه مهم فال تتردد بقراءته بالكامل‪ ،‬لكن إذا أردت العثور على القواعد حول طلبات ‪GET‬‬
‫إذا‬
‫فعليك االطالع على الصفحة رقم ‪ 36‬من املستند املوافق للرقم ‪.RFC2616‬‬
‫ً‬
‫لطلب ُمستند من مخدم ويب ُ‬
‫سنجري اتصاال مع مخدم املوقع ‪ www.pr4e.org‬على املنفذ )‪(port‬‬
‫رقم ‪ 80‬ثم نرسل ً‬
‫أمرا كالتالي‪:‬‬
‫‪GET http://data.pr4e.org/romeo.txt HTTP/1.0‬‬
‫بحيث يكون املعامل الثاني هو صفحة الويب التي طلبناها‪ ،‬ثم نقوم ً‬
‫أيضا بإرسال سطر فارغ‪.‬‬
‫ً‬
‫متبوعا بمحتوى‬
‫سيستجيب خادم الويب بإرسال بعض املعلومات الرئيسية عن املستند وسطر فارغ‬
‫املستند‪.‬‬
‫ّ‬
‫‪ُ 2.12‬متصفح الويب األبسط في العالم‬
‫ربما الطريقة األسهل إليضاح آلية عمل بروتوكول ‪ HTTP‬هي بكتابة برنامج بايثون بسيط يقوم‬
‫باالتصال بخادم الويب وفق قواعد بروتوكول ‪ HTTP‬لطلب املستند ثم عرض الرد الذي ُيرسله‬
‫املخدم‪.‬‬
‫‪import socket‬‬
‫)‪mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM‬‬
‫))‪mysock.connect(('data.pr4e.org', 80‬‬
‫)(‪cmd = 'GET http://data.pr4e.org/romeo.txt HTTP/1.0\r\n\r\n'.encode‬‬
‫)‪mysock.send(cmd‬‬
‫‪while True:‬‬
‫)‪data = mysock.recv(512‬‬
‫‪if len(data) < 1:‬‬
‫‪break‬‬
‫)' '=‪print(data.decode(),end‬‬
‫)(‪mysock.close‬‬
‫‪# Code: http://www.py4e.com/code3/socket1.py‬‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪192‬‬
‫يقوم البرنامج في البداية باالتصال مع املنفذ ‪ 80‬على الخادم ‪www.py4e.com‬‬
‫ُ‬
‫بما أن برنامجنا يؤدي دور ُمتصفح اإلنترنت فإن بروتوكول نقل النص التشعبي يفرض علينا أن نرسل‬
‫ً‬
‫متبوعا بسطر فارغ‪.‬‬
‫أمر ‪GET‬‬
‫َ‬
‫ُ‬
‫ُ‬
‫الرموز ‪ \r\n‬تشير إلى )‪ EOL (End Of Line‬أي "نهاية السطر"‪ .‬لذا فإن الرموز ‪ \r\n\r\n‬تشير إلى عدم‬
‫وجود ش يء بين تتابعي نهاية سطرين‪ .‬وهذا ُيكافئ السطر الفارغ‪.‬‬
‫بمجرد إرسال السطر الفارغ نقوم بإنشاء حلقة تستقبل البيانات على شكل أجزاء بحجم ‪ 512‬محرف‬
‫للجزء الواحد من مآخذ الشبكة‪ ،‬ونستمر بطباعة البيانات حتى ال يبقى أي بيانات للقراءة‪ ،‬أي حتى‬
‫ُيعيد التابع )(‪ recv‬سلسلة نصية فارغة‪.‬‬
‫الشكل ‪ : 13‬نموذج اتصال عبر مآخذ الشبكة‬
‫ُينتج البرنامج الخرج التالي‪:‬‬
‫‪HTTP/1.1 200 OK‬‬
‫‪Date: Wed, 11 Apr 2018 18:52:55 GMT‬‬
‫)‪Server: Apache/2.4.7 (Ubuntu‬‬
‫‪Last-Modified: Sat, 13 May 2017 11:22:22 GMT‬‬
‫"‪ETag: "a7-54f6609245537‬‬
‫‪Accept-Ranges: bytes‬‬
‫‪Content-Length: 167‬‬
‫‪Cache-Control: max-age=0, no-cache, no-store, must-revalidate‬‬
‫‪Pragma: no-cache‬‬
‫‪Expires: Wed, 11 Jan 1984 05:00:00 GMT‬‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪193‬‬
‫‪Connection: close‬‬
‫‪Content-Type: text/plain‬‬
‫‪But soft what light through yonder window breaks‬‬
‫‪It is the east and Juliet is the sun‬‬
‫‪Arise fair sun and kill the envious moon‬‬
‫‪Who is already sick and pale with grief‬‬
‫ُ‬
‫يظهر في بداية الخرج الترويسة (‪ )header‬التي أرسلها الخادم لوصف املستند‪.‬‬
‫على سبيل املثال‪ ،‬تشير عبارة ‪ Content_Type‬إلى أن املستند هو مستند نص ي عادي (‪.)text/plain‬‬
‫ُيضيف الخادم بعد أن ُيرسل لنا الترويسة سطر فارغ لإلشارة إلى نهايتها‪ ،‬ثم بعد ذلك ُيرسل البيانات‬
‫الفعلية وهي امللف النص ي ‪.romeo.txt‬‬
‫ُيوضح هذا املثال كيفية إجراء اتصال شبكي منخفض املستوى بواسطة مآخذ الشبكة‪ .‬حيث يمكن‬
‫أن تستخدم مآخذ الشبكة لالتصال بخادم الويب أو خادم البريد أو أي خوادم أخرى‪ .‬فكل ما هو‬
‫مطلوب هو العثور على املستند الذي يشرح مبدأ عمل البروتوكول ومن ثم كتابة الشيفرة البرمجية‬
‫إلرسال واستقبال البيانات ً‬
‫وفقا له‪.‬‬
‫على أي حال‪ ،‬بما أن البروتوكول الشائع استخدامه هو بروتوكول الويب ‪ HTTP‬فإن لغة بايثون‬
‫تحتوي مكتبة ُ‬
‫ً‬
‫ً‬
‫وخصيصا عمليات استرجاع املستندات والبيانات عبر‬
‫خصيصا لتدعمه‬
‫صممت‬
‫الويب‪.‬‬
‫أحد ُمتطلبات استخدام بروتوكول ‪ HTTP‬هو إرسال واستقبال البيانات على أنها سلسلة من البايتات‬
‫ً‬
‫(‪ )Bytes Objects‬بدال من اعتبارها سالسل نصية‪ ،‬ففي املثال السابق‪ ،‬يحول التابعان )(‪َ encode‬و‬
‫)(‪ decode‬السالسل النصية إلى سلسلة من البايتات وبالعكس‪.‬‬
‫يستخدم املثال التالي الرمز ' '‪ b‬لتخزين املتغير كسلسلة بايتات‪ .‬إن كل من ' '‪َ b‬و )(‪ُ encode‬متكافئان‪.‬‬
‫'‪>>> b'Hello world‬‬
‫'‪b'Hello world‬‬
‫)(‪>>> 'Hello world'.encode‬‬
‫'‪b'Hello world‬‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪194‬‬
‫‪ 3.12‬استعادة صورة عن طريق بروتوكول ‪HTTP‬‬
‫في املثال أعاله‪ ،‬استعدنا ملف نص ي‪ ،‬وعرضنا ببساطة البيانات إلى الشاشة عند تنفيذ البرنامج‪.‬‬
‫ً‬
‫يمكننا استخدام برنامج مشابه الستعادة صورة عن طريق ‪ ،HTTP‬فبدال من عرض البيانات على‬
‫الشاشة عند تنفيذ البرنامج‪ ،‬نقوم بتجميع البيانات في سلسلة وبعدها نحذف الترويسة ثم نحفظ‬
‫بيانات الصورة في ملف كما هو موضح‪:‬‬
‫‪import socket‬‬
‫‪import time‬‬
‫'‪HOST = 'data.pr4e.org‬‬
‫‪PORT = 80‬‬
‫)‪mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM‬‬
‫))‪mysock.connect((HOST, PORT‬‬
‫)'‪mysock.sendall(b'GET http://data.pr4e.org/cover3.jpg HTTP/1.0\r\n\r\n‬‬
‫‪count = 0‬‬
‫" "‪picture = b‬‬
‫‪while True:‬‬
‫)‪data = mysock.recv(5120‬‬
‫‪if len(data) < 1: break‬‬
‫)‪#time.sleep(0.25‬‬
‫)‪count = count + len(data‬‬
‫)‪print(len(data), count‬‬
‫‪picture = picture + data‬‬
‫)(‪mysock.close‬‬
195
‫ البرامج املرتبطة بالشبكات‬:‫الفصل الثاني عشر‬
# Look for the end of the header (2 CRLF)
pos = picture.find(b"\r\n\r\n")
print('Header length', pos)
print(picture[:pos].decode())
# Skip past the header and save the picture data
picture = picture[pos+4:]
fhand = open("stuff.jpg", "wb")
fhand.write(picture)
fhand.close()
# Code: http://www.py4e.com/code3/urljpeg.py
:‫عند تشغيل البرنامج فإنه ُيولد الخرج التالي‬
$ python urljpeg.py
5120 5120
5120 10240
4240 14480
5120 19600
...
5120 214000
3200 217200
5120 222320
5120 227440
3167 230607
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪196‬‬
‫‪Header length 393‬‬
‫‪HTTP/1.1 200 OK‬‬
‫‪Date: Wed, 11 Apr 2018 18:54:09 GMT‬‬
‫)‪Server: Apache/2.4.7 (Ubuntu‬‬
‫‪Last-Modified: Mon, 15 May 2017 12:27:40 GMT‬‬
‫"‪ETag: "38342-54f8f2e5b6277‬‬
‫‪Accept-Ranges: bytes‬‬
‫‪Content-Length: 230210‬‬
‫‪Vary: Accept-Encoding‬‬
‫‪Cache-Control: max-age=0, no-cache, no-store, must-revalidate‬‬
‫‪Pragma: no-cache‬‬
‫‪Expires: Wed, 11 Jan 1984 05:00:00 GMT‬‬
‫‪Connection: close‬‬
‫‪Content-Type: image/jpeg‬‬
‫تستطيع أن ُتالحظ أنه من أجل الرابط املستخدم يشير ‪ Content_Type‬في الترويسة إلى أن محتوى‬
‫املستند هو عبارة عن صورة )‪ .(image/jpeg‬بمجرد أن يتم تنفيذ البرنامج‪ ،‬بإمكانك استعراض بيانات‬
‫الصورة عبر فتح امللف ‪ stuff.jpg‬في برنامج عرض الصور‪.‬‬
‫ستالحظ عند تنفيذ البرنامج أننا ال نستقبل ‪ 5120‬م َ‬
‫حرف في كل مرة نستدعي التابع )(‪ ،recv‬فحين‬
‫نستدعي )(‪ recv‬نحصل على املحارف التي تم نقلها إلينا عبر الشبكة عن طريق خادم الويب‪ .‬ففي هذا‬
‫املثال‪ ،‬حصلنا على دفعات من البيانات تتراوح بين ‪ 3200‬حتى ‪ 5120‬محرف‪.‬‬
‫اعتمادا على سرعة الشبكة‪ .‬ضع بالحسبان ً‬
‫ً‬
‫أيضا أنه عند االستدعاء األخير‬
‫قد تكون نتائجك مختلفة‬
‫لـ )(‪ recv‬نحصل على ‪ 3167‬بايت وهي أخر جزء من البيانات‪ .‬وفي االستدعاء التالي لـ )(‪ recv‬نحصل‬
‫على سلسلة بطول صفري (‪ )Zero-length string‬والتي تشير إلى أن الخادم استدعى التابع )(‪close‬‬
‫عند طرف مآخذ الشبكة‪ ،‬وأنه ال يوجد املزيد من البيانات القادمة‪.‬‬
‫بإمكاننا إبطاء عملية االستدعاء املتتالية لـ )(‪ recv‬عن طريق إلغاء تعليق استدعاء التابع‬
‫)(‪ .time.sleep‬حيث ننتظر بهذه الطريقة ربع ثانية بعد كل استدعاء (نضيف ً‬
‫تأخيرا بمقدار ربع ثانية)‬
‫ البرامج املرتبطة بالشبكات‬:‫الفصل الثاني عشر‬
197
.‫ مرة أخرى‬recv() ‫بحيث يمكن للخادم مجاراتنا وإرسال املزيد من البيانات لنا قبل أن نستدعي‬
:‫مع هذا التأخير يتم تنفيذ البرنامج على النحو التالي‬
$ python urljpeg.py
5120 5120
5120 10240
5120 15360
...
5120 225280
5120 230400
207 230607
Header length 393
HTTP/1.1 200 OK
Date: Wed, 11 Apr 2018 21:42:08 GMT
Server: Apache/2.4.7 (Ubuntu)
Last-Modified: Mon, 15 May 2017 12:27:40 GMT
ETag: "38342-54f8f2e5b6277"
Accept-Ranges: bytes
Content-Length: 230210
Vary: Accept-Encoding
Cache-Control: max-age=0, no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Connection: close
Content-Type: image/jpeg
َ ‫ م‬5120 ‫ نحصل على‬recv() ‫ وبغض النظر عن االستدعاء األول واألخير لـ‬،‫اآلن‬
‫حرف في كل مرة نطلب‬
.‫بيانات جديدة‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪198‬‬
‫ُهناك ذاكرة مؤقتة (‪ )Buffer‬بين الخادم الذي ُينش ئ طلبات التابع )(‪ send‬والتطبيق الخاص بنا الذي‬
‫ُينش ئ طلبات )(‪.recv‬‬
‫في مرحلة ما‪ ،‬وعند تشغيل البرنامج مع التأخير‪ ،‬قد يتسبب الخادم في ملء الذاكرة املؤقتة في مآخذ‬
‫الشبكة ويجبره على التوقف حتى يبدأ برنامجنا بإفراغها‪.‬‬
‫إن عملية إيقاف كل من تطبيق اإلرسال أو االستقبال ُيدعى التحكم في التدفق (‪.)flow control‬‬
‫‪ 4.12‬استعادة صفحات الويب باستخدام مكتبة ‪urllib‬‬
‫أرسلنا واستقبلنا ً‬
‫سابقا البيانات عن طريق ‪ُ HTTP‬مستخدمين مكتبة ‪ ،socket‬لكن هنالك طريقة‬
‫أسهل لتنفيذ هذه املهمة مستخدمين مكتبة ‪.urllib‬‬
‫ُ‬
‫تستطيع باستخدامك ملكتبة ‪ urllib‬التعامل مع صفحة الويب كما لو أنها ملف‪ ،‬فتشير ببساطة إلى‬
‫ُ‬
‫صفحة الويب التي تريد استعادتها لتقوم املكتبة بالتعامل مع تفاصيل بروتوكول ‪ HTTP‬وتفاصيل‬
‫الترويسة‪.‬‬
‫ُ‬
‫إن الشيفرة املكافئة لقراءة ملف ‪ romeo.txt‬من الويب باستخدام مكتبة ‪ urllib‬هي كالتالي‪:‬‬
‫‪import urllib.request‬‬
‫)'‪fhand = urllib.request.urlopen('http://data.pr4e.org/romeo.txt‬‬
‫‪for line in fhand:‬‬
‫))(‪print(line.decode().strip‬‬
‫‪# Code: http://www.py4e.com/code3/urllib1.py‬‬
‫ُ‬
‫ُبمجرد أن تفتح صفحة الويب باستخدام تعليمة ‪ُ ،urllib.urlopen‬يصبح بإمكاننا التعامل معها مثل‬
‫امللف وقراءتها باستخدام حلقة ‪.for‬‬
‫عند تشغيل البرنامج‪ ،‬نرى محتويات امللف فقط في الخرج‪ ،‬بالرغم أن الترويسة أرسلت بالفعل لكن‬
‫شيفرة ‪ urllib‬تتجاهلها وتعيد فقط محتوى امللف‪.‬‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪199‬‬
‫‪But soft what light through yonder window breaks‬‬
‫‪It is the east and Juliet is the sun‬‬
‫‪Arise fair sun and kill the envious moon‬‬
‫‪Who is already sick and pale with grief‬‬
‫على سبيل املثال‪ ،‬يمكننا كتابة برنامج السترداد البيانات الخاصة بـ ‪ romeo.txt‬وحساب تكرار كل‬
‫كلمة في امللف على النحو التالي‪:‬‬
‫‪import urllib.request, urllib.parse, urllib.error‬‬
‫)'‪fhand = urllib.request.urlopen('http://data.pr4e.org/romeo.txt‬‬
‫)(‪counts = dict‬‬
‫‪for line in fhand:‬‬
‫)(‪words = line.decode().split‬‬
‫‪for word in words:‬‬
‫‪counts[word] = counts.get(word, 0) + 1‬‬
‫)‪print(counts‬‬
‫‪# Code: http://www.py4e.com/code3/urlwords.py‬‬
‫من جديد‪ ،‬بمجرد أن نفتح صفحة الويب بإمكاننا قراءتها كملف محلي (متوفر على جهازك)‪.‬‬
‫ُ ّ‬
‫شفرة ً‬
‫ثنائيا باستخدام ‪urllib‬‬
‫‪ 5.12‬قراءة امللفات امل‬
‫قد ترغب ً‬
‫أحيانا في استعادة ملف غير نص ي مرمز ً‬
‫ثنائيا (‪ )binary‬مثل صورة أو فيديو‪.‬‬
‫ً ُ‬
‫عموما‪ ،‬تعتبر البيانات املوجودة في هذه امللفات غير ُمفيدة عند عرضها على الخرج‪ .‬لكنك ببساطة‬
‫تستطيع إنشاء نسخة من عنوان ‪ URL‬إلى ملف محلي على قرصك الصلب باستخدام ‪.urllib‬‬
‫ُ‬
‫اإلجراء املتبع هنا هو فتح عنوان ‪ URL‬واستعمال التعليمة ‪ read‬لتخزين جميع محتويات امللف في‬
‫ُمتغير من نوع سلسلة نصية وليكن اسمه ‪ img‬ثم اكتب تلك املعلومات في ملف محلي كما هو موضح‬
‫في الشيفرة التالية‪:‬‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪200‬‬
‫‪import urllib.request, urllib.parse, urllib.error‬‬
‫)(‪img = urllib.request.urlopen('http://data.pr4e.org/cover3.jpg').read‬‬
‫)'‪fhand = open('cover3.jpg', 'wb‬‬
‫)‪fhand.write(img‬‬
‫)(‪fhand.close‬‬
‫‪# Code: http://www.py4e.com/code3/curl1.py‬‬
‫يقرأ هذا البرنامج جميع البيانات دفعة واحدة ُويخزنها في املتغير ‪ img‬في الذاكرة الرئيسية لحاسوبك‪.‬‬
‫ثم يفتح امللف ‪ cover.jpg‬ويكتب البيانات على قرصك الصلب‪.‬‬
‫يفتح الوسيط ‪ wb‬في التابع )(‪ً open‬‬
‫ملفا ً‬
‫ثنائيا للكتابة فقط مع العلم أن هذا البرنامج يعمل في حال‬
‫كان حجم امللف أقل من حجم ذاكرة حاسوبك‪.‬‬
‫أما في حال كان الفيديو أو امللف الصوتي ذو حجم كبير‪ ،‬فإن البرنامج قد يتوقف‪ ،‬أو على أقل تقدير‬
‫سوف يعمل ببطء شديد بينما تنفد ذاكرة حاسوبك‪.‬‬
‫سعيا ُّ‬
‫ً‬
‫لتجنب نفاد الذاكرة‪ ،‬فإننا نسترجع البيانات ككتل ثم نكتب كل كتلة بيانات على القرص قبل‬
‫استعادة الكتلة التالية‪ .‬بهذه الطريقة يستطيع البرنامج قراءة أي ملف مهما كان حجمه دون استهالك‬
‫الذاكرة املوجودة في حاسوبك‪.‬‬
‫‪import urllib.request, urllib.parse, urllib.error‬‬
‫)'‪img = urllib.request.urlopen('http://data.pr4e.org/cover3.jpg‬‬
‫)'‪fhand = open('cover3.jpg', 'wb‬‬
‫‪size = 0‬‬
‫‪while True:‬‬
‫)‪info = img.read(100000‬‬
‫‪if len(info) < 1: break‬‬
‫)‪size = size + len(info‬‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪201‬‬
‫)‪fhand.write(info‬‬
‫)'‪print(size, 'characters copied.‬‬
‫)(‪fhand.close‬‬
‫‪# Code: http://www.py4e.com/code3/curl2.py‬‬
‫حرف ً‬
‫في هذا املثال‪ ،‬نقرأ فقط ‪ 100,000‬م َ‬
‫معا ثم نكتب هذه املحارف في ملف ‪ cover.jpg‬قبل‬
‫استعادة الـ ‪ 100,000‬محرف التالية من الويب‪ .‬حيث يظهر خرج البرنامج على النحو التالي‪:‬‬
‫‪python curl2.py‬‬
‫‪230210 characters copied.‬‬
‫‪ 6.12‬تحليل واستخراج البيانات من صفحات ‪HTML‬‬
‫ُ‬
‫تعتبر عملية استخراج البيانات من صفحات الويب أحد االستخدامات الشائعة ملكتبة ‪ urllib‬في لغة‬
‫بايثون‪.‬‬
‫ً‬
‫برنامجا يتصرف ُ‬
‫كمتصفح‬
‫يتمثل مفهوم استكشاف أو تعقب الويب (‪ )Web scraping‬عندما نكتب‬
‫ً‬
‫إنترنت ويقوم باسترجاع الصفحات‪ ،‬ثم يفحص البيانات املوجودة في تلك الصفحات بحثا عن أنماط‬
‫ما‪.‬‬
‫كمثال على ذلك‪ ،‬تعاين محركات البحث مثل غوغل ‪ Google‬مصدر صفحة ويب ما لتستخرج روابط‬
‫الصفحات األخرى ثم تستعيد هذه الصفحات ومن ثم تعود لتستخرج الروابط وهكذا‪..‬‬
‫بفضل هذه التقنية‪ ،‬يستطيع غوغل الوصول إلى كل الصفحات في الويب ً‬
‫تقريبا‪.‬‬
‫يستخدم غوغل ً‬
‫أيضا معدل تكرار رابط صفحة ما في باقي الصفحات على أنها معيار ملدى "أهمية"‬
‫الصفحة ولتحديد ترتيبها في قائمة نتائج البحث‪.‬‬
‫‪ 7.12‬تحليل صفحات ‪ HTML‬باستخدام التعابيرالنمطية‬
‫يعتبر استخدام التعابير النمطية أحد األساليب البسيطة لتحليل صفحات ‪ HTML‬وخاصة ألجل‬
‫عمليات البحث املتكررة واستخراج سالسل نصية فرعية التي تتطابق مع نمط معين‪.‬‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪202‬‬
‫فيما يلي صفحة ويب بسيطة‪:‬‬
‫>‪<h1>The First Page</h1‬‬
‫>‪<p‬‬
‫‪If you like, you can switch to the‬‬
‫>"‪<a href="http://www.dr-chuck.com/page2.htm‬‬
‫‪Second Page</a>.‬‬
‫>‪</p‬‬
‫ُيمكننا إنشاء تعبير نمطي الستخراج الرابط من النص أعاله على النحو التالي‪:‬‬
‫"?‪href="http[s]?://.+‬‬
‫يبحث هذا التعبير النمطي عن السالسل النصية التي تبدأ بـ ‪ href="http://‬أو ‪href="https://‬‬
‫ُ‬
‫متبوعة بمحرف أو أكثر ?‪ .+‬ثم بعالمة اقتباس أخرى‪ .‬كما تشير عالمة االستفهام في التعبير ?]‪ [s‬إلى‬
‫البحث عن السلسلة ‪ http‬متبوعة بـ صفر أو واحد ‪( s‬أي وجود ‪ s‬واحدة أو عدمها)‪.‬‬
‫ً‬
‫ُ‬
‫عالمة االستفهام في ?‪ .+‬تشير إلى أن التطابق سيكون من النمط غير املتعدي بدال من النمط املتعدي‬
‫(‪ )Pushy‬حيث يسعى النمط غير املتعدي إليجاد أصغر سلسلة نصية مطابقة ممكنة‪ ،‬بينما يسعى‬
‫النمط املتعدي إلى العثور على أكبر سلسلة نصية مطابقة ممكنة‪.‬‬
‫ُ‬
‫سنضيف األقواس إلى التعبير النمطي لإلشارة إلى الجزء الذي نريد استخراجه من السلسلة املطابقة‪.‬‬
‫ليصبح البرنامج كالتالي‪:‬‬
‫‪# Search for link values within URL input‬‬
‫‪import urllib.request, urllib.parse, urllib.error‬‬
‫‪import re‬‬
‫‪import ssl‬‬
‫‪# Ignore SSL certificate errors‬‬
‫)(‪ctx = ssl.create_default_context‬‬
‫ البرامج املرتبطة بالشبكات‬:‫الفصل الثاني عشر‬
203
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
url = input('Enter - ')
html = urllib.request.urlopen(url, context=ctx).read()
links = re.findall(b' href="(http[s]?://.*?)" ', html)
for link in links:
print(link.decode())
# Code: http://www.py4e.com/code3/urlregex.py
.HTTPS ‫ لهذا البرنامج بالوصول إلى مواقع الويب التي تستخدم بروتوكول‬ssl ‫تسمح مكتبة‬
ً
‫ كسلسلة من البايت بدال من إرجاعها ككائن‬HTML ‫ الشيفرة املصدرية لـ‬read ‫ٌيرجع التابع‬
.HTTPResponse
‫ حيث يعيد فقط الرابط‬،‫ قائمة من السالسل النصية املطابقة لتعبيرنا النمطي‬findall ‫يعيد التابع‬
.‫بين عالمتي االقتباس املزدوجة‬
:‫عند تشغيل البرنامج وإدخال رابط ما نحصل على الخرج التالي‬
Enter - https://docs.python.org
https://docs.python.org/3/index.html
https://www.python.org/
https://docs.python.org/3.8/
https://docs.python.org/3.7/
https://docs.python.org/3.5/
https://docs.python.org/2.7/
https://www.python.org/doc/versions/
https://www.python.org/dev/peps/
https://wiki.python.org/moin/BeginnersGuide
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪204‬‬
‫‪https://wiki.python.org/moin/PythonBooks‬‬
‫‪https://www.python.org/doc/av/‬‬
‫‪https://www.python.org/‬‬
‫‪https://www.python.org/psf/donations/‬‬
‫‪http://sphinx.pocoo.org/‬‬
‫تعمل التعابير النمطية بشكل رائع للغاية عندما تكون الشيفرة املصدرية لصفحة ال ‪ HTML‬مكتوبة‬
‫نظرا لوجود الكثير من صفحات ‪ HTML‬غير املنسقة ً‬
‫بشكل منسق وقابل ُّ‬
‫للتنبؤ‪ .‬لكن ً‬
‫جيدا فإن هذا‬
‫الحل (أي استخدام التعابير النمطية) قد يتسبب بفقدان بعض الروابط املتاحة أو الحصول على‬
‫بيانات غير مفيدة‪ُ .‬يمكن حل هذه املشكلة باستخدام مكتبة خاصة للتعامل مع صفحات ‪.HTML‬‬
‫‪ 8.12‬تحليل صفحات ‪ HTML‬باستخدام مكتبة ‪BeautifulSoup‬‬
‫على الرغم من أن صفحات ‪ HTML‬تبدو ُمشابهة لـ ‪( XML‬سيتم شرح ماهية ‪ XML‬في الفصل القادم)‬
‫وبعض الصفحات مبنية على أساس ‪ ،XML‬إال أن معظم صفحات ‪ HTML‬تكون غير منسقة ً‬
‫جيدا‪،‬‬
‫األمر الذي يؤدي إلى رفض برمجية "‪ "XML parser‬صفحة ‪ HTML‬بأكملها بسبب تنسيقها غير‬
‫الصحيح‪.‬‬
‫يوجد العديد من املكتبات في لغة بايثون ملساعدتك في تحليل صفحات ‪ HTML‬واستخراج البيانات‬
‫منها‪ُ .‬كل مكتبة من هذه املكتبات تمتلك نقاط قوة ونقاط ضعف وتستطيع اختيار املكتبة ً‬
‫بناء على‬
‫احتياجاتك‪.‬‬
‫كمثال على ذلك‪ُ ،‬‬
‫سنحلل ببساطة بعض مدخالت ‪ HTML‬وسنستخرج الروابط باستخدام مكتبة‬
‫‪.BeautifulSoup‬‬
‫تتساهل مكتبة ‪ BeautifulSoup‬مع صفحات ‪ HTML‬التي تحوي ً‬
‫عيوبا كثيرة وتسمح لك باستخراج‬
‫البيانات التي تحتاجها بسهولة‪ .‬بإمكانك تحميل وتنصيب شيفرة البرنامج من الرابط‪:‬‬
‫‪https://pypi.python.org/pypi/beautifulsoup4‬‬
‫ً‬
‫اختصارا "‪ "pip‬معلومات تنصيب مكتبة‬
‫تتيح أداة فهرسة حزم بايثون (‪)Python Package Index‬‬
‫‪ BeautifulSoup‬في الرابط التالي‪:‬‬
‫‪https://packaging.python.org/tutorials/installing-packages/‬‬
205
‫ البرامج املرتبطة بالشبكات‬:‫الفصل الثاني عشر‬
‫ من‬href ‫ الستخراج الخاصية‬BeautifulSoup ‫ لقراءة الصفحة ثم نستخدم‬urllib ‫سنستخدم مكتبة‬
.<a> ‫الوسم‬
# To run this, download the BeautifulSoup zip file
# http://www.py4e.com/code3/bs4.zip
# and unzip it in the same directory as this file
import urllib.request, urllib.parse, urllib.error
from bs4 import BeautifulSoup
import ssl
# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
url = input('Enter - ')
html = urllib.request.urlopen(url, context=ctx).read()
soup = BeautifulSoup(html, 'html.parser')
# Retrieve all of the anchor tags
tags = soup('a')
for tag in tags:
print(tag.get('href', None))
# Code: http://www.py4e.com/code3/urllinks.py
‫ بعدها ُيمرر هذه البيانات‬،‫ ثم يفتح صفحة الويب ويقرأ البيانات‬،‫يطلب البرنامج عنوان صفحة ويب‬
.‫ لكل وسم‬href ‫< ليطبع قيمة الخاصية‬a> ‫ ثم يسترجع كل وسوم‬،BeautifulSoup ‫إلى ُمحلل مكتبة‬
:‫عندما نشغل البرنامج فإنه ُينتج الخرج التالي‬
206
Enter - https://docs.python.org
genindex.html
py-modindex.html
https://www.python.org/
#
whatsnew/3.6.html
whatsnew/index.html
tutorial/index.html
library/index.html
reference/index.html
using/index.html
howto/index.html
installing/index.html
distributing/index.html
extending/index.html
c-api/index.html
faq/index.html
py-modindex.html
genindex.html
glossary.html
search.html
contents.html
bugs.html
about.html
license.html
copyright.html
‫ البرامج املرتبطة بالشبكات‬:‫الفصل الثاني عشر‬
‫ البرامج املرتبطة بالشبكات‬:‫الفصل الثاني عشر‬
207
download.html
https://docs.python.org/3.8/
https://docs.python.org/3.7/
https://docs.python.org/3.5/
https://docs.python.org/2.7/
https://www.python.org/doc/versions/
https://www.python.org/dev/peps/
https://wiki.python.org/moin/BeginnersGuide
https://wiki.python.org/moin/PythonBooks
https://www.python.org/doc/av/
genindex.html
py-modindex.html
https://www.python.org/
#
copyright.html
https://www.python.org/psf/donations/
bugs.html
http://sphinx.pocoo.org/
(relative path) ‫ هي مسارات نسبية‬HTML ‫< في‬a> ‫هذه القائمة أطول بكثير مما أردنا ألن بعض وسوم‬
ً
‫" أو‬http://" ‫') التي ال تتضمن‬#' :‫) أو مراجع داخلية (مثال‬tutorial/index.html :‫(على سبيل املثال‬
.‫" والذي كان أحد املتطلبات في تعبيرنا النمطي‬https://"
ً ‫يمكنك‬
:‫ الستخراج أجزاء أخرى من أي وسم‬BeautifulSoup ‫أيضا استخدام‬
# To run this, download the BeautifulSoup zip file
# http://www.py4e.com/code3/bs4.zip
# and unzip it in the same directory as this file
from urllib.request import urlopen
208
‫ البرامج املرتبطة بالشبكات‬:‫الفصل الثاني عشر‬
from bs4 import BeautifulSoup
import ssl
# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
url = input('Enter - ')
html = urlopen(url, context=ctx).read()
soup = BeautifulSoup(html, "html.parser")
# Retrieve all of the anchor tags
tags = soup('a')
for tag in tags:
# Look at the parts of a tag
print('TAG:', tag)
print('URL:', tag.get('href', None)
print('Contents:', tag.contents[0])
print('Attrs:', tag.attrs)
# Code: http://www.py4e.com/code3/urllink2.py
:‫فيكون الخرج‬
python urllink2.py
Enter - http://www.dr-chuck.com/page1.htm
TAG: <a href="http://www.dr-chuck.com/page2.htm">
Second Page</a>
URL: http://www.dr-chuck.com/page2.htm
Content: ['\nSecond Page']
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪209‬‬
‫])'‪Attrs: [('href', 'http://www.dr-chuck.com/page2.htm‬‬
‫إن املحلل "‪ "html.parser‬هو محلل ‪ HTML‬املتضمن في مكتبة ‪ Python 3‬املعيارية‪.‬‬
‫تستطيع الحصول على معلومات عن محلالت ‪ HTML‬أخرى عبر الرابط‪:‬‬
‫‪http://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser‬‬
‫ُ‬
‫تظهر هذه األمثلة مدى قوة مكتبة ‪ BeautifulSoup‬عندما يتعلق األمر بتحليل صفحات ‪.HTML‬‬
‫ُ‬
‫ُ‬
‫‪ 9.12‬ميزات خاصة ملستخدمي أنظمة لينكس أو يونيكس‬
‫إذا كان لديك حاسوب يعمل بنظام تشغيل ُ‬
‫لينكس (‪ )Linux‬أو يونيكس (‪ (Unix‬أو ماكنتوش‬
‫)‪ (Macintosh‬فعلى األرجح أنك تمتلك أوامر جاهزة في نظام التشغيل‪ .‬حيث تسترجع هذه األوامر‬
‫النصوص وامللفات املرمزة ً‬
‫ثنائيا باستعمال بروتوكول نقل النص التشعبي ‪ HTTP‬أو بروتوكول نقل‬
‫امللفات ‪ .)FTP) File Transfer Protocol‬وأحد هذه األوامر هو ‪:curl‬‬
‫‪$ curl -O http://www.py4e.com/cover.jpg‬‬
‫إن األمر ‪ curl‬هو اختصار للتعبير ‪.copy URL‬‬
‫ُ‬
‫إن املثالين الذين ُذكرا ً‬
‫سابقا السترجاع امللفات املرمزة ً‬
‫ثنائيا باستخدام ‪ urllib‬أطلق عليهما ‪curl1.py‬‬
‫َو ‪ curl2.py‬على املوقع ‪ www.py4e.com/code3‬حيث ُينفذان وظائف مشابهة لألمر ‪.curl‬‬
‫ُهناك ً‬
‫أيضا البرنامج ‪ curl3.py‬الذي ُينجز هذه املهمة بفعالية أكبر‪ ،‬في حال كنت تريد استخدام هذا‬
‫النمط في البرنامج الذي تكتبه‪.‬‬
‫األمر الثاني الذي يؤدي الوظيفة بشكل مشابه هو ‪:wget‬‬
‫‪$ wget http://www.py4e.com/cover.jpg‬‬
‫كال األمرين يسهالن عملية استرجاع صفحات الويب وامللفات غير املخزنة ً‬
‫محليا‪.‬‬
‫‪ 10.12‬فهرس املصطلحات‬
‫• مكتبة ‪ :BeautifulSoup‬مكتبة في لغة بايثون نستخدمها لتحليل صفحات ‪HTML‬‬
‫ً‬
‫واستخراج البيانات منها والتي عادة ما يتجاهلها املتصفح‪ .‬بإمكانك تحميل شيفرة مكتبة‬
‫‪ BeautifulSoup‬من املوقع ‪www.crummy.com‬‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪210‬‬
‫َ‬
‫• املنفذ )‪ :(Port‬رقم ُيشير بشكل عام إلى التطبيق املتصل به عندما تقوم بإجراء اتصال عبر‬
‫ً‬
‫مآخذ الشبكة مع الخادم‪ .‬كمثال على ذلك‪ُ :‬يستخدم عادة املنفذ ‪ 80‬في عملية إرسال‬
‫واستقبال البيانات عبر الويب‪ ،‬بينما للبريد اإللكتروني يستخدم املنفذ ‪.25‬‬
‫• استكشاف أو تعقب الويب )‪ :(Scrape‬عندما يتظاهر البرنامج بأنه متصفح ويب ويسترجع‬
‫ً‬
‫صفحة ويب‪ ،‬ثم ُيعاين محتواها‪ .‬تتبع البرامج عادة الروابط املوجودة في صفحة واحدة‬
‫للعثور على الصفحة التالية لذلك بإمكانهم املرور على شبكة من الصفحات أو على شبكة‬
‫اجتماعية‪.‬‬
‫• مآخذ الشبكة )‪ :(Socket‬اتصال شبكي بين تطبيقين‪ ،‬حيث ُيتاح للتطبيقات تبادل البيانات‬
‫في كال االتجاهين (إرسال واستقبال)‪.‬‬
‫ٌ‬
‫• املتعقب )‪ :(Spider‬عندما يقوم محرك البحث باستعادة صفحة ثم كل الصفحات املرتبطة‬
‫بهذه الصفحة وهكذا حتى يصل ً‬
‫تقريبا إلى كل الصفحات في اإلنترنت‪ ،‬حيث يتم استخدام‬
‫هذا في بناء فهرس البحث‪.‬‬
‫‪ 11.12‬تمارين‬
‫• التمرين ّ‬
‫األول‪ :‬عدل البرنامج ‪ socket1.py‬بحيث يطلب عنوان ‪ URL‬من املستخدم ليتمكن‬
‫َ‬
‫البرنامج من الوصول إلى أي صفحة ويب‪ُ .‬يمكنك استخدام التابع ('‪ split)'/‬من أجل تجزئة‬
‫ُ‬
‫عنوان ‪ URL‬إلى مكوناته بحيث تتمكن من استخراج اسم املضيف من أجل استدعاء التابع‬
‫‪ .connect‬أضف ميزة تجنب األخطاء باستخدام تعليمتي ‪َ try‬و‪ except‬للتعامل مع الحالة التي‬
‫ُيدخل بها املستخدم روابط ‪ URL‬خاطئة أو غير موجودة‪.‬‬
‫• التمرين الثاني‪ :‬عدل البرنامج السابق بحيث يحسب عدد املحارف التي استقبلها‪ ،‬ثم يتوقف‬
‫َ‬
‫ُ‬
‫عن إظهار أي نص بعد عرض ‪ 3000‬محرف‪ .‬يجب على البرنامج استعادة املستند بالكامل‬
‫وحساب العدد اإلجمالي للمحارف وعرضه في نهاية املستند‪.‬‬
‫• التمرين الثالث‪ :‬استخدم مكتبة ‪ urllib‬لتكرار التمرين السابق من أجل‪ )1( :‬استعادة‬
‫ُ‬
‫ُ‬
‫املستند من عنوان ‪ (2) ،URL‬عرض قرابة الـ ‪ 3000‬محرف‪ (3) ،‬حساب العدد اإلجمالي‬
‫للمحارف في املستند‪ .‬ال تقلق بشأن الترويسة في هذا التمرين‪ ،‬ما عليك سوى إظهار أول‬
‫الفصل الثاني عشر‪ :‬البرامج املرتبطة بالشبكات‬
‫‪211‬‬
‫‪ 3000‬محرف من محتويات املستند‪.‬‬
‫ُ‬
‫• التمرين الرابع‪ :‬قم بتعديل برنامج ‪ urllinks.py‬الستخراج وحساب وسوم الفقرات >‪ <p‬من‬
‫ُمستند ‪ HTML‬الذي تم استعادته‪ ،‬ثم اعرض عدد الفقرات كخرج لبرنامجك‪.‬‬
‫ال تعرض َنص الفقرة بل قم بإحصائهم فقط‪َ .‬‬
‫اختبر البرنامج على عدة صفحات ويب صغيرة‬
‫باإلضافة إلى بعض صفحات الويب الكبيرة‪.‬‬
‫• التمرين الخامس‪(ُ :‬متقدم)‬
‫غير برنامجك ‪ socket1.py‬بحيث يعرض البيانات فقط بعد استقبال الترويسة وسطر فارغ‪.‬‬
‫تذكر أن التابع ‪ recv‬يستقبل البيانات كمحارف (محرف السطر الجديد أحدها) وليس‬
‫كأسطر‪.‬‬
‫الفصل الثالث عشر‬
‫استخدام خدمات الويب‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪213‬‬
‫‪ 13‬استخدام خدمات الويب‬
‫ً‬
‫لم يستغرق األمر طويال لتطوير منهجية إلنشاء ملفات صممت لتستخدمها برامج أخرى (مثال‪ :‬فتح‬
‫صفحة غير مبنية باستخدام ‪ HTML‬بواسطة املتصفح) بعد أن أصبحت عملية استدعاء امللفات‬
‫وتحليلها سهلة التنفيذ عبر برامج تستخدم برتوكول ‪ ،HTTP‬حيث يوجد صيغتين نستخدمهما عند‬
‫تبادل البيانات عبر الويب‪ ،‬أولها لغة التوصيف املوسعة ‪ ،XML‬والتي استخدمت لزمن طويل وتعتبر‬
‫األنسب لتبادل البيانات على شكل ملفات‪ ،‬بينما تستخدم البرامج ترميز جافا سكربت الغرض ي‬
‫‪( JSON‬للمزيد تصفح املوقع ‪ )www.json.org‬لتبادل القواميس والقوائم فيما بينها أو أي معلومات‬
‫داخلية‪ ،‬وسنشرح كلتا الصيغتين‪.‬‬
‫‪ 1.13‬لغة التوصيف املوسعة ‪XML‬‬
‫ً‬
‫تنظيما‪ ،‬ونرى هذا في املثال اآلتي‪:‬‬
‫تشبه ‪ XML‬الـ ‪ HTML‬ولكنها أكثر‬
‫>‪<person‬‬
‫>‪<name> Chuck </name‬‬
‫>"‪<phone type="intl‬‬
‫‪+1 734 303 4456‬‬
‫>‪</phone‬‬
‫>‪<email hide="yes" /‬‬
‫>‪</person‬‬
‫كما نالحظ‪ ،‬يمثل كل زوج من وسوم االفتتاح مثل <‪ >person‬واإلغالق مثل <‪ >/person‬عنصر أو‬
‫عقدة (‪ )Node‬بنفس اسم الوسم مثل ‪ ،person‬ويمكن أن يكون لكل عنصر نص معين أو‬
‫خصائص "سمات" مثل ‪ hide‬وعناصر متداخلة أخرى‪ ،‬وإذا كان العنصر فارغ بال محتوى فيمكن‬
‫أن ٌيغلق ً‬
‫ذاتيا مثل <‪ ،<email /‬أي من املفيد أن تنظر إلى ملف ‪ XML‬على أنه ذو بنية شجرية‪ ،‬حيث‬
‫يوجد عنصر رئيس في مثالنا السابق ‪ person‬ووسوم أخرى مثل ‪ phone‬وكأنها فروع من العناصر‬
‫الرئيسية (األبوية)‪.‬‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪214‬‬
‫الشكل ‪ :14‬تمثيل شجري للغة‪XML‬‬
‫‪ 2.13‬تحليل نصوص ‪XML‬‬
‫فيما يلي تطبيق عن تحليل نص ‪ XML‬واستخراج بعض عناصر البيانات منه‪:‬‬
‫‪import xml.etree.ElementTree as ET‬‬
‫' ' ' = ‪data‬‬
‫>‪<person‬‬
‫>‪<name>Chuck</name‬‬
‫>"‪<phone type="intl‬‬
‫‪+1 734 303 4456‬‬
‫>‪</phone‬‬
‫>‪<email hide="yes" /‬‬
‫' ' ' >‪</person‬‬
‫)‪tree = ET.fromstring(data‬‬
‫)‪print('Name: ', tree.find('name').text‬‬
‫))'‪print('Attr: ', tree.find('email').get('hide‬‬
‫‪# Code: http://www.py4e.com/code3/xml1.py‬‬
‫تسمح إشارات التنصيص (االقتباس) األحادية واملزدوجة الثالثية (' ' ' و""") بإنشاء سالسل نصية‬
‫تمتد على عدة أسطر‪ ،‬كما أن استدعاء ‪ fromstring‬يحول السالسل النصية في ‪ XML‬إلى شجرة من‬
‫العناصر‪ ،‬فعندما تكون ‪ XML‬في نمط شجرة يكون لدينا عدة توابع يمكننا استدعاؤها الستخراج‬
‫أجزاء من البيانات من السالسل النصية‪ ،‬أما التابع ‪ find‬فيبحث في شجرة ‪ XML‬عن الوسم‬
‫املطابق ملا حدد ضمنه ويستدعيه‪.‬‬
‫ استخدام خدمات الويب‬:‫الفصل الثالث عشر‬
215
Name: Chuck
Attr: yes
‫ بدون القلق حول‬XML ‫ باستخراج البيانات من‬ElementTree ‫ مثل‬XML ‫يسمح لنا محلل نصوص‬
.‫ والتي تتوضح لنا في املثال السابق البسيط الذي عرضناه‬،‫القواعد الكتابية لها‬
‫ استخدام الحلقات للمرورعلى العقد‬3.13
ً
‫ كما في البرنامج‬،‫ عدة عقد حيث نحتاج لكتابة حلقة ملعالجة كل تلك العقد‬XML ‫عادة ما تحوي‬
:user ‫اآلتي حيث نمر على كل عقد املستخدم‬
import xml.etree.ElementTree as ET
input = ' ' '
<stuff>
<users>
<user x="2">
<id>001</id>
<name>Chuck</name>
</user>
<user x="7">
<id>009</id>
<name>Brent</name>
</user>
</users>
</stuff>' ' '
stuff = ET.fromstring(input)
lst = stuff.findall('users/user')
print('User count:', len(lst))
for item in lst:
print('Name', item.find('name').text)
print('Id', item.find('id').text)
print('Attribute', item.get('x'))
# Code: http://www.py4e.com/code3/xml2.py
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪216‬‬
‫ٌيرجع التابع ‪ findall‬قائمة مكونة من تفرعات تمثل بنية الوسم ‪ user‬في شجرة ‪ ،XML‬نكتب بعدها‬
‫ً‬
‫حلقة ‪ for‬تمر على كل عقدة من عقد الوسم ‪ user‬وتطبع العناصر النصية ‪ name‬و‪ id‬إضافة إلى‬
‫الخاصية ‪ x‬من عقدة الوسم ‪:user‬‬
‫‪User count: 2‬‬
‫‪Name Chuck‬‬
‫‪Id 001‬‬
‫‪Attribute 2‬‬
‫‪Name Brent‬‬
‫‪Id 009‬‬
‫‪Attribute 7‬‬
‫ومن املهم تضمين جميع العناصر الرئيسية (األبوية) في تعليمة ‪( findall‬مثل ‪ )users/user‬باستثناء‬
‫أي من العقد املطلوبة‪:‬‬
‫عند التعامل مع عناصر املستوى الرئيس ي األول وإال لن تجد بايثون ٍ‬
‫‪import xml.etree.ElementTree as ET‬‬
‫' ' ' = ‪input‬‬
‫>‪<stuff‬‬
‫>‪<users‬‬
‫>"‪<user x="2‬‬
‫>‪<id>001</id‬‬
‫>‪<name>Chuck</name‬‬
‫>‪</user‬‬
‫>"‪<user x="7‬‬
‫>‪<id>009</id‬‬
‫>‪<name>Brent</name‬‬
‫>‪</user‬‬
‫>‪</users‬‬
‫' ' ' >‪</stuff‬‬
‫)‪stuff = ET.fromstring(input‬‬
‫)'‪lst = stuff.findall('users/user‬‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪217‬‬
‫))‪print('User count:', len(lst‬‬
‫)'‪lst2 = stuff.findall('user‬‬
‫))‪print('User count:', len(lst2‬‬
‫تخزن القائمة ‪ lst‬كل عناصر الوسم ‪ user‬املضمنة في الوسم ‪ ،users‬بينما تبحث ‪ lst2‬عن عناصر‬
‫الوسم ‪ user‬املضمنة في وسم املستوى األول ‪ stuff‬لكن ال تجد ًأيا منها‪.‬‬
‫‪User count: 2‬‬
‫‪User count: 0‬‬
‫‪JSON 4.13‬‬
‫ُ‬
‫استوحت هذه الصيغة من الصيغة الغرضية واملصفوفية في لغة جافا سكربت‪ ،‬إال أن قواعد كتابة‬
‫بايثون فيما يتعلق بالقواميس والقوائم أثرت على قواعد ‪ JSON‬باعتبار أنها ُوجدت قبل جافا‬
‫سكربت‪ ،‬لذلك تعتبر هذه الصيغة خليط من قوائم وقواميس بايثون‪ ،‬وفيما يأتي مثال عن ترميز‬
‫‪ JSON‬مكافئ لبرنامج ‪ XML‬املذكور ً‬
‫سابقا‪:‬‬
‫{‬
‫‪"name" : "Chuck",‬‬
‫{ ‪"phone" :‬‬
‫‪"type" : "intl",‬‬
‫"‪"number" : "+1 734 303 4456‬‬
‫‪},‬‬
‫{ ‪"email" :‬‬
‫"‪"hide" : "yes‬‬
‫}‬
‫}‬
‫قد تالحظ بعض الفروق ففي ‪ XML‬نستطيع إضافة السمة ‪ intl‬إلى الوسم ‪ phone‬بينما لدينا أزواج‬
‫ُ‬
‫مفتاح‪-‬قيمة في ‪ JSON‬كما يختفي الوسم ‪ person‬هنا فقد استبدل باألقواس الخارجية‪.‬‬
‫ً‬
‫عموما‪ ،‬فإن بنية ‪ JSON‬أبسط من بنية ‪ XML‬حيث تملك إمكانيات أقل‪ ،‬ولكن تملك األفضلية من‬
‫حيث االرتباط مباشرة مع تركيبة القواميس والقوائم‪ ،‬كما أنها صيغة بسيطة لجعل برنامجين‬
‫ً‬
‫يعمالن ً‬
‫معا ويتبادالن البيانات باعتبار أن جميع لغات البرمجة ً‬
‫مكافئا لقواميس وقوائم‬
‫تقريبا تملك‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪218‬‬
‫ً‬
‫إضافة إلى أنها سرعان ما أصبحت ً‬
‫خيارا لصيغة معظم عمليات تبادل البيانات بين‬
‫بايثون‪،‬‬
‫ً‬
‫التطبيقات بسبب بساطتها مقارنة مع ‪.XML‬‬
‫‪ 5.13‬تحليل نصوص ‪JSON‬‬
‫ننش ئ ملفات ‪ JSON‬بترتيب القواميس والقوائم داخل بعضهم البعض كما نحتاج‪ ،‬وفي هذا املثال‬
‫نمثل قائمة مستخدمين بحيث يكون كل مستخدم عبارة عن مجموعة من أزواج مفتاح‪-‬قيمة (أي‬
‫قاموس) أي لدينا قائمة من القواميس‪ ،‬كما سنستخدم مكتبة جاهزة لتحليل نص ‪ JSON‬وقراءة‬
‫البيانات‪ ،‬وبإمكانك إجراء املقارنة مع املثال السابق في ‪ ،XML‬حيث ‪ JSON‬تحوي تفاصيل أقل أي‬
‫ً‬
‫مسبقا أننا سنحصل على قائمة تمثل املستخدمين حيث كل مستخدم هو مجموعة‬
‫يجب أن نعلم‬
‫من أزواج مفتاح‪-‬قيمة فـ ‪ JSON‬أكثر ً‬
‫إيجازا (وهي نقطة إيجابية) ولكنها صعبة التوصيف الذاتي‬
‫(وهذه سلبية)‪:‬‬
‫‪import json‬‬
‫' ' '= ‪data‬‬
‫[‬
‫‪{ "id" : "001",‬‬
‫‪"x" : "2",‬‬
‫"‪"name" : "Chuck‬‬
‫‪},‬‬
‫‪{ "id" : "009",‬‬
‫‪"x" : "7",‬‬
‫"‪"name" : "Brent‬‬
‫}‬
‫''']‬
‫)‪info = json.loads(data‬‬
‫))‪print('User count:', len(info‬‬
‫‪for item in info:‬‬
‫)]'‪print('Name', item['name‬‬
‫)]'‪print('Id', item['id‬‬
‫)]'‪print('Attribute', item['x‬‬
‫‪# Code: http://www.py4e.com/code3/json2.py‬‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪219‬‬
‫إذا قارنت شيفرة استخراج البيانات بين ‪ XML‬و‪ JSON‬فستالحظ أننا نحصل من التابع‬
‫ً‬
‫قاموسا‪،‬‬
‫()‪ json.loads‬على قائمة نمر على عناصرها بحلقة ‪ for‬ويمثل كل عنصر في تلك القائمة‬
‫ونستطيع استخدام عامل الفهرس الستخراج البيانات املختلفة لكل مستخدم بمجرد تحليل نص‬
‫‪ ،JSON‬كما لسنا مضطرين الستخدام مكتبة ‪ JSON‬إلجراء عملية التحليل باعتبار أن بنية البيانات‬
‫هي بنية معروفة لبايثون‪ ،‬ويكون خرج هذا البرنامج مطابق لخرج البرنامج السابق في ‪ XML‬وهو‪:‬‬
‫‪User count: 2‬‬
‫‪Name Chuck‬‬
‫‪Id 001‬‬
‫‪Attribute 2‬‬
‫‪Name Brent‬‬
‫‪Id 009‬‬
‫‪Attribute 7‬‬
‫َ‬
‫ً‬
‫عموما‪ ،‬يوجد توجه منهي نحو ‪ JSON‬بدال من ‪ XML‬فيما يتعلق بخدمات الويب‪ ،‬ألنها أبسط وتعبر‬
‫ً‬
‫عن بنى البيانات األساسية املوجودة في لغات البرمجة بشكل أكبر إضافة إلى كون عملية التحليل‬
‫واستخراج البيانات أبسط ومباشرة بشكل أكبر‪ ،‬إال أن ‪ XML‬قابلة للتوصيف الذاتي بشكل أفضل‬
‫مما يجعل استخدامها أفضلية في بعض التطبيقات‪ ،‬فعلى سبيل املثال‪ ،‬معظم معالجات النصوص‬
‫ً‬
‫ً‬
‫داخليا باستخدام ‪ XML‬بدال من ‪.JSON‬‬
‫تخزن امللفات‬
‫‪ 6.13‬واجهات برمجة التطبيقات ‪API‬‬
‫نتمتع اليوم بالقدرة على تبادل البيانات بين التطبيقات باستخدام بروتوكول ‪ HTTP‬مع طريقة‬
‫لتمثيل البيانات املعقدة املتبادلة باستخدام لغة التوصيف املوسعة ‪ XML‬أو ترميز جافا سكربت‬
‫الغرض ي ‪ ،JSON‬وتكمن الخطوة التالية في تحديد وتوثيق "االتفاقيات" بين تلك التطبيقات عبر‬
‫هذه التقنيات‪ ،‬االسم العام لهذه االتفاقيات بين التطبيقات هو واجهات برمجة التطبيقات ‪API‬‬
‫فعند استخدامها يجعل أحد البرامج مجموعة من الخدمات متاحة لتستخدمها تطبيقات أخرى‬
‫كما بنشر تلك الواجهات (أي القواعد) التي يجب اتباعها للوصول إلى الخدمات التي يقدمها‪ .‬ندعو‬
‫النهج الذي يتضمن تصميم البرامج التي تتطلب وظيفتها الوصول إلى خدمات برامج أخرى‪ ،‬باسم‬
‫البنية خدمية التوجه ‪ SOA‬أي استخدام برنامجنا النهائي لخدمات تطبيقات أخرى‪ .‬بينما يعرف نهج‬
‫البنية ال خدمية التوجه ‪ non-SOA‬بأنه تطبيق قائم بذاته يحتوي على جميع التعليمات البرمجية‬
‫الالزمة ليقدم خدماته‪.‬‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪220‬‬
‫ً‬
‫عادة نالحظ العديد من أمثلة ‪ SOA‬أثناء استخدام الويب‪ ،‬فبإمكاننا الدخول إلى موقع ما وحجز‬
‫تذكرة طيران أو إجراء حجز فندقي أو حجز سيارة من نفس املوقع‪ ،‬إال أن بيانات الفنادق غير‬
‫مخزنة على حواسيب خطوط الطيران‪ ،‬بل تتواصل هذه الحواسيب مع الخدمات على حواسيب‬
‫الفندق الستدعاء بياناته وعرضها للمستخدم‪ ،‬أي أن موقع خطوط الطيران يستخدم خدمة ويب‬
‫أخرى موجودة في أنظمة الفندق عندما يوافق املستخدم على إجراء حجز في ذلك الفندق من خالل‬
‫هذا املوقع‪ ،‬وبالتالي تدخل عدة حواسيب في هذه العملية حتى عند دفعك لألجور املستحقة‪.‬‬
‫خدمة حجز‬
‫السيارات‬
‫خدمة الحجز‬
‫الفندقي‬
‫خدمة حجز‬
‫رحلة الطيران‬
‫‪API‬‬
‫‪API‬‬
‫‪API‬‬
‫برنامج سفريات‬
‫الشكل ‪ : 15‬البنية خدمية التوجه‬
‫ومن فوائد البنى خدمية التوجه (‪:)SOA‬‬
‫ً‬
‫‪ .1‬نحتفظ بنسخة واحدة من البيانات فقط (وهذا مهم خاصة فيما يشابه حجوزات الفنادق‬
‫حيث ال يتم االلتزام ملدة طويلة)‪.‬‬
‫‪ .2‬بإمكان مالكي البيانات وضع قواعد الستخدامها‪.‬‬
‫ومع هذه الفوائد يجب أن يصمم نظام ‪ SOA‬بحذر ليتميز باألداء الجيد ويلبي حاجات املستخدم‪،‬‬
‫ويظهر هنا مصطلح خدمات الويب حيث يجعل تطبيق ما مجموعة من الخدمات في واجهته متاحة‬
‫عبر الويب‪.‬‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪221‬‬
‫‪ 7.13‬األمان واستخدام واجهات برمجة التطبيقات‬
‫من الشائع احتياجك إلى مفتاح معين الستخدام واجهة برمجة التطبيقات العائدة لشركة ما‪،‬‬
‫والهدف رغبتهم في معرفة من يستخدم خدماتهم‪ ،‬وكمية استخدامه‪ ،‬لربما لديهم خدمات مدفوعة‬
‫أو مجانية أو سياسة تحديد عدد الطلبات املتاحة للفرد خالل مدة زمنية معينة‪ ،‬وأحيانا بمجرد‬
‫حصولك على املفتاح تضمنه كجزء من بيانات رسالة ‪ POST‬أو كمعامل في الرابط (‪ )URL‬عند‬
‫استدعاء الواجهة البرمجية‪ ،‬وفي بعض األحيان تطلب الشركة ضمان أكبر فيما يتعلق بمصدر‬
‫الطلبات لهذا يطلبون منك إرسال رسائل موقعة ومشفرة باستخدام املفاتيح املشاركة‪ ،‬أما التقنية‬
‫الشائعة لتوقيع الطلبات عبر اإلنترنت فتدعى ‪ OAuth‬وبإمكانك التعرف على هذا البروتوكول عبر‬
‫الرابط ‪ ،www.oauth.net‬ولحسن الحظ توجد بعض مكتبات ‪ OAuth‬املجانية واملناسبة لتجنب‬
‫كتابة تطبيق ‪ OAuth‬من الصفر من خالل قراءة املواصفات فقط‪ .‬كما تختلف تلك املكتبات‬
‫بدرجة تعقيدها وسعتها‪ ،‬و ً‬
‫أيضا تستطيع الحصول على معلومات أكثر عن مكتبات ‪ OAuth‬من‬
‫خالل زيارة املوقع املذكور أعاله‪.‬‬
‫‪ 8.13‬فهرس املصطلحات‬
‫• واجهة برمجة التطبيقات (‪ :)API‬اتفاقية بين التطبيقات تحدد أنماط التفاعل بين‬
‫مكونات تطبيقين‪.‬‬
‫• مكتبة ‪ :ElementTree‬مكتبة برمجية مضمنة في لغة بايثون تستخدم لتحليل نصوص‬
‫‪.XML‬‬
‫ً‬
‫اعتمادا على القواعد الكتابية للكائنات في جافا‬
‫• ‪ :JSON‬صيغة تسمح بترميز بيانات مهيكلة‬
‫سكربت‪.‬‬
‫• البنى خدمية التوجه (‪ :)SOA‬مصطلح يستخدم عند بناء تطبيق من مكونات متصلة‬
‫ببعضها عبر شبكة ما‪.‬‬
‫• لغة التوصيف املوسعة (‪ :)XML‬صيغة تسمح بترميز بيانات مهيكلة‪.‬‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪222‬‬
‫‪ 9.13‬التطبيق األول‪ :‬خدمة الترميزالجغرافي من غوغل‬
‫لغوغل خدمة ذات فائدة كبرى‪ ،‬إذ تسمح لنا باستخدام قاعدة بياناتهم الضخمة الخاصة‬
‫باملعلومات الجغرافية‪ ،‬حيث نستطيع إجراء بحث جغرافي نص ي مثل "‪ "Ann Arbor, MIT‬ضمن‬
‫واجهة برمجة التطبيقات للترميز الجغرافي من غوغل لتعيد لنا أفضل تخمين للمكان التي يمكن أن‬
‫يجد فيه العنوان املطلوب على الخريطة الجغرافية ويخبرنا باملعالم املحيطة به‪ .‬هذه الخدمة‬
‫مجانية ولكنها محدودة‪ ،‬أي أن استخدامك للواجهة في التطبيقات التجارية محدود‪ ،‬ولكن إن كانت‬
‫لديك بيانات حيث يدخل املستخدم موقع ما ً‬
‫مجانا فبإمكانك استخدام هذه الواجهة للتعامل مع‬
‫البيانات بشكل جيد‪.‬‬
‫ً‬
‫يجب أن تكون معتدال عند استخدام الواجهات املجانية كواجهة غوغل للترميز الجغرافي حيث‬
‫يمكن لغوغل إلغاءها أو تقليل الخدمات املتاحة إن أساء عدد كبير من الناس استخدامها‪ ،‬كما‬
‫يمكنك قراءة توصيف تلك الخدمة على اإلنترنت وهو بسيط للغاية وتستطيع اختباره على أحد‬
‫املتصفحات بكتابة الرابط اآلتي‪:‬‬
‫‪http://maps.googleapis.com/maps/api/geocode/json?address=Ann+Arbor%2C+MI‬‬
‫ً‬
‫لكن تأكد من إزالة الفراغات منه قبل لصقه إلى املتصفح‪ ،‬وسنضع مثاال عن تطبيق يطلب من‬
‫املستخدم إدخال مكان ما لنبحث عنه ثم يستدعي واجهة الترميز الجغرافي لغوغل ليستخرج‬
‫املعلومات من ترميز ‪ JSON‬املعاد‪:‬‬
‫‪import urllib.request, urllib.parse, urllib.error‬‬
‫‪import json‬‬
‫‪import ssl‬‬
‫‪api_key = False‬‬
‫‪# If you have a Google Places API key, enter it here‬‬
‫‪# api_key = AIzaSy___IDByT70‬‬
‫‪#https://developers.google.com/maps/documentation/geocoding/intro‬‬
‫‪if api_key is False:‬‬
‫‪api_key = 42‬‬
‫' ?‪serviceurl = 'http://py4e-data.dr-chuck.net/json‬‬
‫‪else :‬‬
‫' ?‪serviceurl = ' https://maps.googleapis.com/maps/api/geocode/json‬‬
‫ استخدام خدمات الويب‬:‫الفصل الثالث عشر‬
223
# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
while True:
address = input('Enter location: ' )
if len(address) < 1: break
parms = dict()
parms['address'] = address
if api_key is not False: parms['key'] = api_key
url = serviceurl + urllib.parse.urlencode(parms)
print('Retrieving', url)
uh = urllib.request.urlopen(url, context=ctx)
data = uh.read().decode()
print('Retrieved', len(data), 'characters')
try:
js = json.loads(data)
except:
js = None
if not js or 'status' not in js or js['status'] != 'OK':
print('==== Failure To Retrieve ====')
print(data)
continue
print(json.dumps(js, indent=4))
lat = js['results'][0]['geometry']['location']['lat']
lng = js['results'][0]['geometry']['location']['lng']
print('lat', lat, 'lng', lng)
location = js['results'][0]['formatted_address']
print(location)
# Code: http://www.py4e.com/code3/geojson.py
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪224‬‬
‫مستخدما إياه كمعامل َّ‬
‫ً‬
‫مشفر ثم يستخدم ‪urllib‬‬
‫يستقبل البرنامج نص البحث وينش ئ رابط )‪(URL‬‬
‫الستدعاء النص من واجهة غوغل للترميز الجغرافي‪ ،‬كما تعتمد البيانات التي نحصل عليها على‬
‫املعامالت التي نرسلها والبيانات الجغرافية املخزنة في خوادم غوغل على عكس صفحات الويب‬
‫الثابتة‪ ،‬وبمجرد حصولنا على بيانات ‪ JSON‬نحللها باستخدام مكتبة ‪ JSON‬لنجري بعدها عدة‬
‫َ‬
‫املستقبلة‪ ،‬ثم نستخرج املعلومات التي نبحث عنها‪.‬‬
‫اختبارات للتأكد من جودة البيانات‬
‫ويكون خرج البرنامج كاآلتي ُ‬
‫(حذفت بعض بيانات ‪ JSON‬املستقبلة)‪:‬‬
‫‪$ python3 geojson.py‬‬
‫‪Enter location: Ann Arbor, MI‬‬
‫‪Retrieving http://py4e-data.dr-chuck.net/json?address=Ann+Arbor%2C+MI&key=42‬‬
‫‪Retrieved 1736 characters‬‬
‫{‬
‫[ ‪"results":‬‬
‫{‬
‫[ ‪"address_components":‬‬
‫{‬
‫‪"long_name": "Ann Arbor",‬‬
‫‪"short_name": "Ann Arbor",‬‬
‫[ ‪"types":‬‬
‫‪"locality",‬‬
‫"‪"political‬‬
‫]‬
‫‪},‬‬
‫{‬
‫‪"long_name": "Washtenaw County",‬‬
‫‪"short_name": "Washtenaw County",‬‬
‫[ ‪"types":‬‬
‫‪"administrative_area_level_2",‬‬
‫"‪"political‬‬
‫]‬
‫‪},‬‬
‫{‬
‫ استخدام خدمات الويب‬:‫الفصل الثالث عشر‬
225
"long_name": "Michigan",
"short_name": "MI",
"types": [
"administrative_area_level_1",
"political"
]
},
{
"long_name": "United States",
"short_name": "US",
"types": [
"country",
"political"
]
}
],
"formatted_address": "Ann Arbor, MI, USA",
"geometry": {
"bounds": {
"northeast": {
"lat": 42.3239728,
"lng": -83.6758069
},
"southwest": {
"lat": 42.222668,
"lng": -83.799572
}
},
"location": {
"lat": 42.2808256,
"lng": -83.7430378
},
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪226‬‬
‫‪"location_type": "APPROXIMATE",‬‬
‫{ ‪"viewport":‬‬
‫{ ‪"northeast":‬‬
‫‪"lat": 42.3239728,‬‬
‫‪"lng": -83.6758069‬‬
‫‪},‬‬
‫{ ‪"southwest":‬‬
‫‪"lat": 42.222668,‬‬
‫‪"lng": -83.799572‬‬
‫}‬
‫}‬
‫‪},‬‬
‫‪"place_id": "ChIJMx9D1A2wPIgR4rXIhkb5Cds",‬‬
‫[ ‪"types":‬‬
‫‪"locality",‬‬
‫"‪"political‬‬
‫]‬
‫}‬
‫‪],‬‬
‫"‪"status": "OK‬‬
‫}‬
‫‪lat 42.2808256 lng -83.7430378‬‬
‫‪Ann Arbor, MI, USA‬‬
‫‪Enter location:‬‬
‫ويمكنك تنزيل البرنامج ‪ www.py4e.com/code3/geoxml.py‬الكتشاف اختالف البرنامج بحالة‬
‫استخدام ‪ XML‬لواجهة ترميز غوغل الجغرافي‪.‬‬
‫التمرين األول‪ :‬عدل أحد البرنامجين ‪ geojson.py‬أو ‪ geoxml.py‬لطباعة رمز الدولة الثنائي من‬
‫البيانات املستقبلة وأضف تعليمات للتحقق من األخطاء كي ال يفشل برنامجك إن لم يكن رمز‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪227‬‬
‫الدولة موجود‪ ،‬وبمجرد عمله ابحث عن املحيط األطلس ي "‪ "Atlantic Ocean‬وتأكد أنه يستطيع‬
‫التعامل مع مواقع غير موجودة ضمن حدود أي دولة‪.‬‬
‫‪ 10.13‬التطبيق الثاني‪ :‬تويتر‬
‫انتقلت تويتر من الواجهات مفتوحة املصدر والعامة إلى الواجهات التي تتطلب استخدام تواقيع‬
‫‪ OAuth‬لكل طلب وذلك مع ازدياد أهمية واجهاتها‪ ،‬وألجل املثال التالي نزل امللفات ‪twurl.py‬‬
‫و‪ hidden.py‬و‪ oauth.py‬و‪ twitter1.py‬من ‪ www.py4e.com/code‬وضعهم في مجلد واحد ً‬
‫معا‬
‫على حاسوبك‪ ،‬والستخدام هذه البرامج تحتاج حساب على تويتر وتفويض برنامجك كتطبيق‬
‫وإعداد املفتاح وكلمة سر والرمز (‪ )token‬وكلمة سر الرمز ومن ثم عدل امللف ‪ hidden.py‬وضع‬
‫هذه السالسل النصية ضمن متحوالت مناسبة في البرنامج‪:‬‬
‫‪# Keep this file separate‬‬
‫‪# https://apps.twitter.com/‬‬
‫‪# Create new App and get the four strings‬‬
‫‪def oauth():‬‬
‫‪return {"consumer_key": "h7Lu...Ng",‬‬
‫‪"consumer_secret" : "dNKenAC3New...mmn7Q",‬‬
‫‪"token_key" : "10185562-eibxCp9n2...P4GEQQOSGI",‬‬
‫}"‪"token_secret" : "H0ycCFemmC4wyf1...qoIpBo‬‬
‫‪# Code: http://www.py4e.com/code3/hidden.py‬‬
‫نصل لخدمات تويتر عبر الرابط اآلتي‪:‬‬
‫‪https://api.twitter.com/1.1/statuses/user_timeline.json‬‬
‫ولكن بمجرد إضافة جميع معلومات األمان فسيبدو الرابط كاآلتي‪:‬‬
‫‪https://api.twitter.com/1.1/statuses/user_timeline.json?count=2‬‬
‫‪&oauth_version=1.0&oauth_token=101...SGI&screen_name=drchuck‬‬
‫‪&oauth_nonce=09239679&oauth_timestamp=1380395644‬‬
‫‪&oauth_signature=rLK...BoD&oauth_consumer_key=h7Lu...GNg‬‬
‫ استخدام خدمات الويب‬:‫الفصل الثالث عشر‬
228
&oauth_signature_method=HMAC-SHA1
‫ في حال أردت املزيد من املعلومات حول معاني املعامالت املختلفة‬OAuth ‫ويمكنك قراءة توصيف‬
twurl.py‫ و‬oauth.py ‫ سنخفي كل التعقيدات في امللفات‬،‫ لألمان‬OAuth ‫املضافة لتلبية متطلبات‬
ً
‫ ثم نرسل الرابط‬hidden.py ‫ بداية نضيف كلمة السر في‬.‫من أجل البرامج التي تعمل مع تويتر‬
.‫ لتضيف املكتبة جميع املعامالت الالزمة إلى الرابط ألجلنا‬twurl.augment ‫املطلوب إلى التابع‬
JSON ‫يحدد هذا البرنامج منشورات (تغريدات) مستخدم تويتر محدد ويعيدها إلينا في صيغة‬
:‫ محرف منها على الشاشة‬250 ‫كسلسلة نصية لنظهر أول‬
import urllib.request, urllib.parse, urllib.error
import twurl
import ssl
# https://apps.twitter.com/
# Create App and get the four strings, put them in hidden.py
TWITTER_URL = 'https://api.twitter.com/1.1/statuses/user_timeline.json'
# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
while True:
print('')
acct = input('Enter Twitter Account:')
if (len(acct) < 1): break
url = twurl.augment(TWITTER_URL,{'screen_name': acct, 'count': '2'})
print('Retrieving', url)
connection = urllib.request.urlopen(url, context=ctx)
data = connection.read().decode()
print(data[:250])
‫ استخدام خدمات الويب‬:‫الفصل الثالث عشر‬
229
headers = dict(connection.getheaders())
# print headers
print('Remaining', headers['x-rate-limit-remaining'])
# Code: http://www.py4e.com/code3/twitter1.py
:‫وعند تشغيل البرنامج نحصل على الخرج اآلتي‬
Enter Twitter Account: drchuck
Retrieving https://api.twitter.com/1.1/ …
[{"created_at":"Sat Sep 28 17:30:25 +0000 2013","
id":384007200990982144,"id_str":"384007200990982144",
"text":"RT @fixpert: See how the Dutch handle traffic
intersections: http:\/\/t.co\/tIiVWtEhj4\n#brilliant",
"source":"web","truncated":false,"in_rep
Remaining 178
Enter Twitter Account: fixpert
Retrieving https://api.twitter.com/1.1/ …
[{"created_at":"Sat Sep 28 18:03:56 +0000 2013",
"id":384015634108919808,"id_str":"384015634108919808",
"text":"3 months after my freak bocce ball accident,
my wedding ring fits again! :)\n\nhttps:\/\/t.co\/2XmHPx7kgX",
"source":"web","truncated":false,
Remaining 177
Enter Twitter Account:
ً
ً ‫تعيد تويتر أي‬
‫ إضافة إلى بيانات‬HTTP ‫ضا بيانات وصفية حول الطلب في ترويسة استجابة‬
‫ بعدد الطلبات التي‬x-rate-limit-remaining ‫ ويخبرنا أحد البيانات الوصفية وهو‬،‫املنشورات‬
ً ‫نستطيع إرسالها قبل إيقاف الخدمة‬
‫ كما يمكنك مالحظة أن عدد مرات االستدعاء تقل‬،‫مؤقتا‬
.‫بواحد بعد كل طلب‬
230
‫ استخدام خدمات الويب‬:‫الفصل الثالث عشر‬
‫ املستقبلة الستخراج‬JSON ‫ نستدعي قائمة أصدقاء مستخدم تويتر ونحلل نصوص‬،‫في املثال التالي‬
ً ‫ و‬،‫بعض املعلومات حول أولئك األصدقاء‬
‫ بعد تحليله ثم نطبع مؤشر‬JSON ‫أيضا نتخلص من ملف‬
:‫معبر عنه من أربع محارف يسمح لنا بمسح البيانات إذا أردنا استخراج حقول معلومات إضافية‬
import urllib.request, urllib.parse, urllib.error
import twurl
import json
import ssl
# https://apps.twitter.com/
# Create App and get the four strings, put them in hidden.py
TWITTER_URL = 'https://api.twitter.com/1.1/friends/list.json'
# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
while True:
print('')
acct = input('Enter Twitter Account:')
if (len(acct) < 1): break
url = twurl.augment(TWITTER_URL, {'screen_name': acct, 'count': '5'})
print('Retrieving', url)
connection = urllib.request.urlopen(url, context=ctx)
data = connection.read().decode()
js = json.loads(data)
print(json.dumps(js, indent=2))
headers = dict(connection.getheaders())
print('Remaining', headers['x-rate-limit-remaining'])
for u in js['users']:
‫ استخدام خدمات الويب‬:‫الفصل الثالث عشر‬
231
print(u['screen_name'])
if 'status' not in u:
print(' * No status found')
continue
s = u['status']['text']
print(' ', s[:50])
# Code: http://www.py4e.com/code3/twitter2.py
‫ تتحول إلى قوائم وقواميس بايثون متداخلة فنستطيع استخدام مزيج من عامل‬JSON ‫وبما أن‬
،‫ لنمر عبر بنى البيانات املستقبلة باستخدام عدد قليل من تعليمات بايثون‬for ‫الفهرس وحلقات‬
:)‫وسيبدو خرج البرنامج كما يأتي (اختصرت بعض عناصر البيانات لتسع الصفحة‬
Enter Twitter Account:drchuck
Retrieving https://api.twitter.com/1.1/friends ...
Remaining 14
{
"next_cursor": 1444171224491980205,
"users": [
{
"id": 662433,
"followers_count": 28725,
"status": {
"text": "@jazzychad I just bought one .__.",
"created_at": "Fri Sep 20 08:36:34 +0000 2013",
"retweeted": false,
},
"location": "San Francisco, California",
"screen_name": "leahculver",
"name": "Leah Culver",
},
{
"id": 40426722,
‫ استخدام خدمات الويب‬:‫الفصل الثالث عشر‬
232
"followers_count": 2635,
"status": {
"text": "RT @WSJ: Big employers like Google ...",
"created_at": "Sat Sep 28 19:36:37 +0000 2013",
},
"location": "Victoria Canada",
"screen_name": "_valeriei",
"name": "Valerie Irvine",
}
],
"next_cursor_str": "1444171224491980205"
}
leahculver
@jazzychad I just bought one .__.
_valeriei
RT @WSJ: Big employers like Google, AT&T are h
ericbollens
RT @lukew: sneak peek: my LONG take on the good &a
halherzog
Learning Objects is 10. We had a cake with the LO,
scweeker
@DeviceLabDC love it! Now where so I get that "etc
Enter Twitter Account:
‫@ (حساب املؤلف) في‬drchuck ‫ تقرأ بيانات أحدث خمس أصدقاء لحساب تويتر‬for ‫نرى أن حلقة‬
‫ إال أنه توجد بيانات أكثر متاحة‬،‫القسم األخير من الخرج وتطبع آخر تغريدة (منشور) لكل صديق‬
"‫بالنظر إلى خرج البرنامج أن خدمة "جد األصدقاء‬- ‫ كما ستالحظ‬،‫ املستقبل‬JSON ‫ضمن ملف‬
‫الفصل الثالث عشر‪ :‬استخدام خدمات الويب‬
‫‪233‬‬
‫لحساب تويتر له معدل محدد ومختلف القيمة عن عدد طلبات الحصول على املنشورات املسموح‬
‫لنا إجراؤها خالل مدة زمنية معينة‪.‬‬
‫إن هذه املفاتيح املؤمنة الخاصة بالواجهات تسمح لتويتر بتكوين معرفة عميقة ملن يستخدم‬
‫واجهاتهم وبياناتهم وعلى أي مستوى‪ ،‬بينما يسمح لنا مفهوم تحديد معدل االستخدام بإجراء‬
‫استدعاءات بسيطة وشخصية للبيانات ولكن ال يسمح بتصميم منتج يسحب البيانات من‬
‫واجهاتهم مليون مرة باليوم الواحد‪.‬‬
‫الفصل الرابع عشر‬
‫البرمجة كائنية التوجه‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪235‬‬
‫‪ 14‬البرمجة الكائنية التوجه‬
‫‪ 1.14‬إدارة البرامج الكبيرة‬
‫مررنا في الفصول األولى من الكتاب على أربع أنماط برمجية لبناء البرامج املختلفة وهي‪:‬‬
‫ الشيفرة التسلسلية‬‫ الشيفرة الشرطية (بنية ‪)if‬‬‫ الشيفرة التكرارية )الحلقات)‬‫ التخزين وإعادة االستخدام (التوابع)‬‫ثم تعرفنا في الفصول الالحقة إلى املتغيرات إلى جانب بعض بنى البيانات مثل القوائم والصفوف‬
‫والقواميس‪.‬‬
‫َ‬
‫كتبت حتى اآلن العديد من البرامج‪ ،‬منها املمتاز ومنها غير املتقن وبالرغم من أن هذه البرامج‬
‫لقد‬
‫بسيطة ولكن البد أن تكون قد أدركت اآلن أن البرمجة فن‪.‬‬
‫من املهم للغاية كتابة شيفرة سهلة الفهم خاصة حين يتكون البرنامج من ماليين األسطر‪ ،‬فحينها لن‬
‫يستطيع عقلك استيعابه‪ .‬لذا اقتضت الحاجة أن يتم تقسيم البرنامج إلى قطع صغيرة حتى يتسنى لنا‬
‫التركيز على حل مشكلة وإصالح خطأ أو إضافة ميزة جديدة‪.‬‬
‫وهنا يأتي دور البرمجة كائنية التوجه‪ ،‬فهي طريقة لترتيب الشيفرات تمكنك من التركيز على ‪ 50‬سطر‬
‫من الشيفرة وفهمها وتجاهل األسطر ‪ 999950‬األخرى‪.‬‬
‫‪ 2.14‬مقدمة‬
‫كباقي النواحي البرمجية من الضروري تعلم مفاهيم البرمجة كائنية التوجه قبل استخدامها‪ ،‬فعليك‬
‫التركيز في هذا الفصل على تعلم بعض مصطلحاتها ومفاهيمها وتنفيذ بعض األمثلة البسيطة لوضع‬
‫آت‪.‬‬
‫حجر األساس ملا هو ٍ‬
‫ُ‬
‫ً‬
‫مبدئيا كيف تبنى الكائنات وطريقة عملها واألهم من ذلك كيف نستفيد‬
‫هدفنا األساس ي هو أن تفهم‬
‫من الكائنات الجاهزة التي تزودنا بها لغة بايثون ومكتباتها‪.‬‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪236‬‬
‫‪ 3.14‬استخدام الكائنات‬
‫دعني أخبرك بش يء‪ ،‬لقد كنا نستخدم الكائنات بكثرة في هذا الكتاب حيث توفر لغة بايثون العديد‬
‫من الكائنات الجاهزة‪ ،‬إليك بعض الشيفرات البسيطة‪ ،‬الحظ األسطر األولى منها فستجدها مألوفة‬
‫لديك‪:‬‬
‫)(‪stuff = list‬‬
‫)'‪stuff.append('python‬‬
‫)'‪stuff.append('chuck‬‬
‫)(‪stuff.sort‬‬
‫)]‪print (stuff[0‬‬
‫))‪print (stuff.__getitem__(0‬‬
‫))‪print (list.__getitem__(stuff,0‬‬
‫‪# Code: http://www.py4e.com/code3/party1.py‬‬
‫لندع اآلن ما تنفذه هذه األسطر ولنلقي نظرة على ماذا يحدث ً‬
‫حقا من وجهة نظر البرمجة كائنية‬
‫التوجه‪ ،‬ال تقلق إذا شعرت أن الفقرات التالية بال أي معنى عند قراءتها للمرة األولى فأنت لم تتعرف‬
‫على جميع املفاهيم بعد‪.‬‬
‫يبني السطر األول كائنا من نوع قائمة ‪ list‬في حين يستدعي السطر الثاني والثالث تابع ()‪ append‬لهذا‬
‫الكائن‪ ،‬ثم استدعينا في السطر الرابع التابع ()‪ sort‬وفي السطر الخامس نحصل على أول عنصر في‬
‫القائمة‪.‬‬
‫ننتقل إلى السطر السادس حيث نستدعي تابع ()__‪ __getitem‬في القائمة ‪ stuff‬بمعامل صفري‬
‫(لنستعيد العنصر ذو الفهرس صفر في القائمة)‪.‬‬
‫))‪print (stuff.__getitem__(0‬‬
‫السطر السابع هو مجرد طريقة مطولة السترجاع العنصر الصفري في القائمة‪.‬‬
‫))‪print (list.__getitem__(stuff,0‬‬
‫في هذه الشيفرة استدعينا التابع __‪ __getitem‬من الصنف )‪ list (class‬ومررنا القائمة والعنصر‬
‫الذي نريد استرجاعه من القائمة كمعامل‪.‬‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪237‬‬
‫إن األسطر الثالث األخيرة من البرنامج متكافئة‪ ،‬لكن من األنسب استخدم األقواس املربعة [ ] للبحث‬
‫عن عنصر محدد في قائمة‪.‬‬
‫يمكننا التعرف على قدرات الكائن عبر النظر إلى خرج التابع )(‪: dir‬‬
‫)(‪>>> stuff = list‬‬
‫)‪>>> dir(stuff‬‬
‫‪['__add__', '__class__', '__contains__', '__delattr__',‬‬
‫‪'__delitem__', '__dir__', '__doc__', '__eq__',‬‬
‫‪'__format__', '__ge__', '__getattribute__', '__getitem__',‬‬
‫‪'__gt__', '__hash__', '__iadd__', '__imul__', '__init__',‬‬
‫‪'__iter__', '__le__', '__len__', '__lt__', '__mul__',‬‬
‫‪'__ne__', '__new__', '__reduce__', '__reduce_ex__',‬‬
‫‪'__repr__', '__reversed__', '__rmul__', '__setattr__',‬‬
‫‪'__setitem__', '__sizeof__', '__str__', '__subclasshook__',‬‬
‫‪'append', 'clear', 'copy', 'count', 'extend', 'index',‬‬
‫]'‪'insert', 'pop', 'remove', 'reverse', 'sort‬‬
‫>>>‬
‫سيتضح لك في بقية هذا الفصل كل املصطلحات املبهمة في األعلى لذلك أحرص على العودة عندما‬
‫تنهي الفصل وأعد قراءة الفقرات السابقة كي تتحقق من فهمك‪.‬‬
‫‪ 4.14‬البدء مع البرامج‬
‫تعلمنا ً‬
‫سابقا أن البرنامج في أبسط أشكاله يأخذ بعض املدخالت‪ ،‬ليعالجها‪ ،‬ثم ٌينتج بعض من‬
‫املخرجات‪ .‬فلننظر إلى برنامج تحويل أرقام الطوابق في املصاعد القصير ً‬
‫جدا لكنه كامل ُويظهر كال‬
‫من تلك الخطوات الثالث‪.‬‬
‫)' ‪usf = input('Enter the US Floor Number:‬‬
‫‪wf = int(usf) - 1‬‬
‫)‪print('Non-US Floor Number is',wf‬‬
‫‪Code: http://www.py4e.com/code3/elev.py #‬‬
‫إذا تأملنا هذا البرنامج بتمعن فسنرى البرنامج وما يمكن أن نسميه بالعالم الخارجي حيث يتفاعل‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪238‬‬
‫البرنامج مع العالم الخارجي فيستقبل منه ويرسل إليه‪ ،‬وفي قلب البرنامج نفسه لدينا شيفرة وبيانات‬
‫إلنجاز املهمة التي صمم البرنامج لحلها‪.‬‬
‫ولقد أخذت البرمجة كائنية التوجه هذا املفهوم وطورته أكثر فهي تقسم برنامجنا إلى نطاقات‬
‫متعددة‪ ،‬ولكل نطاق شيفراته وبياناته (كأنه برنامج مستقل) وتفاعالته املحددة جي ًدا مع العالم‬
‫ً‬
‫مجددا إلى تطبيق استخراج الرابط‬
‫الخارجي والنطاقات األخرى ضمن البرنامج الرئيس ي‪ .‬إذا نظرنا‬
‫التشعبي حين استخدمنا مكتبة ‪BeautifulSoup‬‬
‫ً‬
‫مثاال لبرنامج ُمنشأ عبر ربط الكائنات املختلفة ً‬
‫سويا لتحقيق املهمة‪.‬‬
‫سنرى بوضوح‬
‫الشكل ‪ : 17‬البرنامج‬
‫‪# To run this, download the BeautifulSoup zip file‬‬
‫‪# http://www.py4e.com/code3/bs4.zip‬‬
‫‪# and unzip it in the same directory as this file‬‬
‫‪import urllib.request, urllib.parse, urllib.error‬‬
‫‪from bs4 import BeautifulSoup‬‬
‫‪import ssl‬‬
‫‪# Ignore SSL certificate errors‬‬
‫)(‪ctx = ssl.create_default_context‬‬
‫‪ctx.check_hostname = False‬‬
‫‪ctx.verify_mode = ssl.CERT_NONE‬‬
‫)' ‪url = input('Enter -‬‬
‫)(‪html = urllib.request.urlopen(url, context=ctx).read‬‬
‫)'‪soup = BeautifulSoup(html, 'html.parser‬‬
‫‪# Retrieve all of the anchor tags‬‬
‫)'‪tags = soup('a‬‬
‫‪for tag in tags:‬‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪239‬‬
‫))‪print(tag.get('href', None‬‬
‫‪# Code: http://www.py4e.com/code3/urllinks.py‬‬
‫لقد خزنا الرابط في متغير من نوع سلسلة نصية ثم مررناه إلى ‪ urllib‬لجلب البيانات من الويب‪ ،‬حيث‬
‫تستخدم مكتبة ‪ urllib‬مكتبة ‪ socket‬إلنشاء اتصال الشبكة الفعلي الستعادة البيانات‪ .‬بعد ذلك‬
‫نأخذ النص الناتج عن ‪ urllib‬ونسلمه إلى ‪ BeautifulSoup‬لتحليله‪ ،‬حيث تستعين ‪BeautifulSoup‬‬
‫بالكائن ‪ html.parser‬لتعيد ً‬
‫كائنا‪.‬‬
‫ً‬
‫قاموسا من الوسوم‪ ،‬ثم نمر على عناصر القاموس باستخدام حلقة ونستدعي التابع‬
‫نخزن في ‪tags‬‬
‫()‪ get‬لكل وسم لطباعة الخاصية ‪.href‬‬
‫بإمكاننا رسم مخطط لهذا البرنامج وكيف تعمل هذه الكائنات معا‪.‬‬
‫ً‬
‫الغرض من هذا املثال ليس معرفة كيف نستخرج رابطا من صفحة ويب بل رؤية كيف نبني شبكة‬
‫كائنات متفاعلة وكيفية انسياب املعلومات بين تلك الكائنات إلنشاء البرنامج‪ ،‬لعلك الحظت عندما‬
‫استخدمت هذا البرنامج في فصل سابق من هذا الكتاب أمكنك فهم ماذا يقوم به بدون أن تدرك‬
‫كيف كان ينسق البرنامج حركة البيانات بين الكائنات‪ ،‬فما هي إال أسطر من الشيفرة التي تؤدي‬
‫املطلوب‪.‬‬
‫الشكل ‪ :18‬البرنامج كشبكة من الكائنات‬
‫‪ 5.14‬تقسيم املشكلة‬
‫ً‬
‫يتميز أسلوب البرمجة كائنية التوجه أنه بإمكانه إخفاء التعقيد‪ ،‬فمثال عندما نحتاج ملعرفة كيف‬
‫ً‬
‫داخليا‪،‬‬
‫نستخدم مكتبتي ‪ urllib‬و‪ BeautifulSoup‬فنحن ال نحتاج ملعرفة كيف تعمل هذه املكتبات‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪240‬‬
‫مما يسمح لنا بالتركيز على املشكلة الذي نريد حلها وتجاهل ما سواها‪.‬‬
‫الشكل ‪ :19‬تجاهل التفصيل عند استخدام الكائن‬
‫تعد القدرة على التركيز على جزء من البرنامج وتجاهل ما سواه ً‬
‫مفيدا ً‬
‫أيضا ملطوري الكائنات التي‬
‫ً‬
‫نستخدمها‪ ،‬فمثال ال يحتاج املبرمجون الذين يطورون ‪ BeautifulSoup‬ملعرفة أو لالهتمام كيف‬
‫نحصل على صفحة ‪ HTML‬أو ماهية الصفحات التي نريد قراءتها أو ما الذي نخطط لفعله مع‬
‫البيانات التي نستخرجها من صفحة ويب‪.‬‬
‫‪ 6.14‬إنشاء كائن في لغة بايثون‬
‫الكائن ببساطة هو جزء صغير من البرنامج يحتوي على بعض الشيفرات باإلضافة إلى بعض من بنى‬
‫البيانات‪.‬‬
‫اسما ً‬
‫لنتذكر مفهوم التابع الذي يسمح لنا بتخزين بعض الشيفرة ويمنحها ً‬
‫معينا‪ ،‬ثم يمكننا‬
‫استحضار تلك الشيفرة ً‬
‫الحقا بكتابة اسم التابع فقط‪.‬‬
‫الشكل ‪ :20‬تجاهل التفاصيل عند إنشاء الكائن‬
‫قد يحوي الكائن العديد من التوابع تسمى (‪ )methods‬إلى جانب البيانات التي تستخدمها هذه‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪241‬‬
‫التوابع‪ ،‬ونسمي عناصر البيانات التي هي جزء من الكائن بالخواص (‪.)properties‬‬
‫نستخدم الكلمة املفتاحية ‪ class‬لنحدد البيانات والشيفرة التي سنستخدمها إلنشاء الكائنات حيث‬
‫يأتي بعد الكلمة املفتاحية اسم الصنف يليها الشيفرة املتضمنة للخواص (البيانات) والتوابع‬
‫(الشيفرة)‪.‬‬
‫‪class PartyAnimal:‬‬
‫‪x=0‬‬
‫‪def party(self) :‬‬
‫‪self.x = self.x + 1‬‬
‫)‪print("So far",self.x‬‬
‫)(‪an = PartyAnimal‬‬
‫)(‪an.party‬‬
‫)(‪an.party‬‬
‫)(‪an.party‬‬
‫)‪PartyAnimal.party(an‬‬
‫‪# Code: http://www.py4e.com/code3/party2.py‬‬
‫هذا الكائن يحوي خاصية واحدة ‪ x‬وتابع واحد هو ‪ ،party‬يحوي التابع على عامل خاص نطلق عليه‬
‫‪ .self‬كما أن الكلمة املفتاحية ‪ def‬ال تؤدي إلى تنفيذ شيفرة التابع كذلك فالكلمة املفتاحية ‪ class‬ال‬
‫تصنع ً‬
‫كائنا‪ ،‬فالصنف يمثل القالب الذي يتضمن البيانات والشيفرة التي سيتكون منها كل كائن من‬
‫الشكل ‪: 21‬صنف وكائنان‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪242‬‬
‫نوع ‪ .PartyAnimal‬للتوضيح‪ ،‬اعتبر الصنف كقالب صنع الكعك والكائنات املنشأة منه هي الكعك‪،‬‬
‫فنحن ال نضع الزينة على القالب بل على الكعك‪ ،‬وبإمكانك وضع زينة مختلفة على كل قطعة‪.‬‬
‫لنتابع اآلن شرح البرنامج ونأتي للسطر التالي‬
‫)(‪an = PartyAnimal‬‬
‫نأمر هنا لغة بايثون ببناء كائن أو نموذج من الصنف ‪ PartyAnimal‬ويبدو األمر كأنه استدعاء تابع‬
‫للصنف نفسه‪.‬‬
‫تبني لغة بايثون الكائن ببياناته وتوابعه ثم تعيده إلى املتغير ‪ ،an‬ما سبق يشبه األمر التالي الذي كنا‬
‫نستخدمه في الفصول السابقة‪:‬‬
‫)(‪counts = dict‬‬
‫حيث نأمر بايثون ببناء كائن باستخدام قالب القاموس ‪( dict‬الجاهز في بايثون) ونسنده إلى متغير‬
‫‪.counts‬‬
‫تذكر عندما نستخدم صنف ‪ PartyAnimal‬لبناء كائن فإن املتغير ‪ an‬يستخدم ليشير إلى ذلك‬
‫الكائن‪ ،‬ويحوي كل كائن أو نموذج من ‪ PartyAnimal‬املتغير‪ x‬وتابع يدعى ‪.party‬‬
‫نستدعي التابع ‪ party‬في هذا السطر‬
‫)(‪an.party‬‬
‫ً‬
‫اصطالحا ‪ )self‬يشير إلى الكائن بذاته من بين‬
‫عند استدعاء التابع ‪ party‬فإن العامل (الذي نسميه‬
‫كائنات الصنف ‪ PartyAnimal‬والذي تم استدعاء التابع عبره‪.‬‬
‫في التابع ‪ party‬نرى السطر‪:‬‬
‫‪self.x = self.x + 1‬‬
‫يستخدم هذا السطر عامل النقطة التي تعني (استخدم ‪ x‬التي تنتمي للكائن) وفي كل مرة تستدعى فيها‬
‫التابع ‪ party‬فإن قيمة ‪ x‬الداخلية تزداد بمقدار ‪ 1‬ثم تعرض النتيجة على الخرج‪.‬‬
‫يمثل السطر التالي طريقة أخرى الستدعاء التابع ‪ party‬عبر الكائن ‪:an‬‬
‫)‪PartyAnimal.party(an‬‬
‫االختالف هنا أننا نستدعي الشيفرة من داخل الصنف نفسه ثم نمرر مؤشر الكائن ‪ an‬كمعامل (أي‬
‫املعامل املسمى ‪ self‬ضمن التابع)‪ ،‬وبإمكاننا التفكير أن ‪ an.party‬هي اختصار للسطر أعاله‪.‬‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪243‬‬
‫عندما ينفذ البرنامج فإنه سيعطي الخرج التالي‪:‬‬
‫‪So far 1‬‬
‫‪So far 2‬‬
‫‪So far 3‬‬
‫‪So far 4‬‬
‫فالكائن ٌبني ثم استدعى التابع ‪ party‬أربع مرات‪ ،‬بحيث يزيد بمقدار ‪ 1‬ويطبع القيمة ‪ x‬املوجودة في‬
‫الكائن ‪.an‬‬
‫‪ 7.14‬الصنف كنوع بيانات‬
‫في لغة بايثون كل املتغيرات لها نوع محدد‪ .‬استخدم التابع الجاهز ‪ dir‬ملعرفة قدرات أي متغير ً‬
‫وأيضا‬
‫بإمكاننا استخدام ‪ type‬و‪ dir‬مع األصناف التي انشأناها‬
‫‪class PartyAnimal:‬‬
‫‪x=0‬‬
‫‪def party(self) :‬‬
‫‪self.x = self.x + 1‬‬
‫)‪print("So far",self.x‬‬
‫)(‪an = PartyAnimal‬‬
‫))‪print ("Type", type(an‬‬
‫))‪print ("Dir ", dir(an‬‬
‫))‪print ("Type", type(an.x‬‬
‫))‪print ("Type", type(an.party‬‬
‫‪# Code: http://www.py4e.com/code3/party3.py‬‬
‫عندما ينفذ البرنامج سينتج الخرج التالي‪:‬‬
‫>'‪Type <class '__main__.PartyAnimal‬‬
‫‪Dir ['__class__', '__delattr__', ...‬‬
‫‪'__sizeof__', '__str__', '__subclasshook__',‬‬
‫]'‪'__weakref__', 'party', 'x‬‬
‫>'‪Type <class 'int‬‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪244‬‬
‫>'‪Type <class 'method‬‬
‫يمكنك القول إننا باستخدام الكلمة املفتاحية ‪ class‬صنعنا نوع بيانات جديد‪.‬‬
‫يمكن باستخدام التابع ‪ dir‬رؤية كل من خواص العدد الصحيح ‪ x‬والتابع ‪ party‬في الكائن‪.‬‬
‫‪ 8.14‬دورة حياة الكائن‬
‫في األمثلة السابقة عرفنا صنف (أي قالب) واستخدمناه إلنشاء نموذج منه (كائن) ثم استخدمنا هذا‬
‫الكائن‪.‬‬
‫عندما ينتهي البرنامج ُتهمل كل املتغيرات‪ .‬عادة ال نفكر ً‬
‫كثيرا في عملية إنشاء وهدم املتغيرات‪ ،‬لكن‬
‫ً‬
‫تعقيدا نحتاج التخاذ إجراءات معينة أثناء إنشاء الكائن‪ ،‬وحذف األشياء‬
‫عندما يصبح كائننا أكثر‬
‫عند إهماله‪.‬‬
‫إذا أردنا تبيان عمليات البناء والهدم نضيف توابع خاصة لكائنا‪.‬‬
‫‪class PartyAnimal:‬‬
‫‪x=0‬‬
‫‪def __init__(self):‬‬
‫)'‪print('I am constructed‬‬
‫‪def party(self) :‬‬
‫‪self.x = self.x + 1‬‬
‫)‪print('So far',self.x‬‬
‫‪def __del__(self):‬‬
‫)‪print('I am destructed', self.x‬‬
‫)(‪an = PartyAnimal‬‬
‫)(‪an.party‬‬
‫)(‪an.party‬‬
‫‪an = 42‬‬
‫)‪print('an contains',an‬‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪245‬‬
‫‪# Code: http://www.py4e.com/code3/party4.py‬‬
‫عندما ينفذ البرنامج فإنه يعطي الخرج التالي‪:‬‬
‫‪I am constructed‬‬
‫‪So far 1‬‬
‫‪So far 2‬‬
‫‪I am destructed 2‬‬
‫‪an contains 42‬‬
‫عندما ٌتنشأ لغة بايثون الكائن فإنها تستدعي تابع __‪ __init‬لتعطينا فرصة لضبط القيم االبتدائية‬
‫للكائن‪.‬‬
‫عندما تصادف لغة بايثون السطر‪an = 42 :‬‬
‫فإن بايثون تتخلص من الكائن عن طريق إعادة استخدام املتغير ‪ an‬لتخزين القيمة ‪ ،42‬وعند تدمير‬
‫الكائن تستدعى شيفرة الهادم __‪.__del‬‬
‫ال يمكننا حماية املتغيرات في الكائن من عملية الهدم‪ ،‬كل ما هنالك أننا نقوم بالعمليات الضرورية‬
‫قبل أن يختفي الكائن ً‬
‫نهائيا‪.‬‬
‫دائما عند تطوير الكائنات فمن الشائع ً‬
‫تذكر ً‬
‫جدا إضافة التابع الباني للكائن لضبط القيم االبتدائية‬
‫له‪ً ،‬‬
‫ونادرا ما نحتاج تابع الهادم للكائن‪.‬‬
‫‪ 9.14‬تعدد الكائنات‬
‫حتى اآلن عرفنا ما هو الصنف وبنينا كائن وحيد واستخدمناه ثم تخلصنا منه‪.‬‬
‫صنف واحد‪ ،‬حيث‬
‫تظهر القوة الحقيقية للبرمجة كائنية التوجه عندما نبني كائنات متعددة من‬
‫ٍ‬
‫نعطي قيم ابتدائية مختلفة لكل من الكائنات‪.‬‬
‫هنا سنقوم بتمرير البيانات إلى الباني إلعطاء كل كائن قيمة ابتدائية مختلفة‪:‬‬
‫‪class PartyAnimal:‬‬
‫‪x=0‬‬
‫' ' = ‪name‬‬
‫‪def __init__(self, nam):‬‬
‫ البرمجة كائنية التوجه‬:‫الفصل الرابع عشر‬
246
self.name = nam
print(self.name,'constructed')
def party(self) :
self.x = self.x + 1
print(self.name,'party count',self.x)
s = PartyAnimal('Sally')
j = PartyAnimal('Jim')
s.party()
j.party()
s.party()
# Code: http://www.py4e.com/code3/party5.py
‫ الذي يشير إلى حالة العنصر وعوامل إضافية تمرر عبر الباني أثناء‬self ‫تضم عوامل الباني العامل‬
:‫إنشاء الكائن‬
s = PartyAnimal('Sally')
self ‫ للكائن عبر‬name ‫) إلى خاصية‬nam( ‫أثناء عملية اإلنشاء فإن السطر الثاني ينسخ العامل‬
self.name = nam
name ‫ و‬x ‫ تحوي نسخ مستقلة من قيم‬j ‫ و‬s ‫إن خرج البرنامج يظهر أن كل من تلك الكائنات‬
Sally constructed
Jim constructed
Sally party count 1
Jim party count 1
Sally party count 2
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪247‬‬
‫‪ 10.14‬الوراثة‬
‫ُ‬
‫تعد القدرة على إنشاء صنف جديد عبر توسيع صنف موجود ميزة أخرى للبرمجة كائنية التوجه‪،‬‬
‫فعند توسيع الصنف ندعو الصنف األصلي بالصنف األب (‪ )parent class‬والصنف الجديد‬
‫بالصنف االبن (‪)child class‬‬
‫فلننقل صنف ‪ PartyAnimal‬إلى ملف منفصل‪ ،‬الستيراده في ملف جديد وتوسيعه كما يلي‪:‬‬
‫‪from party import PartyAnimal‬‬
‫‪class CricketFan(PartyAnimal):‬‬
‫‪points = 0‬‬
‫‪def six(self):‬‬
‫‪self.points = self.points + 6‬‬
‫)(‪self.party‬‬
‫)‪print(self.name,"points",self.points‬‬
‫)"‪s = PartyAnimal("Sally‬‬
‫)(‪s.party‬‬
‫)"‪j = CricketFan("Jim‬‬
‫)(‪j.party‬‬
‫)(‪j.six‬‬
‫))‪print(dir(j‬‬
‫‪# Code: http://www.py4e.com/code3/party6.py‬‬
‫نشير عند تعريف الصنف ‪ CricketFan‬إلى الصنف ‪ ،PartyAnimal‬هذا يعني أن كل من املتغيرات ‪x‬‬
‫والتوابع ‪ party‬في الصنف ‪ PartyAnimal‬ستورث إلى الصنف ‪ ،CricketFan‬فعلى سبيل املثال‬
‫استدعينا التابع ‪ party‬من صنف ‪ PartyAnimal‬في تابع ‪ six‬للصنف ‪.CricketFan‬‬
‫عند تنفيذ البرنامج ننشأ ‪ s‬و‪ j‬ككائنات مستقلة من الصنفين ‪ PartyAnimal‬و‪CricketFan‬‬
‫الحظ أن الكائن ‪ j‬لديه قدرات إضافية تفوق الكائن ‪s‬‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪248‬‬
‫‪Sally constructed‬‬
‫‪Sally party count 1‬‬
‫‪Jim constructed‬‬
‫‪Jim party count 1‬‬
‫‪Jim party count 2‬‬
‫‪Jim points 6‬‬
‫‪['__class__', '__delattr__', ... '__weakref__',‬‬
‫]'‪'name', 'party', 'points', 'six', 'x‬‬
‫في خرج التابع ‪ dir‬للكائن ‪( j‬ذو الصنف ‪ )CricketFan‬نرى أن له خواص وتوابع من الصنف األب و ً‬
‫أيضا‬
‫الخواص والتوابع التي أضفناها عندما وسعنا الصنف إلنشاء ‪.CricketFan‬‬
‫‪ 11.14‬ملخص‬
‫هذه مقدمة مختصرة للبرمجة كائنية التوجه التي تركز بصورة أساسية على قواعد تعريف واستخدام‬
‫الكائنات‪.‬‬
‫لنراجع الشيفرة التي رأيناها في بداية الفصل‪ ،‬اآلن لن تجد أدنى صعوبة في فهمها‪.‬‬
‫)(‪stuff = list‬‬
‫)'‪stuff.append('python‬‬
‫)'‪stuff.append('chuck‬‬
‫)(‪stuff.sort‬‬
‫)]‪print (stuff[0‬‬
‫))‪print (stuff.__getitem__(0‬‬
‫))‪print (list.__getitem__(stuff,0‬‬
‫‪# Code: http://www.py4e.com/code3/party1.py‬‬
‫ٌينش ئ في السطر األول كائن من الصنف ‪ ،list‬عندها تستدعي بايثون التابع الباني وهو ( __‪)__init‬‬
‫ُ‬
‫لضبط البيانات الداخلية التي سوف تستخدم لتخزين قائمة من البيانات‪.‬‬
‫الحظ أننا لم نمرر أي عوامل إلى هذا الباني‪ ،‬وعندما ينتهي الباني من عمله نستخدم املتغير ‪stuff‬‬
‫لإلشارة إلى الكائن الناتج من الصنف ‪.list‬‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪249‬‬
‫في السطرين الثاني والثالث نستدعي التابع ‪ append‬إلضافة عنصر جديد إلى نهاية القائمة عبر‬
‫تحديث خواص الكائن ‪ .stuff‬ثم في السطر الرابع نستدعي تابع ‪ sort‬بال أي عوامل لترتيب بيانات‬
‫الكائن‪.‬‬
‫ً‬
‫ً‬
‫مختصرا‬
‫نستخدم عندما نريد طباعة أول عنصر في القائمة األقواس املربعة [] والتي تعد بديال‬
‫الستدعاء __‪ __getitem‬باستخدام ‪ ،stuff‬وهذا يكافئ استدعاء تابع __‪ __getitem‬على صنف ‪List‬‬
‫وتمرير كائن ‪ stuff‬كمعامل أول والفهرس التي نرغب بعرض محتواه كمعامل ثاني‪.‬‬
‫نستدعي في نهاية البرنامج التابع الهادم (والذي يسمى __‪ )__del‬ليتمكن الكائن من التعامل مع أي‬
‫بيانات سائبة قبل هدم الكائن ‪ .stuff‬هذه هي أساسيات البرمجة كائنية التوجه وهناك تفاصيل‬
‫ُ‬
‫إضافية تتبع عند تطوير تطبيقات ضخمة أو مكتبات لكنها خارج نطاق هذا الفصل‪.‬‬
‫‪ 12.14‬فهرس املصطلحات‬
‫• الخاصية (‪ :)attribute‬متغير جزء من الصنف‪.‬‬
‫• الصنف (‪ :)class‬قالب يستخدم لبناء كائن‪ ،‬ويحدد الخواص والتوابع التي تشكل الكائن‪.‬‬
‫• الصنف االبن (‪ :)child class‬صنف جديد ينشأ من توسيع الصنف األب‪ ،‬ويرث جميع‬
‫الخواص والتوابع من الصنف األب‪.‬‬
‫• التابع الباني (‪ :)constructor‬تابع اختياري يسمى (__‪ )__init‬يستدعى لحظة بناء الكائن‬
‫ويستخدم عادة لضبط القيم االبتدائية‪.‬‬
‫• التابع الهادم (‪ :)destructor‬تابع اختياري يسمى (__‪ )__del‬يستدعى في اللحظة قبل إزالة‬
‫الكائن‪ ،‬نادر االستخدام‪.‬‬
‫• الوراثة (‪ :)inheritance‬عندما يتم إنشاء صنف جديد (االبن ‪ )child‬عند توسيع صنف‬
‫موجود (أب ‪ )parent‬يحصل الصنف االبن على جميع الخواص والتوابع من الصنف األب‬
‫باإلضافة لخواص وتوابع محددة له‪.‬‬
‫• التابع (‪ :)method‬تابع موجود في صنف والكائنات املبنية من الصنف‪ ،‬وبعض املنهجيات‬
‫ً‬
‫في البرمجة كائنية التوجه تستخدم عبارة رسالة ‪ message‬بدال من ‪ method‬للتعبير عن هذا‬
‫املفهوم‪.‬‬
‫الفصل الرابع عشر‪ :‬البرمجة كائنية التوجه‬
‫‪250‬‬
‫• الكائن (‪ :)object‬نموذج يتم إنشاؤه من الصنف‪ ،‬يحوي كل من الخواص والتوابع املعرفة‬
‫ً‬
‫في الصنف‪ ،‬وبعض وثائق البرمجة كائنية التوجه تستخدم مصطلح ‪ instance‬بدال من‬
‫‪.object‬‬
‫• الصنف األب (‪ :)parent class‬الصنف الذي تم توسيعه لصنع صنف ابن جديد‪ ،‬يشارك‬
‫الصنف األب كل الخواص والتوابع مع الصنف االبن‪.‬‬
‫الفصل الخامس عشر‬
‫استخدام قواعد البيانات ولغة ‪SQL‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪252‬‬
‫‪ 15‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪ 1.15‬ما هي قاعدة البيانات؟‬
‫إن قاعدة البيانات هي ملف منظم لتخزين البيانات‪ ،‬وتكون معظم هذه القواعد منظمة بطريقة‬
‫مشابهة للقواميس حيث تربط بين مفاتيح وقيم‪ ،‬لكن االختالف الرئيس ي بينهما أن قاعدة البيانات‬
‫موجودة على القرص الصلب (أو أي أداة تخزين دائمة أخرى)‪ ،‬أي تحتفظ بالبيانات حتى بعد انتهاء‬
‫البرنامج‪ ،‬وبإمكانها تخزين بيانات أكثر من القواميس بسبب وجودها على وحدة تخزين دائمة‪ ،‬بينما‬
‫يكون حجم القاموس مرتبط بحجم ذاكرة الحاسوب‪ٌ .‬‬
‫صممت برمجيات قواعد البيانات بشكل يجعل‬
‫سريعا ً‬
‫ً‬
‫جدا مهما ك َبر حجمها ً‬
‫تماما كالقواميس‪ ،‬وتحافظ هذه‬
‫إدخال البيانات والوصول إليها‬
‫ً‬
‫البرمجيات على األداء السريع بإنشاء فهارس تز ً‬
‫امنا مع إدخال بيانات جديدة سامحة للحاسوب‬
‫َ‬
‫بالوصول إلى ُمدخل معين بسرعة‪.‬‬
‫توجد أنظمة مختلفة لقواعد البيانات تستخدم ألهداف متعددة ومنها ‪ Oracle‬و ‪MySQL‬‬
‫و ‪ Microsoft SQL Server‬و‪ PostgreSQL‬و ‪. SQLite‬‬
‫َّ‬
‫ومضمن في بايثون‪ ،‬كما‬
‫سنركز في هذا الكتاب على ‪ SQLite‬لكونه قاعدة بيانات شائعة االستخدام‬
‫صممت بطريقة تسمح بتضمينها في التطبيقات املختلفة لتأمين دعم قواعد البيانات فيها‪ .‬على سبيل‬
‫ً‬
‫داخليا كحال تطبيقات أخرى وموقعها‬
‫املثال يستخدم متصفح ‪ Firefox‬قاعدة بيانات ‪SQLite‬‬
‫‪ http://sqlite.org/‬وهي مناسبة للتعامل مع مسائل التالعب بالبيانات كالتي نشهدها في مجال‬
‫املعلوماتية مثل استكشاف (‪ )spidering‬موقع تويتر (آلية تستخدم في محركات البحث لالكتشاف‬
‫والوصول إلى جميع صفحات الويب على شبكة االنترنت لفهرستها في هذا البرنامج‪ ،‬يكتشف البرنامج‬
‫قائمة أصدقاء حساب ما على تويتر ويستخدمه لكشف أصدقائهم وهكذا) الذي سنتحدث عنه في‬
‫هذا الفصل‪.‬‬
‫‪ 2.15‬مفاهيم في قواعد البيانات‬
‫للوهلة األولى‪ ،‬تشبه قاعدة البيانات الجدول املليء بالحقول‪ ،‬حيث أن بنى البيانات الرئيسية فيها هي‪:‬‬
‫الجداول واألسطر واألعمدة‪ .‬بينما يشار إليهم في قواعد البيانات العالئقية كـ ‪ :‬العالقة (‪(relation‬‬
‫والصف )‪ (tuple‬والسمة )‪ (attribute‬على الترتيب‪ ،‬لذلك سنستخدم الكلمات الشائعة في هذا‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪253‬‬
‫الكتاب‪.‬‬
‫الشكل ‪ :22‬قاعدة بيانات عالئقية‬
‫‪ 3.15‬متصفح قاعدة البيانات في ‪SQLite‬‬
‫سنركز في هذا الفصل على استخدام بايثون للتعامل مع البيانات في ملفات قاعدة بيانات ‪،SQLite‬‬
‫يسهل برنامج يدعى متصفح قاعدة البيانات في ‪ SQLite‬العديد من العمليات وهو متاح ً‬
‫مجانا على‬
‫املوقع‪. http://sqlitebrowser.org/‬‬
‫بإمكانك إنشاء الجداول بسهولة بواسطة املتصفح وإدخال بيانات أو التعديل عليها أو إجراء استعالم‬
‫بسيط حول البيانات املوجودة في تلك القاعدة‪ ،‬أي أن متصفح قاعدة البيانات يشبه محرر‬
‫النصوص عند التعامل مع امللفات النصية‪ .‬فعندما تحتاج لتنفيذ عملية أو عدة عمليات على امللف‬
‫النص ي ستفتحه باستخدام محرر النصوص وتجري التعديالت التي ترغب بها‪ ،‬إال إن كان لديك‬
‫العديد من التعديالت والعمليات لتجريها فستنش ئ برنامج بايثون يساعدك في تنفيذ هذا‪ ،‬وهذا‬
‫مشابه ملا يتعلق بقواعد البيانات حيث نجري عمليات بسيطة عبر مدير قاعدة البيانات بينما نفضل‬
‫ً‬
‫تعقيدا‪.‬‬
‫بايثون للعمليات األكثر‬
‫‪ 4.15‬إنشاء جدول قاعدة بيانات‬
‫تتطلب قواعد البيانات بنية محددة أكثر من قوائم وقواميس بايثون (تتيح ‪ SQL‬مرونة أكبر فيما‬
‫يتعلق بنوع البيانات املخزنة ضمن عمود ما‪ ،‬ولكن سنبقي أنماط البيانات التي سنستخدمها محددة‬
‫بحيث تنطبق املبادئ بشكل مشابه على أنظمة قواعد بيانات أخرى مثل ‪ ، MySQL‬يجب علينا تحديد‬
‫ً‬
‫أسماء أعمدة الجدول قبل إنشائه إضافة إلى نوع البيانات التي ننوي تخزينها في تلك األعمدة ليتمكن‬
‫البرنامج من اختيار الطريقة األكثر فعالية لتخزين املعلومة والبحث عنها‪ ،‬كما يمكنك االطالع على‬
‫أنماط البيانات التي تدعمها ‪ SQLite‬عبر الرابط اآلتي‪. http://www.sqlite.org/datatypes.html :‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪254‬‬
‫ً ً ً‬
‫أمرا شاقا في بداية األمر ولكن النتيجة تكون الوصول السريع‬
‫قد يبدو لك تحديد بنية بياناتك مسبقا‬
‫إلى تلك البيانات بالرغم من احتواء قاعدة بياناتك على حجوم كبيرة من املعلومات‪.‬‬
‫إلنشاء ملف قاعدة بيانات مع جدول اسمه ‪ Tracks‬ذو عمودين بلغة بايثون نكتب الشيفرة التالية‪:‬‬
‫‪import sqlite3‬‬
‫)'‪conn = sqlite3.connect('music.sqlite‬‬
‫)(‪cur = conn.cursor‬‬
‫)'‪cur.execute('DROP TABLE IF EXISTS Tracks‬‬
‫)')‪cur.execute('CREATE TABLE Tracks (title TEXT, plays INTEGER‬‬
‫)(‪conn.close‬‬
‫‪# Code: http://www.py4e.com/code3/db1.py‬‬
‫ً‬
‫تنش ئ تعليمة ‪ connect‬اتصاال مع قاعدة البيانات املوجودة ضمن امللف ‪ music.sqlite‬في املجلد‬
‫ً‬
‫الحالي‪ٌ ،‬‬
‫مسبقا وسبب تسمية هذه العملية باالتصال فهو بسبب‬
‫وسينشأ امللف في حال عدم وجوده‬
‫احتمال وجود قاعدة البيانات على خادم قواعد بيانات منفصل وهو الخادم الذي شغلنا تطبيقنا‬
‫عن طريقه‪ ،‬أما في أمثلتنا القادمة فستكون قاعدة البيانات ملف محلي موجود بنفس مجلد برنامج‬
‫بايثون الذي سننفذه‪.‬‬
‫يشبه املؤشر )‪َ (cursor‬‬
‫معرف امللف (‪ )file handle‬حيث نستخدمه لتنفيذ عمليات معينة على قاعدة‬
‫البيانات‪ ،‬استدعاء التابع )( ‪ cursor‬يشبه من حيث املبدأ استدعاء التابع )( ‪ open‬عند التعامل مع‬
‫امللفات النصية‪.‬‬
‫الشكل ‪ :23‬مؤشر قاعدة البيانات‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪255‬‬
‫نستطيع بدء تنفيذ األوامر على محتويات قاعدة البيانات مستخدمين التابع )(‪ excute‬بمجرد‬
‫حصولنا على املؤشر‪ُ ،‬وي َّ‬
‫عبر عن تلك األوامر بلغة خاصة موحدة من قبل مجموعة من شركات قواعد‬
‫ً‬
‫اختصارا ‪SQL‬‬
‫البيانات‪ ،‬األمر الذي يتيح لنا تعلم لغة واحدة وتسمى لغة االستعالم البنيوية أو‬
‫ويمكنك االطالع على معلومات عنها عبر الرابط‪. http://en.wikipedia.org/wiki/SQL :‬‬
‫نفذنا تعليمتين من تعليمات قواعد البيانات في مثالنا السابق حيث سنكتب الكلمات املفتاحية لهذه‬
‫اللغة بأحرف كبيرة واألجزاء التي سنضيفها على األوامر املستخدمة بأحرف صغيرة (كأسماء الجداول‬
‫واألعمدة)‪.‬‬
‫ً‬
‫مسبقا مما يسمح لنا‬
‫تحذف التعليمة األولى الجدول ‪ Tracks‬من قاعدة البيانات إذا كان موجود‬
‫ً‬
‫بإنشاء الجدول‬
‫مجددا في كل مرة تشغيل بدون حدوث أخطاء‪ ،‬مع مالحظة أن تعليمة ‪DROP TABLE‬‬
‫تحذف الجدول مع جميع محتوياته من قاعدة البيانات (ال يمكن التراجع عن العملية)‪.‬‬
‫)'‪cur.execute('DROP TABLE IF EXISTS Tracks‬‬
‫بينما تنش ئ التعليمة الثانية جدول اسمه ‪ Tracks‬ذو عمود باسم ‪ title‬محتوياته نصية وعمود باسم‬
‫‪ play‬محتوياته أعداد صحيحة‪.‬‬
‫)')‪cur.execute('CREATE TABLE Tracks (title TEXT, plays INTEGER‬‬
‫نستطيع بعد إنشاء الجدول إضافة بعض البيانات إليه باستخدام عملية ‪ INSERT‬وهذا بعد إنشاء‬
‫اتصال جديد مع قاعدة البيانات والحصول على املؤشر لنتمكن من تنفيذ أوامر ‪ SQL‬باستخدام‬
‫ذلك املؤشر‪.‬‬
‫ً‬
‫ً‬
‫جديدا بتحديد الحقول التي نريد‬
‫سطرا‬
‫يشير األمر ‪ INSERT‬إلى الجدول الذي نستخدمه ثم يعرف‬
‫تضمينها )‪ (title, plays‬متبوعة بالقيم التي نريد إدخالها إلى السطر الجديد‪ ،‬كما نكتب القيم‬
‫ستدخل ً‬
‫كعالمات استفهام (?‪ )?,‬لنبين أن تلك القيم الفعلية ُ‬
‫الحقا كصف )‪ ('My way', 15‬في‬
‫املعامل الثاني للتابع )( ‪execute‬‬
‫‪import sqlite3‬‬
‫)'‪conn = sqlite3.connect('music.sqlite‬‬
‫)(‪cur = conn.cursor‬‬
‫))‪cur.execute('INSERT INTO Tracks (title, plays) VALUES (?, ?)', ('Thunderstruck', 20‬‬
‫))‪cur.execute('INSERT INTO Tracks (title, plays) VALUES (?, ?)', ('My Way', 15‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪256‬‬
‫)(‪conn.commit‬‬
‫)'‪print('Tracks:‬‬
‫)'‪cur.execute('SELECT title, plays FROM Tracks‬‬
‫‪for row in cur:‬‬
‫)‪print(row‬‬
‫)'‪cur.execute('DELETE FROM Tracks WHERE plays < 100‬‬
‫)(‪conn.commit‬‬
‫)(‪cur.close‬‬
‫‪# Code: http://www.py4e.com/code3/db2.py‬‬
‫الشكل‪ : 24‬األسطر في الجدول‬
‫ً‬
‫نضيف بداية سطرين إلى الجدول باستخدام ‪ INSERT‬ثم نستخدم )(‪ commit‬لكتابة البيانات ضمن‬
‫قاعدة البيانات‪ ،‬ثم نستخدم األمر ‪ SELECT‬الستدعاء الصفوف التي أدخلناها ً‬
‫سابقا إلى الجدول‬
‫ونحدد فيه األعمدة التي نريد )‪ (title, plays‬كما نحدد أي جدول نريد استخراج البيانات منه‪ ،‬وبعد‬
‫تنفيذ ‪ SELECT‬يصبح بإمكاننا املرور على محتويات املؤشر باستخدام حلقة ‪ ،for‬مع العلم أن املؤشر‬
‫ال يقرأ جميع محتويات قاعدة البيانات عند استخدام تعليمة ‪ SELECT‬وذلك لزيادة الكفاءة حيث‬
‫يقرأ البيانات التي نحتاجها وفق تكرارات حلقة ‪ for‬ويكون خرج البرنامج كما يأتي‪:‬‬
‫‪Tracks:‬‬
‫)‪('Thunderstruck', 20‬‬
‫)‪('My Way', 15‬‬
‫تستخرج الحلقة سطرين عبارة عن صفوف بحيث تكون القيمة األولى هي العنوان ‪ title‬والقيمة‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪257‬‬
‫الثانية عبارة عن عدد مرات تشغيل األغنية ‪.plays‬‬
‫ً‬
‫مالحظة‪ :‬قد تجد سالسل نصية تبدأ بحرف '‪ 'u‬في كتب أخرى أو على اإلنترنت حيث كان هذا دليال في‬
‫إصدار بايثون ‪ 2‬على كون السالسل مرمزة بترميز ‪ Unicode‬أي سالسل تتضمن مجموعة املحارف‬
‫غير الالتينية لكن في بايثون اإلصدار ‪ 3‬جميع السالسل هي ‪ Unicode‬افتر ً‬
‫اضيا‪.‬‬
‫ننفذ في نهاية البرنامج أمر الحذف ‪ DELETE‬إلزالة الصفوف التي أنشأناها لنتمكن من إعادة تشغيل‬
‫البرنامج عدة مرات‪ ،‬كما يظهر هذه األمر استخدام عبارة ‪ WHERE‬والتي تسمح لنا بتحديد الصفوف‬
‫التي ستنفذ عليها تعليمة الحذف‪ ،‬ولكن صدف في هذا املثال أن طابق معيار التحديد جميع صفوف‬
‫قاعدة البيانات إلخالء الجدول وتشغيل البرنامج بشكل متكرر‪ ،‬ونستدعي )(‪ commit‬بعد تنفيذ‬
‫‪ DELETE‬لتأكيد حذف البيانات من قاعدة البيانات‪.‬‬
‫ّ‬
‫البنيوية ‪SQL‬‬
‫‪ 5.15‬ملخص عن لغة االستعالم‬
‫استخدمنا لحد اآلن لغة ‪ SQL‬في برامج بايثون السابقة وذكرنا العديد من أوامرها األساسية‪ ،‬لذا‬
‫سنركز عليها بشكل أكبر في هذا القسم وسنقدم نظرة عامة على قواعد هذه اللغة‪ ،‬وباعتبار وجود‬
‫شركات عدة مختصة بقواعد البيانات فقد ُحددت ‪ SQL‬كلغة معيارية لنتمكن من التواصل‬
‫باستخدام مختلف أنظمة قواعد البيانات التابعة لتلك الشركات‪.‬‬
‫إن قواعد البيانات العالئقية مكونة من جداول وسطور وأعمدة حيث تكون األعمدة ذات نوع معين‬
‫نص ي أو رقمي أو تواريخ وعند إنشاء جدول نصرح بأسماء وأنواع األعمدة مثال‪:‬‬
‫)‪CREATE TABLE Tracks (title TEXT, plays INTEGER‬‬
‫وإلضافة سطر جديد ضمن الجدول نستخدم األمر ‪ INSERT‬في لغة ‪ SQL‬مثال‪:‬‬
‫)‪INSERT INTO Tracks (title, plays) VALUES ('My Way', 15‬‬
‫تحدد هذه التعليمة اسم الجدول ومجموعة من الحقول (األعمدة) التي تود إضافتها للسطر الجديد‪،‬‬
‫كما تضيف الكلمة املفتاحية ‪ VALUES‬مجموعة من القيم املوافقة لكل حقل‪.‬‬
‫ُيستخدم األمر ‪ SELECT‬الستدعاء السطور واألعمدة التي نحتاجها من قاعدة البيانات أما عبارة‬
‫‪ WHERE‬تظهر السطور املطلوبة‪ ،‬كما يمكن استخدام عبارة ‪ ORDER BY‬عند الحاجة للتحكم‬
‫بترتيب الصفوف املستدعاة مثال‪:‬‬
‫'‪SELECT * FROM Tracks WHERE title = 'My Way‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪258‬‬
‫يدل استخدام رمز النجمة * على استدعاء جميع أعمدة لكل األسطر التي تحقق شرط عبارة‬
‫ً‬
‫‪ ،WHERE‬وعلى عكس بايثون نستخدم هنا إشارة يساوي واحدة في هذا الشرط بدال من إشارتين‪،‬‬
‫بينما تكون بقية العمليات املنطقية املتاحة مع ‪ WHERE‬هي نفسها <‪ ،!= ،<= ،>= ،> ،‬إضافة إلى‬
‫األقواس واستخدام ‪ AND‬و‪.OR‬‬
‫ً‬
‫اعتمادا على أحد الحقول مثال‪:‬‬
‫تستطيع تحديد ترتيب الصفوف‬
‫‪SELECT title,plays FROM Tracks ORDER BY title‬‬
‫ولحذف سطر ما تحتاج الستخدام تعليمة ‪ DELETE‬وعبارة ‪ WHERE‬لتحديد أي السطور تريد حذفها‬
‫مثال‪:‬‬
‫'‪DELETE FROM Tracks WHERE title = 'My Way‬‬
‫يمكن ً‬
‫أيضا تحديث قيمة أحد األعمدة أو كلها ضمن سطر أو أكثر في جدول ما باستخدام تعليمة‬
‫‪ UPDATE‬كما يأتي‪:‬‬
‫'‪UPDATE Tracks SET plays = 16 WHERE title = 'My Way‬‬
‫ٌتحدد هذه التعليمة جدول معين ثم مجموعة القيم املطلوب تغييرها بعد تعليمة ‪ SET‬أما عبارة‬
‫ُ‬
‫‪ WHERE‬فلتحديد الصفوف املراد تحديثها‪ ،‬وتعدل تعليمة ‪ UPDATE‬كافة السطور التي توافق شرط‬
‫‪ WHERE‬أو جميع سطور الجدول في حال عدم استخدام ‪.WHERE‬‬
‫تسمح تعليمات ‪ SQL‬األربعة هذه ( ‪ INSERT‬و ‪ SELECT‬و ‪ UPDATE‬و ‪ (DELETE‬بتنفيذ عمليات إنشاء‬
‫وتعديل البيانات‪.‬‬
‫‪ 6.15‬استكشاف تويترباستخدام قواعد البيانات‬
‫سنكتب في هذا القسم برنامج استكشاف أو تعقب يمر على حسابات تويتر ويسجل بياناتهم ضمن‬
‫قاعدة بيانات (كن ً‬
‫حذرا عند تشغيل هذا البرنامج كي ال تتسبب في إلغاء وصولك إلى تويتر إن‬
‫استخرجت كم كبير من البيانات أو استخدمت البرنامج ً‬
‫كثيرا)‪.‬‬
‫إحدى مشاكل هذه البرامج احتياجنا إلعادة تشغيله عدة مرات دون فقد البيانات التي قد استخرجتها‬
‫وإعادة استدعائها مرة أخرى من البداية لذلك نود تخزين تلك البيانات ليتمكن برنامجنا من إكمال‬
‫العمل من نقطة توقفه‪.‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪259‬‬
‫سنبدأ باستخراج قائمة أصدقاء حساب تويتر معين ومنشوراته (تغريداته) ثم سنمر باستخدام‬
‫ً‬
‫الحلقات على قائمة األصدقاء لنضيفهم إلى قاعدة بيانات الستدعائهم مستقبال‪ ،‬بعد ذلك نأخذ اسم‬
‫حساب أحد األصدقاء لنستدعي قائمة أصدقائه ونضيف أسماء األصدقاء التي لم ترد في قاعدة‬
‫البيانات ً‬
‫سابقا ونتابع هذه العملية للصديق التالي وهكذا‪ ،‬ثم نحسب عدد مرات تكرار اسم أحد‬
‫األصدقاء كتعبير عن شعبيته‪ ،‬ويصبح بإمكاننا بعد انتهاء هذه العملية إعادة تشغيل البرنامج مر ًارا‬
‫ً‬
‫معقدا بعض الش يء حيث يعتمد على البرامج املكتوبة في تمارين‬
‫وتكر ًارا‪ ،‬كما يعتبر هذا البرنامج‬
‫سابقة والتي تستخدم واجهة برمجية ‪ API‬لتويتر‪ ،‬وتكون الشيفرة املصدرية له كاآلتي‪:‬‬
‫‪from urllib.request import urlopen‬‬
‫‪import urllib.error‬‬
‫‪import twurl‬‬
‫‪import json‬‬
‫‪import sqlite3‬‬
‫‪import ssl‬‬
‫'‪TWITTER_URL = 'https://api.twitter.com/1.1/friends/list.json‬‬
‫)'‪conn = sqlite3.connect('spider.sqlite‬‬
‫)(‪cur = conn.cursor‬‬
‫' ' ' (‪cur.execute‬‬
‫‪CREATE TABLE IF NOT EXISTS Twitter‬‬
‫)' ' ')‪(name TEXT, retrieved INTEGER, friends INTEGER‬‬
‫‪# Ignore SSL certificate errors‬‬
‫)(‪ctx = ssl.create_default_context‬‬
‫‪ctx.check_hostname = False‬‬
‫‪ctx.verify_mode = ssl.CERT_NONE‬‬
SQL ‫ استخدام قواعد البيانات ولغة‬:‫الفصل الخامس عشر‬
260
while True:
acct = input('Enter a Twitter account, or quit: ')
if (acct == quit): break
if (len(acct) < 1) :
cur.execute('SELECT name FROM Twitter WHERE retrieved = 0
LIMIT 1')
try:
acct = cur.fetchone()[0]
except:
print('No unretrieved Twitter accounts found')
continue
url = twurl.augment(TWITTER_URL, {'screen_name': acct, 'count': '20'} )
print('Retrieving', url)
connection = urlopen(url, context=ctx)
data = connection.read().decode()
headers = dict(connection.getheaders())
print('Remaining', headers['x-rate-limit-remaining'])
js = json.loads(data)
# Debugging
# print json.dumps(js, indent=4)
cur.execute('UPDATE Twitter SET retrieved=1 WHERE name = ? ', (acct, ))
countnew = 0
countold = 0
for u in js['users']:
friend = u['screen_name']
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪261‬‬
‫)‪print(friend‬‬
‫‪cur.execute('SELECT friends FROM Twitter WHERE name = ? LIMIT 1',‬‬
‫)) ‪(friend,‬‬
‫‪try:‬‬
‫]‪count = cur.fetchone()[0‬‬
‫‪cur.execute('UPDATE Twitter SET friends = ? WHERE name‬‬
‫))‪=?', (count+1,friend‬‬
‫‪countold = countold + 1‬‬
‫‪except:‬‬
‫‪cur.execute(''' INSERT INTO Twitter (name, retrieved, friends) VALUES‬‬
‫)) ‪(?, 0, 1) ''', (friend,‬‬
‫‪countnew = countnew + 1‬‬
‫)‪print('New accounts=', countnew, 'revisited=', countold‬‬
‫)(‪conn.commit‬‬
‫)(‪cur.close‬‬
‫‪# Code: http://www.py4e.com/code3/twspider.py‬‬
‫إن قاعدة بياناتنا مخزنة في امللف ‪ spider.sqlite‬وتحتوي جدول واحد اسمه ‪ ،Twitter‬حيث كل سطر‬
‫في هذا الجدول يحوي عمود باسم ‪ name‬السم الحساب وعمود باسم ‪ retrieved‬يدل إن كنا قد‬
‫استخرجنا قائمة أصدقائه وعمود باسم ‪ friends‬يمثل عدد مرات إضافته كصديق‪.‬‬
‫سنطلب من املستخدم في الحلقة الرئيسية للبرنامج إدخال حساب تويتر أو كتابة كلمة ‪ quit‬للخروج‬
‫من البرنامج‪ ،‬فإن أدخل حساب تويتر سنستخرج قائمة أصدقائه ونخزنها في قاعدة البيانات في حال‬
‫ً‬
‫ً‬
‫مسبقا فنزيد بمقدار ‪ 1‬خانة ‪ friends‬في السطر‬
‫مسبقا‪ ،‬وإن كان اسم الصديق موجود‬
‫عدم وجودها‬
‫املخصص في قاعدة البيانات‪ ،‬وفي حال ضغط املستخدم مفتاح ‪- enter‬بدون كتابة أي ش يء‪ -‬نبدأ‬
‫ً‬
‫مسبقا‪ -‬لنضيفهم إلى قاعدة‬
‫باستخراج قائمة أصدقاء الحساب التالي ‪ -‬من القائمة التي استخرجناها‬
‫البيانات أو نحدث بياناتهم ونزيد عداد أصدقائهم (أي الخانة ‪ ،)friends‬وبمجرد االنتهاء من عملية‬
‫االستخراج نمر على كامل عناصر القاموس ‪ users‬في شيفرة ‪ JSON‬املعادة لنستخرج اسم الحساب‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪262‬‬
‫(املخزن في املتغير‪ )screen_name‬لكل مستخدم‪ ،‬ثم نستخدم تعليمة ‪ SELECT‬لنتحقق فيما إذا كان‬
‫ً‬
‫االسم ً‬
‫مخزنا في قاعدة البيانات وإن كان ٌمسجال نستعيد عداد األصدقاء ونحدث قيمته‪.‬‬
‫‪countnew = 0‬‬
‫‪countold = 0‬‬
‫‪for u in js['users'] :‬‬
‫]'‪friend = u['screen_name‬‬
‫)‪print(friend‬‬
‫‪cur.execute('SELECT friends FROM Twitter WHERE name = ? LIMIT 1',‬‬
‫) ) ‪(friend,‬‬
‫‪try:‬‬
‫]‪count = cur.fetchone()[0‬‬
‫‪cur.execute('UPDATE Twitter SET friends = ? WHERE name = ? ',‬‬
‫) )‪(count+1,friend‬‬
‫‪countold = countold + 1‬‬
‫‪except:‬‬
‫‪cur.execute('INSERT INTO Twitter (name, retrieved, friends) VALUES ( ?,‬‬
‫) ) ‪0, 1 ) ', ( friend,‬‬
‫‪countnew = countnew + 1‬‬
‫)‪print('New accounts'=,countnew, 'revisited=',countold‬‬
‫)(‪conn.commit‬‬
‫ويجب أن نستعيد السطور بمجرد تنفيذ تعليمة ‪ SELECT‬باستخدام حلقة ‪ for‬ولكن من األفضل‬
‫كوننا سنستعيد سطر واحد (‪ )LIMIT 1‬استخدام التابع )(‪ fetchone‬لجلب السطر األول والوحيد‬
‫الناتج عن األمر ‪ ،SELECT‬وبما أن هذا التابع يعيد السطر كصف (بالرغم من وجود خانة واحدة)‬
‫نأخذ أول قيمة من الصف ]‪ [0‬لنحصل على قيمة عداد األصدقاء الحالي ونضعها في املتغير ‪،count‬‬
‫وفي حال نجاح هذه العملية نستعمل األمر ‪ Update‬مع عبارة ‪ WHERE‬لزيادة ‪ 1‬إلى قيمة عامود عداد‬
‫األصدقاء ‪ friends‬في السطر املوافق لحساب الصديق املطلوب‪ ،‬مع مالحظة وجود عنصرين نائبين‬
‫(عالمات االستفهام) في شيفرة ‪ SQL‬حيث املعامل الثاني للتابع )( ‪ execute‬هو صف ذو عنصرين‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪263‬‬
‫يحتوي القيم البديلة لعالمات االستفهام‪.‬‬
‫ً‬
‫فغالبا السبب هو عدم تطابق أي سجل مع العبارة ‪WHERE‬‬
‫إن حدث فشل في تنفيذ تعليمات ‪try‬‬
‫?=‪ name‬ضمن تعليمة ‪ SELECT‬لذلك نستخدم ضمن تعليمة ‪ except‬تعليمة ‪ INSERT‬إلضافة‬
‫االسم الجديد ‪ screen_name‬إلى الجدول مع وضع قيمة ‪ 0‬في خانة ‪ retrived‬لتشير إلى عدم استدعاء‬
‫االسم بعد ثم نسند قيمة ‪ 1‬إلى خانة عداد األصدقاء‪.‬‬
‫كخالصة عند تشغيل البرنامج للمرة األولى ندخل اسم حساب تويتر‪ ،‬فيعمل كاآلتي‪:‬‬
‫‪Enter a Twitter account, or quit: drchuck‬‬
‫‪Retrieving http://api.twitter.com/1.1/friends ...‬‬
‫‪New accounts= 20 revisited= 0‬‬
‫‪Enter a Twitter account, or quit: quit‬‬
‫وباعتبارها املرة األولى لتشغيل البرنامج تكون قاعدة البيانات فارغة وننشئها ضمن امللف‬
‫‪ spider.sqlite‬مع إضافة جدول باسم ‪ ،Twitter‬ثم نستخرج بعض أسماء األصدقاء ونضيفهم إلى‬
‫قاعدة البيانات‪ ،‬ولربما ترغب بكتابة تعليمات تظهر لك مضمون امللف بعد تنفيذ ما سبق‪:‬‬
‫‪import sqlite3‬‬
‫)'‪conn = sqlite3.connect('spider.sqlite‬‬
‫)(‪cur = conn.cursor‬‬
‫)'‪cur.execute('SELECT * FROM Twitter‬‬
‫‪count = 0‬‬
‫‪for row in cur:‬‬
‫)‪print(row‬‬
‫‪count = count + 1‬‬
‫)' ‪print(count, 'rows.‬‬
‫)(‪cur.close‬‬
‫‪# Code: http://www.py4e.com/code3/twdump.py‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪264‬‬
‫ببساطة يفتح هذا البرنامج قاعدة البيانات ويحدد جميع األعمدة لكل األسطر ضمن جدول ‪،Twitter‬‬
‫ثم يمر على كل سطر ويعرضه‪ ،‬ويكون خرجه عند تنفيذ أول عملية استكشاف كما يأتي‪:‬‬
‫)‪('opencontent', 0, 1‬‬
‫)‪('lhawthorn', 0, 1‬‬
‫)‪('steve_coppin', 0, 1‬‬
‫)‪('davidkocher', 0, 1‬‬
‫)‪('hrheingold', 0, 1‬‬
‫‪...‬‬
‫‪20 rows.‬‬
‫لكل‬
‫نالحظ وجود سطر واحد لكل اسم ‪ screen_name‬لم نستخرج بياناته حيث يوجد صديق واحد ٍ‬
‫منهم ضمن قاعدة البيانات‪ ،‬حيث تعكس هذه القاعدة عملية استخراج أصدقاء حساب تويتر معين‬
‫للمرة األولى‪ ،‬كما باستطاعتنا إعادة تشغيل البرنامج لنستخرج أصدقاء الحساب التالي‪ ،‬وذلك عن‬
‫ً‬
‫طريق الضغط على مفتاح ‪ enter‬بدال من إدخال اسم حساب جديد كما يأتي‪:‬‬
‫‪Enter a Twitter account, or quit:‬‬
‫‪Retrieving http://api.twitter.com/1.1/friends ...‬‬
‫‪New accounts= 18 revisited= 2‬‬
‫‪Enter a Twitter account, or quit:‬‬
‫‪Retrieving http://api.twitter.com/1.1/friends ...‬‬
‫‪New accounts= 17 revisited= 3‬‬
‫‪Enter a Twitter account, or quit: quit‬‬
‫وتكون الشيفرة البرمجية املنفذة هي ‪:‬‬
‫‪if (len(acct) < 1) :‬‬
‫‪cur.execute('SELECT name FROM Twitter WHERE‬‬
‫)'‪retrieved = 0 LIMIT 1‬‬
‫‪try:‬‬
‫]‪acct = cur.fetchone()[0‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪265‬‬
‫‪except:‬‬
‫)'‪print('No unretrieved twitter accounts found‬‬
‫‪continue‬‬
‫ثم نستخدم األمر ‪ SELECT‬الستخراج اسم املستخدم األول )‪ (LIMT 1‬صاحب القيمة الصفرية في‬
‫عامود ‪ ،retrived‬كما نستخدم العبارة ]‪ fetchone()[0‬ضمن كتلة ‪ try/except‬الستخراج االسم‬
‫‪ screen_name‬من البيانات املستعادة أو العودة للمرور على بقية املستخدمين‪ ،‬وفي حال نجحنا‬
‫باستدعاء االسم لحساب غير مكتشف فنستخرج بياناته كما يلي‪:‬‬
‫)}'‪url=twurl.augment(TWITTER_URL,{ 'screen_name': acct, 'count': '20‬‬
‫)‪print('Retrieving', url‬‬
‫)‪connection = urllib.urlopen(url‬‬
‫)(‪data = connection.read‬‬
‫)‪js = json.loads(data‬‬
‫)) ‪cur.execute('UPDATE Twitter SET retrieved=1 WHERE name = ? ',(acct,‬‬
‫نستخدم تعليمة ‪ UPDATE‬بمجرد نجاح العملية السابقة‪ ،‬وذلك لتغيير قيمة العمود ‪ retrieved‬إلى‬
‫الواحد لإلشارة إلى انتهاء عملية استخراج قائمة أصدقاء املستخدم لعدم استخراج نفس البيانات‬
‫مر ًارا وتكر ًارا والسماح لنا بالتقدم عبر شبكة األصدقاء في تويتر‪.‬‬
‫عند تشغيل البرنامج والضغط على مفتاح ‪ enter‬مرتين الستخراج أصدقاء الصديق نحصل على‬
‫الخرج اآلتي‪:‬‬
‫)‪('opencontent', 1, 1‬‬
‫)‪('lhawthorn', 1, 1‬‬
‫)‪('steve_coppin', 0, 1‬‬
‫)‪('davidkocher', 0, 1‬‬
‫)‪('hrheingold', 0, 1‬‬
‫‪...‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪266‬‬
‫)‪('cnxorg', 0, 2‬‬
‫)‪('knoop', 0, 1‬‬
‫)‪('kthanos', 0, 2‬‬
‫)‪('LectureTools', 0, 1‬‬
‫‪...‬‬
‫‪55 rows.‬‬
‫كما نرى فقد وثقنا زيارة الحسابين ‪ lhawthorn‬و ‪ opencontent‬ونالحظ وجود متابعين لكل من‬
‫الحسابين ‪ cnxorg‬و‪ ،kthanos‬وبما أننا استخرجنا قائمة أصدقاء ثالثة أشخاص حتى اآلن وهم‬
‫سطر من األصدقاء‬
‫‪ drchuck‬و ‪ opencontent‬و‪ lhawthorn‬فإن جدولنا األن يحتوي على ‪55‬‬
‫ٍ‬
‫الستخراج بياناتهم‪ ،‬وفي كل مرة تشغيل سيختار البرنامج الحساب التالي غير املزار بعد ضغط ‪enter‬‬
‫(على سبيل املثال الحساب التالي الواجب معالجته هو‪ )steve_coppin‬ثم نستخرج قائمة األصدقاء‬
‫لهذا الحساب ونضيفهم لنهاية قاعدة البيانات أو نحدث عداد أصدقائهم إن كانوا موجودين ضمن‬
‫ً‬
‫الجدول‬
‫مسبقا‪ ،‬وباعتبار أن بيانات البرنامج مخزنة على قرص في قاعدة بيانات فيمكن إيقاف عملية‬
‫االكتشاف ً‬
‫مؤقتا وإكمالها بعدد املرات الذي نحتاجه دون فقد البيانات‪.‬‬
‫‪ 7.15‬نمذجة البيانات‬
‫تكمن قوة قاعدة البيانات العالئقية الحقيقية في إمكانية إنشاء عدة جداول وربطها ببعضها البعض‪،‬‬
‫وتدعى عملية تقسيم البيانات إلى عدد من الجداول وإنشاء روابط بينها بنمذجة البيانات ( ‪data‬‬
‫‪ ،)modeling‬ويدعى املخطط الذي يظهر الجداول والعالقات بينها بنموذج البيانات‪.‬‬
‫تتطلب عملية نمذجة البيانات مهارات وخبرة كبيرة ً‬
‫نسبيا لذلك سنتطرق إلى أساسيات نمذجة قواعد‬
‫البيانات العالئقية في هذا القسم من الفصل‪ ،‬وللحصول على مزيد من املعلومات حول هذا املوضوع‬
‫بإمكانك زيارة الرابط اآلتي‪. http://en.wikipedia.org/wiki/Relational_model :‬‬
‫فلنفترض أننا أردنا إنشاء قائمة تبين جميع عالقات األصدقاء ببعضهم البعض في البرنامج السابق‬
‫ً‬
‫بدال من إحصاء أصدقاء كل شخص فحسب بهدف الحصول على قائمة جميع األشخاص املتابعين‬
‫لحساب تويتر معين‪ ،‬وبما أن كل حساب قد يكون ُمتابع من عدة حسابات أخرى فال نستطيع االكتفاء‬
‫بإضافة عمود واحد إلى جدول ‪ ،Twitter‬لذا ننش ئ جدول جديد منفصل لنحدد طرفي الصداقة‪،‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪267‬‬
‫ونوضح في الشيفرة التالية طريقة التنفيذ‪:‬‬
‫)‪CREATE TABLE Pals (from_friend TEXT, to_friend TEXT‬‬
‫وفي كل مرة نضيف شخص ٌيتابعه ‪ drchuck‬نضيف سطر كالتالي‪:‬‬
‫)'‪INSERT INTO Pals (from_friend,to_friend) VALUES ('drchuck', 'lhawthorn‬‬
‫وبما أننا سنتعامل مع ‪ 20‬صديق من أصدقاء حساب تويتر الخاص بـ " ‪ " drchuck‬أي سنضيف ‪20‬‬
‫مرة اسم " ‪ " drchuck‬باعتباره املعامل األول مما يعني إعادة ذكر اسم الحساب عدة مرات في قاعدة‬
‫البيانات‪ ،‬ينتهك هذا التكرار أهم معايير قواعد البيانات والذي ينص على أال نكرر سلسلة نصية‬
‫نفسها أكثر من مرة‪ ،‬فإن احتجنا تلك السلسلة أكثر من مرة استبدلناها برقم‪ ،‬حيث ً‬
‫عمليا تشغل‬
‫ً‬
‫حجما أكبر من األرقام على قرص التخزين وفي ذاكرة الحاسوب وتتطلب زمن‬
‫السالسل النصية‬
‫معالجة أكبر في عمليات املقارنة والترتيب‪ ،‬لكن قد يكون زمن املعالجة ومساحة التخزين غير مهمين‬
‫في حال وجود بضعة مئات فقط من املدخالت في قاعدة البيانات‪ ،‬أما إذا كان لدينا مليون شخص في‬
‫قاعدة البيانات مع احتمال وجود رابط مع ‪ 100‬مليون صديق فتكون لسرعة عملية البحث في‬
‫البيانات أهمية كبرى‪.‬‬
‫ً‬
‫سنخزن حسابات تويتر املستخرجة في جدول اسمه ‪ People‬بدال من ‪ Twitter‬املستخدم في املثال‬
‫السابق‪ ،‬ويحتوي هذا الجدول على عمود إضافي لتخزين املفتاح الرقمي املرتبط بالسطر الخاص‬
‫ً‬
‫تلقائيا ألي‬
‫بحساب تويتر محدد‪ ،‬مع األخذ بعين االعتبار أن ‪ SQLite‬تملك ميزة إضافة قيمة املفتاح‬
‫سطر ندخله للجدول باستخدام عمود ذي نوع بيانات مخصص (‪.)INTEGER PRIMARY KEY‬‬
‫ننش ئ جدول ‪ People‬مع عمود إضافي يسمى ‪ id‬كما يأتي‪:‬‬
‫‪CREATE TABLE People‬‬
‫)‪(id INTEGER PRIMARY KEY, name TEXT UNIQUE, retrieved INTEGER‬‬
‫ونالحظ أننا لم نعد نحتفظ بعداد األصدقاء في كل سطر ضمن جدول ‪ ،People‬وعند تحديد نوع‬
‫العمود ‪ id‬كـ (‪ )INTEGER PRIMARY KEY‬فهذا يعني أننا نرغب في أن تسند ‪ SQLite‬رقم فريد لكل‬
‫ً‬
‫تلقائيا‪ ،‬كما أضفنا الكلمة املفتاحية ‪ UNIQUE‬لإلشارة إلى عدم سماحنا بإدخال‬
‫سطر ندخله‬
‫ً‬
‫سطرين بنفس القيمة للخانة ‪ ،name‬وبدال من إنشاء جدول ‪ Pals‬كما فعلنا أعاله سننش ئ جدول‬
‫يدعى ‪ Follows‬ذي عمودين كالهما من نوع عدد صحيح وسندعوهما ‪ from_id‬و ‪ to_id‬ونركز على‬
‫كون كل زوج من هاتين الخانتين فريد في الجدول (أي ال نستطيع تكرار السطر) في قاعدة البيانات‪.‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪268‬‬
‫‪CREATE TABLE Follows‬‬
‫) )‪(from_id INTEGER, to_id INTEGER, UNIQUE(from_id, to_id‬‬
‫نحدد عند إضافة عبارة ‪ UNIQUE‬للجداول مجموعة قواعد نطلب من قاعدة البيانات تنفيذها‬
‫أثناء إدخالنا السجالت‪ ،‬وغرضنا من وضع هذه القواعد هو جعل برنامجنا أسهل ومريح أكثر كما‬
‫سنرى ً‬
‫الحقا فهذه القواعد تمنعنا من ارتكاب األخطاء وتسهل كتابة جزء من برنامجنا‪ ،‬وباختصار‬
‫ً‬
‫ً‬
‫شخصا آخر‬
‫نموذجا للعالقة بين األشخاص عندما يتابع أحدهم‬
‫فإن إنشاء جدول ‪ Follows‬يمثل‬
‫وذلك من خالل زوج من األرقام التي تشير إلى وجود عالقة بين هؤالء األشخاص واتجاه هذه العالقة‪.‬‬
‫‪ 8.15‬برمجة قاعدة البيانات ذات الجداول املتعددة‬
‫سنعدل على برنامج اكتشاف تويتر بحيث يحوي جدولين للمفاتيح األساسية وعالقات املفاتيح كما‬
‫وضحنا أعاله‪ ،‬ويكون البرنامج كما يأتي‪:‬‬
‫الشكل ‪ : 25‬العالقات بين الجداول‬
‫‪import urllib.request, urllib.parse, urllib.error‬‬
‫‪import twurl‬‬
‫‪import json‬‬
SQL ‫ استخدام قواعد البيانات ولغة‬:‫الفصل الخامس عشر‬
269
import sqlite3
import ssl
TWITTER_URL = 'https://api.twitter.com/1.1/friends/list.json'
conn = sqlite3.connect('friends.sqlite')
cur = conn.cursor()
cur.execute('''CREATE TABLE IF NOT EXISTS People (id INTEGER
PRIMARY KEY, name TEXT UNIQUE, retrieved INTEGER)''')
cur.execute('''CREATE TABLE IF NOT EXISTS Follows (from_id INTEGER,
to_id INTEGER, UNIQUE(from_id, to_id))''')
# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
while True:
acct = input('Enter a Twitter account, or quit: ')
if (acct == 'quit'): break
if (len(acct) < 1):
cur.execute('SELECT id, name FROM People WHERE retrieved=0
LIMIT 1')
try:
(id, acct) = cur.fetchone()
except:
SQL ‫ استخدام قواعد البيانات ولغة‬:‫الفصل الخامس عشر‬
270
print('No unretrieved Twitter accounts found')
continue
else:
cur.execute('SELECT id FROM People WHERE name = ? LIMIT 1',
(acct, ))
try:
id = cur.fetchone()[0]
except:
cur.execute('''INSERT OR IGNORE INTO People
(name, retrieved)
VALUES (?, 0)''', (acct, ))
conn.commit()
if cur.rowcount != 1:
print('Error inserting account:', acct)
continue
id = cur.lastrowid
url = twurl.augment(TWITTER_URL, {'screen_name': acct, 'count': '100'})
print('Retrieving account', acct)
try:
connection = urllib.request.urlopen(url, context=ctx)
except Exception as err:
print('Failed to Retrieve', err)
break
data = connection.read().decode()
headers = dict(connection.getheaders())
SQL ‫ استخدام قواعد البيانات ولغة‬:‫الفصل الخامس عشر‬
271
print('Remaining', headers['x-rate-limit-remaining'])
try:
js = json.loads(data)
except:
print('Unable to parse json')
print(data)
break
# Debugging
# print(json.dumps(js, indent=4))
if 'users' not in js:
print('Incorrect JSON received')
print(json.dumps(js, indent=4))
continue
cur.execute('UPDATE People SET retrieved=1 WHERE name = ?', (acct, ))
countnew = 0
countold = 0
for u in js['users']:
friend = u['screen_name']
print(friend)
SQL ‫ استخدام قواعد البيانات ولغة‬:‫الفصل الخامس عشر‬
272
cur.execute('SELECT id FROM People WHERE name = ? LIMIT 1',
(friend, ))
try:
friend_id = cur.fetchone()[0]
countold = countold + 1
except:
cur.execute('''INSERT OR IGNORE INTO People (name, retrieved)
VALUES (?, 0)''', (friend, ))
conn.commit()
if cur.rowcount != 1:
print('Error inserting account:', friend)
continue
friend_id = cur.lastrowid
countnew = countnew + 1
cur.execute('''INSERT OR IGNORE INTO Follows (from_id, to_id)
VALUES (?, ?)''', (id, friend_id))
print('New accounts=', countnew, ' revisited=', countold)
print('Remaining', headers['x-rate-limit-remaining'])
conn.commit()
cur.close()
# Code: http://www.py4e.com/code3/twfriends.py
‫يبدو البرنامج وكأنه معقد بعض الش يء إال أنه يوضح األنماط البرمجية التي نحتاج الستخدامها عند‬
:‫االعتماد على مفاتيح رقمية لربط الجداول حيث تكون تلك األنماط كما يأتي‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪273‬‬
‫‪. ١‬إنشاء جداول ذات مفاتيح أساسية (‪ )primary keys‬وقيود‪.‬‬
‫ً‬
‫‪ . ٢‬عند وجود مفتاح منطقي (‪ )logical key‬لشخص ما (مثال اسم الحساب) واحتجنا ملعرفة قيمة‬
‫‪ id‬الخاصة به‪ ،‬مع األخذ بعين االعتبار وجود الشخص في جدول ‪ people‬من عدمه فسنحتاج إما‬
‫للبحث عن الشخص في جدول ‪ people‬الستخراج قيمة ‪ id‬الخاصة به أو إضافته إلى الجدول‬
‫والحصول على ‪ id‬السطر املضاف الجديد‪.‬‬
‫‪. ٣‬إدخال السطر الذي يحدد عالقة الصداقة ‪.follows‬‬
‫وسنغطي كل من هذه النقاط على حدة في الفقرات التالية‪.‬‬
‫‪ 1.8.15‬القيود في قواعد البيانات‬
‫يمكننا في مرحلة تصميم الجداول تطبيق مجموعة قواعد على قاعدة البيانات‪ ،‬لتجنب ارتكاب‬
‫األخطاء أو إدخال بيانات غير صحيحة‪ ،‬ويتم هذا باآللية التالية‪:‬‬
‫‪cur.execute('''CREATE TABLE IF NOT EXISTS People (id INTEGER PRIMARY‬‬
‫)''')‪KEY, name TEXT UNIQUE, retrieved INTEGER‬‬
‫‪cur.execute('''CREATE TABLE IF NOT EXISTS Follows (from_id INTEGER,‬‬
‫)'''))‪to_id INTEGER, UNIQUE(from_id, to_id‬‬
‫نشترط أن كل من عمود االسم ‪ name‬في جدول ‪ people‬وزوج الرقمين )‪ (from_id, to_id‬في كل سطر‬
‫من جدول ‪ follows‬فريد (غير مكرر) حيث تمنعنا هذه القيود أو القواعد من ارتكاب األخطاء كإضافة‬
‫نفس عالقة الصداقة في مثالنا السابق عدة مرات‪ ،‬ونستطيع االستفادة منها من خالل التعليمات‬
‫اآلتية‪:‬‬
‫( ‪cur.execute('''INSERT OR IGNORE INTO People (name, retrieved) VALUES ( ?, 0)''',‬‬
‫) ) ‪friend,‬‬
‫أضفنا عبارة ‪ OR IGNORE‬إلى تعليمة ‪ INSERT‬ليتم تجاهل التعليمة ‪ INSERT‬إن خالفت قاعدة‬
‫استخدام اسم فريد غير مكرر‪ ،‬أي أننا نستخدم تلك القواعد كشبكة أمان لنتأكد من عدم ارتكاب‬
‫أخطاء بدون قصد‪ ،‬وبشكل مشابه نستخدم التعليمات التالية للتأكد من عدم إضافة نفس العالقة‬
‫لجدول ‪: follows‬‬
‫‪cur.execute('''INSERT OR IGNORE INTO Follows (from_id, to_id) VALUES (?, ?)''',‬‬
‫) )‪(id, friend_id‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪274‬‬
‫أي ببساطة طلبنا من قاعدة البيانات تجاهل تعليمة اإلدخال إن كانت تنتهك قاعدة عدم التكرار في‬
‫أسطر الجدول ‪.Follows‬‬
‫‪ 2.8.15‬استعادة أو إضافة سجل في قاعدة البيانات‬
‫عندما نطلب من املستخدم إدخال اسم حساب تويتر معين ونجده ضمن قاعدة البيانات علينا‬
‫البحث عن قيمة معرفه ‪ ،id‬بينما إن لم يكن موجود في جدول ‪ people‬فعلينا إضافة السجل‬
‫والحصول على قيمة املعرف في السطر املضاف‪ ،‬وهذا أسلوب شائع ً‬
‫جدا ٌونفذ مرتين في البرنامج‬
‫السابق أعاله‪ ،‬حيث يظهر البرنامج كيفية البحث عن معرف حساب صديق ما بعد استخراج االسم‬
‫‪ screen_name‬من عقدة ‪ user‬في ملف ‪ JSON‬املستعاد‪ ،‬وباعتبار وجود احتمالية لوجود الحساب‬
‫ً‬
‫ً‬
‫ً‬
‫مسبقا في جدول ‪ people‬عن طريق تعليمة‬
‫مسبقا لذا علينا أوال تفقد وجوده‬
‫في قاعدة البيانات‬
‫‪ ،SELECT‬فإن لم نواجه أي أخطاء في بنية )‪ (try/except‬نستخرج السجل باستخدام )( ‪fetchone‬‬
‫ثم نستخرج أول عنصر (وهو العنصر الوحيد) من الصف املستعاد ونخزنه في املتحول ‪،friend_id‬‬
‫فإن فشلت تعليمة ‪ SELECT‬ستفشل تعليمات ]‪ fetchone () [0‬وسينتقل التنفيذ إلى قسم ‪except‬‬
‫]'‪friend = u['screen_name‬‬
‫'‪cur.execute('SELECT id FROM People WHERE name = ? LIMIT 1‬‬
‫) ) ‪(friend,‬‬
‫‪try:‬‬
‫]‪friend_id = cur.fetchone()[0‬‬
‫‪countold = countold + 1‬‬
‫‪except:‬‬
‫)‪cur.execute('''INSERT OR IGNORE INTO People (name, retrieved‬‬
‫) ) ‪VALUES ( ?, 0)''', ( friend,‬‬
‫)(‪conn.commit‬‬
‫‪if cur.rowcount != 1 :‬‬
‫)‪print('Error inserting account:',friend‬‬
‫‪continue‬‬
‫‪friend_id = cur.lastrowid‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪275‬‬
‫‪countnew = countnew + 1‬‬
‫ُ‬
‫وإن نفذت تعليمات قسم ‪ except‬فهذا يعني أننا لم نعثر على السطر لذلك سيتوجب علينا إضافة‬
‫السطر‪ ،‬أي نستخدم ‪ INSERT OR IGNORE‬لتجنب األخطاء ثم نستدعي )(‪ commit‬إلجبار قاعدة‬
‫البيانات إلجراء عملية تحديث للبيانات‪ ،‬وبعد انتهاء عملية الكتابة يصبح بإمكاننا تفقد قيمة‬
‫‪ cur.rowcount‬ملعرفة عدد السطور املتأثرة وإن كان عدد الصفوف املتأثرة ال يساوي الواحد فهذا‬
‫خطأ حيث أننا نعمل على إدخال صف واحد فقط‪ ،‬وإن نجحت عملية ‪ INSERT‬نستطيع تفقد قيمة‬
‫ُ َ‬
‫‪ cur.lastrowid‬ملعرفة القيمة التي أسندتها قاعدة البيانات لعمود ‪ id‬في السطر الجديد املنشأ‪.‬‬
‫‪ 3.8.15‬تخزين عالقة الصداقة بين مستخدمي تويتر‬
‫لكل من مستخدم تويتر وصديقه في ملفات ‪ JSON‬تصبح عملية إدخال‬
‫بمجرد معرفة قيمة املفتاح ٍ‬
‫القيم إلى جدول ‪ Follow‬عملية بسيطة وذلك عن طريق التعليمة اآلتية‪:‬‬
‫‪cur.execute('INSERT OR IGNORE INTO Follows (from_id, to_id) VALUES‬‬
‫) )‪(?, ?)', (id, friend_id‬‬
‫كما يجب مالحظة أن قاعدة البيانات تمنعنا من إدخال نفس العالقة مرتين عبر إضافة القيود‬
‫وإضافة ‪ OR IGNORE‬إلى تعليمة ‪ ،INSERT‬ونعرض هنا نتيجة تنفيذ هذا البرنامج‪:‬‬
‫‪Enter a Twitter account, or quit:‬‬
‫‪No unretrieved Twitter accounts found‬‬
‫‪Enter a Twitter account, or quit: drchuck‬‬
‫‪Retrieving http://api.twitter.com/1.1/friends ...‬‬
‫‪New accounts= 20 revisited= 0‬‬
‫‪Enter a Twitter account, or quit:‬‬
‫‪Retrieving http://api.twitter.com/1.1/friends ...‬‬
‫‪New accounts= 17 revisited= 3‬‬
‫‪Enter a Twitter account, or quit:‬‬
‫‪Retrieving http://api.twitter.com/1.1/friends ...‬‬
‫‪New accounts= 17 revisited= 3‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪276‬‬
‫‪Enter a Twitter account, or quit: quit‬‬
‫كما نرى‪ ،‬فقد بدأنا بمعالجة الحساب ‪( drchuck‬اسم حساب املؤلف في تويتر) ثم ندع البرنامج يختار‬
‫ً‬
‫تلقائيا‪ ،‬ونعرض هنا بعض‬
‫الحسابين التاليين الستخراج بياناتهما وإضافتها إلى قاعدة البيانات‬
‫الصفوف األولى من جدولي ‪ people‬و‪ follows‬الناتجة بعد اكتمال تشغيل البرنامج‪:‬‬
‫‪People:‬‬
‫)‪(1, 'drchuck', 1‬‬
‫)‪(2, 'opencontent', 1‬‬
‫)‪(3, 'lhawthorn', 1‬‬
‫)‪(4, 'steve_coppin', 0‬‬
‫)‪(5, 'davidkocher', 0‬‬
‫‪55 rows.‬‬
‫‪Follows:‬‬
‫)‪(1, 2‬‬
‫)‪(1, 3‬‬
‫)‪(1, 4‬‬
‫)‪(1, 5‬‬
‫)‪(1, 6‬‬
‫‪60 rows.‬‬
‫نجد هنا من جدول ‪ people‬رقم املعرف ‪ id‬واالسم ‪ name‬والخانة األخيرة ‪ visited‬تشير فيما إذا كان‬
‫الحساب قد تم معالجته أم ال‪ ،‬ونالحظ أنه تمت معالجة الحسابات الثالثة األولى‪ ،‬أما في جدول‬
‫‪ follows‬فنجد أرقام توضح العالقة بين األصدقاء حيث تبين البيانات الظاهرة أن املستخدم األول‬
‫‪ drchuck‬صديق لجميع األشخاص الظاهرة أسماؤهم في الصفوف الخمسة األولى‪ ،‬وهذا منطقي‬
‫ً‬
‫فقد استخرجنا أوال قائمة أصدقاء ‪ drchuck‬وخزناها وهكذا إن استطعت إظهار صفوف أكثر من‬
‫جدول ‪ follows‬فسترى أصدقاء املستخدمين ‪ 2‬و‪ً 3‬‬
‫أيضا‪.‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪277‬‬
‫‪ 9.15‬أنواع املفاتيح الثالثة‬
‫بما أننا بدأنا ببناء نموذج بيانات من خالل إضافة بياناتنا إلى عدد من الجداول املرتبطة ببعضها‬
‫البعض‪ ،‬حيث ربطنا السطور باستخدام املفاتيح فالبد من التعرف على بعض املصطلحات املتعلقة‬
‫بهذا املوضوع‪ ،‬حيث يوجد بشكل عام ثالثة أنواع من املفاتيح املستخدمة في نمذجة البيانات‪:‬‬
‫• املفتاح املنطقي )‪ :(logical key‬هو مفتاح يستخدم ً‬
‫علميا للبحث عن سطر معين‪ ،‬وهو في‬
‫ً‬
‫اعتمادا عليه لنحصل على بيانات‬
‫مثالنا خانة ‪ name‬الذي يمثل اسم املستخدم وقد بحثنا‬
‫ً‬
‫سابقا أنه من املفيد فرض قيود على املفتاح‬
‫سطر خاصة بأحد املستخدمين‪ ،‬الحظنا‬
‫املنطقي بحيث يكون غير مكرر ‪ UNIQUE‬ولكن بما أنه ‪-‬أي املفتاح‪ -‬يعبر عن كيفية بحثنا‬
‫ً‬
‫أحيانا السماح لعدة سطور‬
‫عن سطر معين من وجهة نظر العالم الخارجي فمن املنطقي‬
‫ضمن الجدول بالحصول على نفس القيمة‪.‬‬
‫ً‬
‫تلقائيا‪ ،‬يستخدم لربط‬
‫• املفتاح الرئيس ي )‪ :(primary key‬هو رقم تولده قاعدة البيانات‬
‫عدة سطور من جداول مختلفة فال فائدة لوجوده خارج البرنامج‪ ،‬وتكون الطريقة األسرع‬
‫إليجاد سطر ما ضمن أحد الجداول بالبحث عنه عن طريق املفتاح الرئيس ي باعتباره رقم‬
‫صحيح حيث ال يشغل مساحة تخزين كبيرة ويمكن مقارنته وترتيبه بسرعة‪ ،‬وكمثال عنه في‬
‫نموذجنا الخانة ‪. id‬‬
‫• املفتاح الخارجي (‪ :)foreign key‬وهو رقم يشير إلى املفتاح الرئيس ي لسطر بجدول أخر‪،‬‬
‫وكمثال عليه في نموذجنا املفتاح ‪.from_id‬‬
‫مع األخذ بعين االعتبار أننا استخدمنا نظام تسميات معين حيث أشرنا إلى املفتاح الرئيس ي بـ ‪ id‬بينما‬
‫أشرنا إلى املفتاح الخارجي باسم ينتهي بالالحقة ‪. _id‬‬
‫‪ 10.15‬استخدام عبارة ‪ JOIN‬الستعادة البيانات‬
‫ً‬
‫اآلن وقد قطعنا شوطا اتبعنا فيه معايير تصميم قواعد البيانات وفصلنا البيانات ضمن جدولين‬
‫وربطنا بينهما باستخدام املفاتيح الرئيسية والخارجية أصبح باإلمكان أن نستخدم تعليمة ‪SELECT‬‬
‫لجمع البيانات من الجدولين‪ .‬تستخدم لغة ‪ SQL‬عبارة ‪ JOIN‬لربط تلك الجداول ببعضها حيث تسمح‬
‫لنا بتحديد الخانات الالزمة لربط السطور بين الجداول املختلفة‪ ،‬كما في املثال اآلتي‪:‬‬
‫‪SELECT * FROM Follows JOIN People‬‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪278‬‬
‫‪ON Follows.from_id = People.id WHERE People.id = 1‬‬
‫وتشير ‪ JOIN‬إلى أننا نسترجع الخانات املتقاطعة بين الجدولين ‪ Follows‬و‪ People‬وتشير عبارة ‪ON‬‬
‫إلى شرط تحقيق هذا التقاطع‪ ،‬نفسر التعليمة السابقة كما يلي‪ :‬نستعيد السطور من جدول‬
‫‪ Follows‬ونضيف إليه السطر من جدول ‪ People‬حيث تتطابق قيمة ‪ from_id‬في جدول ‪follows‬‬
‫مع قيمة ‪ id‬في جدول ‪. People‬‬
‫الشكل ‪ : 26‬ربط الجداول باستخدام ‪JOIN‬‬
‫باختصار إن مهمة ‪ JOIN‬هي إنشاء سطور معدلة طويلة تحتوي على خانات من جدول ‪People‬‬
‫والخانات املوافقة لها في جدول ‪ Follows‬حيث يوجد أكثر من حالة توافق ما بين حقل ‪ id‬من جدول‬
‫لكل من أزواج‬
‫‪ People‬وحقل ‪ from_id‬من جدول ‪ ،Follows‬أي تنش ئ عبارة ‪ JOIN‬سطر معدل ٍ‬
‫ً‬
‫الصفوف املتوافقة مكررة البيانات بالقدر الذي نحتاجه‪.‬‬
‫ويوضح البرنامج التالي البيانات التي ستخزن في قاعدة البيانات بعد تشغيل برنامج استكشاف تويتر‬
‫عدة مرات‪:‬‬
‫‪import sqlite3‬‬
‫)'‪conn = sqlite3.connect('friends.sqlite‬‬
SQL ‫ استخدام قواعد البيانات ولغة‬:‫الفصل الخامس عشر‬
279
cur = conn.cursor()
cur.execute('SELECT * FROM People')
count = 0
print('People:')
for row in cur:
if count < 5: print(row)
count = count + 1
print(count, 'rows.')
cur.execute('SELECT * FROM Follows')
count = 0
print('Follows:')
for row in cur:
if count < 5: print(row)
count = count + 1
print(count, 'rows.')
cur.execute('''SELECT * FROM Follows JOIN People
ON Follows.to_id = People.id
WHERE Follows.from_id = 2''')
count = 0
print('Connections for id=2:')
for row in cur:
if count < 5: print(row)
count = count + 1
print(count, 'rows.')
cur.close()
# Code: http://www.py4e.com/code3/twjoin.py
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪280‬‬
‫عرضنا بيانات الجدولين في بداية البرنامج ثم عرضنا مجموعة جزئية من البيانات املتقاطعة بين‬
‫الجداول املترابطة ببعضها ويكون خرج البرنامج كما يلي‪:‬‬
‫‪python twjoin.py‬‬
‫‪People:‬‬
‫)‪(1, 'drchuck', 1‬‬
‫)‪(2, 'opencontent', 1‬‬
‫)‪(3, 'lhawthorn', 1‬‬
‫)‪(4, 'steve_coppin', 0‬‬
‫)‪(5, 'davidkocher', 0‬‬
‫‪55 rows.‬‬
‫‪Follows:‬‬
‫)‪(1, 2‬‬
‫)‪(1, 3‬‬
‫)‪(1, 4‬‬
‫)‪(1, 5‬‬
‫)‪(1, 6‬‬
‫‪60 rows.‬‬
‫‪Connections for id=2:‬‬
‫)‪(2, 1, 1, 'drchuck', 1‬‬
‫)‪(2, 28, 28, 'cnxorg', 0‬‬
‫)‪(2, 30, 30, 'kthanos', 0‬‬
‫)‪(2, 102, 102, 'SomethingGirl', 0‬‬
‫)‪(2, 103, 103, 'ja_Pac', 0‬‬
‫‪20 rows.‬‬
‫الحظ أننا نجد في الخرج أعمدة الجدولين ‪ People‬و ‪ Follows‬ومجموعة األسطر الظاهرة في النهاية‬
‫هي نتيجة استخدام تعليمة ‪ SELECT‬مع عبارة ‪ JOIN‬حيث نفحص في عملية ‪SELECT‬األخيرة حسابات‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪281‬‬
‫أصدقاء”‪ – “opencontent‬اسم أحد الحسابات‪ -‬حيث (‪ ،(People.id=2‬ففي كل سطر معدل من‬
‫ً‬
‫متبوعا باألعمدة ً‬
‫بدءا من العمود الثالث حتى‬
‫تلك العملية يظهر أول عمودين من جدول ‪Follows‬‬
‫الخامس من جدول ‪ ،People‬وتجد ً‬
‫أيضا أن العمود الثاني )‪ (Follows.to_id‬يطابق العمود الثالث‬
‫كل من السطور املعدلة املضافة‪.‬‬
‫)‪(People.id‬في ٍ‬
‫‪ 11.15‬امللخص‬
‫تناول هذا الفصل أساسيات استخدام قواعد البيانات في لغة بايثون‪ ،‬مع مالحظة أن كتابة برنامج‬
‫ً‬
‫تعقيدا من استخدام قواميس بايثون أو ملفات عادية‬
‫الستخدام قاعدة بيانات لتخزين البيانات أكثر‬
‫ً‬
‫قليال ً‬
‫نسبيا إال عند الحاجة الحقيقية لها ولإلمكانيات التي‬
‫مما يجعل امليل نحو قواعد البيانات‬
‫توفرها‪ ،‬ونلخص هنا الحاالت التي تكون فيها قواعد البيانات مفيدة ً‬
‫جدا‪:‬‬
‫‪ 1‬إن كان برنامجك يحتاج إلى إجراء العديد من التحديثات العشوائية الصغيرة ضمن مجموعة‬
‫بيانات هائلة الحجم‪.‬‬
‫‪ 2‬في حال كانت البيانات ضخمة ً‬
‫جدا بحيث ال َ‬
‫تسع ضمن قاموس ولديك حاجة للبحث عن معلومات‬
‫معينة بشكل متكرر‪.‬‬
‫‪ 3‬عند وجود عملية معالجة تستهلك وقت طويل وتحتاج خاللها إلى وقف وإعادة تشغيل البرنامج‬
‫وحفظ البيانات من عملية تشغيل إلى أخرى‪.‬‬
‫باختصار‪ ،‬تستطيع إنشاء قاعدة بيانات بسيطة تحتوي جدول بسيط لتناسب احتياجات تطبيقات‬
‫مختلفة‪ ،‬إال أن معظم القضايا ستتطلب عدة جداول وعالقات بين السطور في مختلف الجداول‪،‬‬
‫ومن املهم التمعن بشكل جيد بالتصميم واتباع معايير قواعد البيانات عند البدء بإنشاء الروابط بين‬
‫الجداول لالستفادة أقص ى ما يمكن من اإلمكانيات التي توفرها قاعدة البيانات‪ ،‬وبما أن الهدف‬
‫الرئيس ي الستخدام قواعد البيانات هو التعامل مع كمية كبيرة من البيانات فمن املهم نمذجة‬
‫البيانات بطريقة فعالة ليتمكن البرنامج من العمل أسرع ما يمكن‪.‬‬
‫‪ 12.15‬التنقيح‬
‫ً‬
‫شيوعا عند تطوير برامج بلغة بايثون لالتصال بقاعدة بيانات ‪ SQLite‬هو‬
‫أحد أكثر اإلجراءات‬
‫تشغيل برنامج وتفحص النتائج باستخدام متصفح قواعد بيانات الخاص بـ ‪ ،SQLite‬حيث يسمح‬
‫لك املتصفح بتفقد عمل البرنامج‪ ،‬كما يجب أن تكون ً‬
‫حذرا ألن ‪ SQLite‬تمنع برنامجين مختلفين من‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪282‬‬
‫تعديل نفس البيانات في نفس الوقت‪ .‬على سبيل املثال‪ ،‬إن فتحت قاعدة بيانات معينة في متصفح‬
‫قواعد بيانات وأجريت تعديل ما عليها بدون الضغط على زر "حفظ" فسيحجب املتصفح ملف‬
‫قاعدة البيانات وسيمنع أي برنامج آخر من الوصول إلى امللف‪ ،‬أي لن يكون برنامج بايثون ً‬
‫قادرا على‬
‫الوصول امللف في هذه الحالة‪ ،‬وكحل لتلك املشكلة نتأكد من إغالق متفصح قاعدة البيانات أو‬
‫استخدام قائمة ملف إلغالق قاعدة البيانات في املتصفح قبل محاولة الوصول إلى قاعدة البيانات‬
‫باستخدام بايثون‪ ،‬وبهذا نتجنب مشكلة فشل برنامج بايثون بسبب حجب قاعدة البيانات‪.‬‬
‫‪ 13.15‬فهرس املصطلحات‬
‫• السمة (‪ :)attribute‬إحدى قيم صفوف بايثون ُيعرف باسم عمود أو خانة‪.‬‬
‫• قاعدة أو قيد (‪ :)constraint‬عندما نطلب من قاعدة البيانات تطبيق قاعدة ما على أحد‬
‫ً‬
‫الحقول أو السطور في جدول ما‪ ،‬وأشهرها عدم تكرار القيم في حقل معين (مثال‪ :‬يجب أن‬
‫تكون جميع القيم فريدة)‪.‬‬
‫• املؤشر (‪ :)cursor‬يسمح لك بتنفيذ أوامر ‪ SQL‬في قاعدة بيانات معينة واستخراج البيانات‬
‫منها‪ ،‬كما ُيشابه مأخذ الشبكة (‪ )socket‬أو معرف امللفات (‪ )file handle‬الخاصين باتصاالت‬
‫الشبكة وامللفات‪.‬‬
‫• متصفح قواعد البيانات (‪ :)database browser‬برنامج يسمح لك باالتصال بشكل مباشر‬
‫مع قواعد البيانات والتعديل عليها دون الحاجة إلى كتابة برنامج‪.‬‬
‫• املفتاح الخارجي (‪ :)foreign key‬مفتاح رقمي يشير إلى املفتاح الرئيس ي الخاص بسطر ما‬
‫في جدول آخر‪ ،‬وتنش ئ هذه املفاتيح الروابط بين السطور املخزنة في جداول مختلفة‪.‬‬
‫• الفهرس (‪ :)index‬بيانات إضافية يحتويها برنامج قاعدة البيانات كالسطور واإلدخاالت إلى‬
‫جدول ما بهدف إجراء عمليات البحث بسرعة‪.‬‬
‫• املفتاح املنطقي (‪ :)logical key‬مفتاح نستخدمه للبحث عن سطر معين‪ ،‬على سبيل املثال‬
‫قد يشكل عنوان البريد اإللكتروني لشخص ما في جدول حسابات املستخدمين قيمة مناسبة‬
‫ليكون املفتاح املنطقي الخاص ببيانات املستخدم‪.‬‬
‫• املعايرة (‪ :)normalization‬تصميم نموذج بيانات يمنع تكرارها حيث نخزن كل عنصر من‬
‫الفصل الخامس عشر‪ :‬استخدام قواعد البيانات ولغة ‪SQL‬‬
‫‪283‬‬
‫البيانات في مكان واحد ضمن قاعدة البيانات ونربطه بمكان آخر عن طريق املفتاح الخارجي‪.‬‬
‫• املفتاح الرئيس ي (‪ :)primary key‬مفتاح رقمي خاص بكل سطر ويستخدم لإلشارة إلى‬
‫ً‬
‫سطر ما في جدول مختلف‪ ،‬وعادة ما تكون قاعدة البيانات مضبوطة بحيث تسند قيم هذه‬
‫املفاتيح بشكل تلقائي أثناء إدخال السطور‪.‬‬
‫• العالقة (‪ :)relation‬جزء من قاعدة البيانات تحتوي على صفوف (‪ )tuples‬وسمات‬
‫ُ‬
‫(‪ )attributes‬وتعرف باسم "جدول"‪.‬‬
‫• الصف (‪ :)tuple‬مدخل وحيد ضمن قاعدة بيانات معينة يتألف من مجموعة من السمات‪،‬‬
‫ُويعرف باسم "سطر"‪.‬‬
‫الفصل السادس عشر‬
‫العرض املرئي للبيانات‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪285‬‬
‫ّ‬
‫املرئي للبيانات‬
‫‪ 16‬العرض‬
‫تعلمنا إلى حد اآلن أساسيات لغة بايثون‪ ،‬وكيفية استخدامها مع الشبكات‪ ،‬وقواعد البيانات‪،‬‬
‫وطرائق التعامل مع البيانات‪.‬‬
‫سندرس في هذا الفصل ثالث تطبيقات تشمل جميع تلك املفاهيم ً‬
‫معا؛ بهدف إدارة وعرض البيانات‬
‫نماذج ُت ُ‬
‫َ‬
‫ًّ‬
‫عين َك عندما تبدأ بحل مسائل حقيقية‪.‬‬
‫مرئيا‪ .‬ويمكنك اعتبار هذه التطبيقات‬
‫كملف مضغوط بصيغة "‪ ،"ZIP‬يمكنك تحميله وفك ضغطه على حاسوبك‬
‫تتوفر هذه التطبيقات‬
‫ٍ‬
‫الشخص ي لتشغيله‪.‬‬
‫‪ 1.16‬عرض خريطة باستخدام بيانات جغر ّ‬
‫افية من غوغل‬
‫سنستخدم في هذا املشروع واجهة غوغل البرمجية للترميز الجغرافي (‪)Google geocoding API‬؛‬
‫للبحث عن مواقع جغرافية لبعض أسماء جامعات ٌمدخلة من املستخدم‪ ،‬ثم إدراج هذه املواقع على‬
‫خريطة غوغل‪.‬‬
‫حمل التطبيق من هنا‪http://www.py4e.com/code3/geodata.zip :‬‬
‫أولى القضايا الواجب حلها هي أن النسخة املجانية من واجهة غوغل البرمجية للترميز الجغرافي‬
‫محدودة من ناحية عدد الطلبات في اليوم‪ ،‬فإن كان لديك الكثير من البيانات‪َّ ،‬‬
‫ترتب عليك إيقاف‬
‫عملية البحث وإعادتها عدة مرات‪ ،‬لذلك سنحل هذه املشكلة على مرحلتين‪.‬‬
‫في املرحلة األولى‪ ،‬نقرأ بيانات أسماء الجامعات املوجودة في ملف ‪ where.data‬كل سطر على حدة‪،‬‬
‫ثم نسترجع املعلومات َّ‬
‫املرمزة جغر ًّ‬
‫افيا من غوغل لكل سطر‪ ،‬ونخزنها في قاعدة البيانات‬
‫‪ .geodata.sqlite‬لكن‪ ،‬قبل استخدام الواجهة البرمجية مع كل موقع ُمدخل من قبل املستخدم‪،‬‬
‫ً‬
‫مسبقا؛ للتأكد من عدم تكرار الطلب لذات البيانات‬
‫علينا التحقق من عدم توفر تلك البيانات لدينا‬
‫من غوغل‪ ،‬حيث تعمل قاعدة البيانات بمثابة ذاكرة تخزين مؤقت (‪ )cache‬محلية لبيانات الترميز‬
‫الجغرافي‪.‬‬
‫يمكنك إعادة تنفيذ العملية في أي وقت بحذف امللف ‪.geodata.sqlite‬‬
‫سيقرأ برنامج ‪ geoload.py‬املدخالت من امللف ‪ ،where.data‬ويتحقق فيما إذا كان كل سطر متوف ًرا‬
‫ً‬
‫مسبقا في قاعدة البيانات‪ ،‬أم ال‪ .‬في حال عدم توفر بيانات املوقع‪ ،‬سنستدعي الواجهة البرمجية‬
‫ العرض املرئي للبيانات‬:‫الفصل السادس عشر‬
286
.‫ وتخزينها ضمن قاعدة البيانات‬،‫للترميز الجغرافي السترجاع البيانات‬
‫ خريطة غوغل‬: 27 ‫الشكل‬
:‫ وذلك بوجود بعض البيانات في قاعدة البيانات‬،‫نبين فيما يلي الخرج بعد التشغيل‬
Found in database Northeastern University
Found in database University of Hong Kong, ...
Found in database Viswakarma Institute, Pune, India
Found in database UMD
Found in database Tufts University
Resolving Monash University
Retrieving http://maps.googleapis.com/maps/api/
geocode/json?address=Monash+University
Retrieved 2063 characters { "results" : [
{'status': 'OK', 'results': ... }
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪287‬‬
‫‪Resolving Kokshetau Institute of Economics and Management‬‬
‫‪Retrieving http://maps.googleapis.com/maps/api/‬‬
‫‪geocode/json?address=Kokshetau+Inst ...‬‬
‫[ ‪Retrieved 1749 characters { "results" :‬‬
‫} ‪{'status': 'OK', 'results': ...‬‬
‫‪...‬‬
‫ً‬
‫مسبقا في قاعدة البيانات‪ ،‬لذلك تم تخطيها‪ .‬يستمر البرنامج حتى يجد‬
‫املواقع الخمسة األولى موجودة‬
‫مواقع جديدة‪ ،‬ثم يبدأ في استرجاعها‪.‬‬
‫يمكن إيقاف برنامج ‪ groload.py‬في أي وقت تريد‪ ،‬باإلضافة إلى وجود عداد يمكن استخدامه للحد‬
‫من استدعاءات الواجهة البرمجية للترميز الجغرافي في كل مرة تشغيل؛ ألنه ال يجب الوصول إلى‬
‫املعدل األقص ى للبيانات اليومية‪ ،‬ألن ‪ where.data‬ال يحتوي إال على بضع مئات من عناصر‬
‫البيانات‪ ،‬فلن يكون هناك مشكلة‪ .‬لكن‪ ،‬في حال وجود املزيد من البيانات‪ ،‬سيتطلب ذلك التشغيل‬
‫عدة مرات على مدار أيام عدة حتى تحصل قاعدة البيانات على جميع البيانات الجغرافية املرمزة‬
‫للمواقع املطلوبة‪.‬‬
‫بمجرد توفر البيانات في ‪ ،geodata.py‬يمكنك عرضها باستخدام برنامج ‪ ،geodump.py‬حيث يقرأ‬
‫هذا البرنامج محتوى قاعدة البيانات‪ ،‬وينش ئ امللف "‪"where.js‬؛ ليعرض املوقع وخطوط الطول‬
‫والعرض على شكل ملف ‪ Javascript‬تنفيذي‪.‬‬
‫ويكون ناتج تنفيذ برنامج ‪ geodump.py‬كالتالي‪:‬‬
‫‪Northeastern University, ... Boston, MA 02115, USA 42.3396998 -71.08975‬‬
‫‪Bradley University, 1501 ... Peoria, IL 61625, USA 40.6963857 -89.6160811‬‬
‫‪...‬‬
‫‪Monash University Clayton ... VIC 3800, Australia -37.9152113 145.134682‬‬
‫‪Kokshetau, Kazakhstan 53.2833333 69.3833333‬‬
‫‪...‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪288‬‬
‫‪12 records written to where.js‬‬
‫‪Open where.html to view the data in a browser‬‬
‫يتألف امللف "‪ "where.html‬من شيفرة ‪ ،HTML‬و‪ JavaScript‬ملعاينة وعرض خريطة غوغل‪.‬‬
‫يقرأ أحدث البيانات في "‪ "where.js‬لعرضها‪ .‬ويكون محتوى هذا امللف على الشكل التالي‪:‬‬
‫[ = ‪myData‬‬
‫‪[42.3396998,-71.08975, 'Northeastern Uni ... Boston, MA 02115'],‬‬
‫‪[40.6963857,-89.6160811, 'Bradley University, ... Peoria, IL 61625, USA'],‬‬
‫‪...‬‬
‫;]‬
‫يحتوي هذا املتغير املكتوب بلغة ‪ JavaScript‬على قائمة من القوائم‪ .‬ومن املفترض أن تكون هذه‬
‫الصيغة مألوفة بالنسبة لك‪ ،‬حيث إن الصيغة البرمجية لكتابة القوائم بلغة ‪ JavaScript‬تشبه إلى‬
‫َ‬
‫املستخدمة في بايثون ألجل هذا الغرض‪.‬‬
‫حد كبير الصيغة البرمجية‬
‫ٍ‬
‫افتح "‪ "where.html‬على املتصفح ملعاينة املواقع‪ .‬يمكنك التحرك بين املواقع على الخريطة ملعرفة‬
‫املوقع الذي أوجدته واجهة الترميز الجغرافي‪ .‬وفي حال عدم وجود أية بيانات عند فتح ملف‬
‫"‪ ،"where.html‬يجب التحقق من ‪ ،JavaScript‬أو وحدة املطورين (‪ )developer console‬على‬
‫املتصفح‪.‬‬
‫‪ 2.16‬العرض ّ‬
‫املرئي للشبكات واالرتباطات‬
‫سننفذ في هذا التطبيق إحدى وظائف محركات البحث‪ .‬سنكتشف ً‬
‫ً‬
‫صغيرا من شبكة اإلنترنت‪،‬‬
‫جزءا‬
‫ونشغل نسخة ُمبسطة من خوارزمية غوغل لترتيب الصفحات؛ بهدف التعرف على أكثر الصفحات‬
‫ً‬
‫ارتباطا‪ ،‬ثم سنعرض ترتيب وارتباطات الصفحات التي اكتشفناها‪.‬‬
‫سنستخدم مكتبة ‪( D3 JavaScript Visualization‬مزيد من املعلومات في الرابط ‪)http://d3js.org/‬‬
‫إلعداد عرض الخرج‪.‬‬
‫يمكن تحميل وفك ضغط التطبيق عبر الرابط‪www.py4e.com/code3/pagerank.zip :‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪289‬‬
‫الشكل ‪ : 28‬رتبة الصفحات‬
‫يكتشف البرنامج األول ‪ spider.py‬أحد مواقع الشبكة‪ ،‬ويستخرج منه عدة صفحات ليخزنها في‬
‫قاعدة البيانات ‪ً spider.sqlite‬‬
‫وفقا للروابط بين هذه الصفحات‪.‬‬
‫يمكنك إعادة تشغيل هذه العملية في أي وقت بحذف امللف ‪ ،spider.sqlite‬وإعادة تشغيل‬
‫‪.spider.py‬‬
‫‪Enter web url or enter: http://www.dr-chuck.com/‬‬
‫]'‪['http://www.dr-chuck.com‬‬
‫‪How many pages:2‬‬
‫‪1 http://www.dr-chuck.com/ 12‬‬
‫‪2 http://www.dr-chuck.com/csev-blog/ 57‬‬
‫‪How many pages:‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪290‬‬
‫في املثال السابق‪ ،‬بحث البرنامج في أحد املواقع‪ ،‬وأرجع صفحتين منه‪ .‬في حال أعدنا تشغيل البرنامج‬
‫َ‬
‫لتعقب املزيد من الصفحات‪ ،‬فلن َّ‬
‫يتتبع الصفحات التي ُحفظت مسب ًقا في قاعدة البيانات‪.‬‬
‫َ‬
‫صفحات جديدة لم ُتكت َشف بعد؛ ليبدأ من عندها‪ .‬بالتالي‪ ،‬يمكن القول‬
‫حاملا تعيد تشغيله‪ ،‬يتجه إلى‬
‫ٍ‬
‫إن مع كل عملية تشغيل ناجحة للبرنامج ‪ ،spider.py‬تضاف صفحات جديدة‪.‬‬
‫‪Enter web url or enter: http://www.dr-chuck.com/‬‬
‫]'‪['http://www.dr-chuck.com‬‬
‫‪How many pages:3‬‬
‫‪3 http://www.dr-chuck.com/csev-blog 57‬‬
‫‪4 http://www.dr-chuck.com/dr-chuck/resume/speaking.htm 1‬‬
‫‪5 http://www.dr-chuck.com/dr-chuck/resume/index.htm 13‬‬
‫‪How many pages:‬‬
‫يمكنك الحصول على عدة نقاط مرجعية في قاعدة البيانات داخل البرنامج‪ ،‬وتدعى "‪ ."webs‬يختار‬
‫ُ‬
‫عشوائيا ليكتشفها ً‬
‫ًّ‬
‫تاليا‪.‬‬
‫البرنامج إحدى الصفحات التي لم تكتشف بعد‬
‫إذا أردت عرض محتويات ملف ‪ ،spider.sqlite‬يمكنك تشغيل ‪.spdump.py‬‬
‫)'‪(5, None, 1.0, 3, 'http://www.dr-chuck.com/csev-blog‬‬
‫)'‪(3, None, 1.0, 4, 'http://www.dr-chuck.com/dr-chuck/resume/speaking.htm‬‬
‫)'‪(1, None, 1.0, 2, 'http://www.dr-chuck.com/csev-blog/‬‬
‫)'‪(1, None, 1.0, 5, 'http://www.dr-chuck.com/dr-chuck/resume/index.htm‬‬
‫‪4 rows.‬‬
‫يعرض املثال السابق عدد الروابط الجديدة املضافة‪ ،‬والترتيب القديم‪ ،‬ثم الجديد للصفحة‪ ،‬ورمز‬
‫تعريف الصفحة‪ ،‬ورابطها بالترتيب‪ .‬يعرض برنامج ‪ spdump.py‬فقط الصفحات التي تملك على‬
‫األقل رابط يشير لها‪.‬‬
‫بمجرد توفر عدة صفحات في قاعدة البيانات‪ ،‬يمكنك تنفيذ عملية الترتيب لهذه الصفحات‬
‫باستخدام برنامج ‪ ،sprank.py‬حيث يمكنك إخبار البرنامج بعدد مرات تكرار خوارزمية ترتيب‬
‫الصفحات‪.‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪291‬‬
‫‪How many iterations:2‬‬
‫‪1 0.546848992536‬‬
‫‪2 0.226714939664‬‬
‫])‪[(1, 0.559), (2, 0.659), (3, 0.985), (4, 2.135), (5, 0.659‬‬
‫يمكنك عرض محتوى قاعدة البيانات بتنفيذ ‪ pdump.py‬لترى أن قيمة ترتيب الصفحة قد ُحدثت‬
‫لجميع املواقع‪:‬‬
‫)'‪(5, 1.0, 0.985, 3, 'http://www.dr-chuck.com/csev-blog‬‬
‫)'‪(3, 1.0, 2.135, 4, 'http://www.dr-chuck.com/dr-chuck/resume/speaking.htm‬‬
‫)'‪(1, 1.0, 0.659, 2, 'http://www.dr-chuck.com/csev-blog/‬‬
‫)'‪(1, 1.0, 0.659, 5, 'http://www.dr-chuck.com/dr-chuck/resume/index.htm‬‬
‫‪4 rows.‬‬
‫يمكنك تشغيل البرنامج ‪ sprank.py‬بقدر ما تشاء‪ ،‬وسيظهر لك في كل مرة ترتيب الصفحات‪ .‬أو‬
‫يمكنك تشغيله بضع مرات‪ ،‬ثم إضافة صفحات جديدة بتشغيل البرنامج ‪ ،spider.py‬وثم تشغيل‬
‫‪ ،sprank.py‬واالطالع على الترتيب الجديد‪.‬‬
‫تقوم محركات البحث بهاتين العمليتين (تعقب صفحات جديدة وترتيبها) طوال الوقت‪.‬‬
‫إذا أردت ترتيب الصفحات من جديد‪ ،‬شغل برنامج ‪ ،spreset.py‬ثم أعد تشغيل ‪.sprank.py‬‬
‫‪How many iterations:50‬‬
‫‪1 0.546848992536‬‬
‫‪2 0.226714939664‬‬
‫‪3 0.0659516187242‬‬
‫‪4 0.0244199333‬‬
‫‪5 0.0102096489546‬‬
‫‪6 0.00610244329379‬‬
‫‪...‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪292‬‬
‫‪42 0.000109076928206‬‬
‫‪43 9.91987599002e-05‬‬
‫‪44 9.02151706798e-05‬‬
‫‪45 8.20451504471e-05‬‬
‫‪46 7.46150183837e-05‬‬
‫‪47 6.7857770908e-05‬‬
‫‪48 6.17124694224e-05‬‬
‫‪49 5.61236959327e-05‬‬
‫‪50 5.10410499467e-05‬‬
‫])‪[(512, 0.0296), (1, 12.79), (2, 28.93), (3, 6.808), (4, 13.46‬‬
‫ُيعرض التغير الوسطي الحاصل في ترتيب الصفحات عند كل تكرار لخوارزمية ترتيب الصفحات‪ .‬في‬
‫البداية‪ ،‬تكون الشبكة غير متوازنة‪ ،‬لذا تتباين قيم ترتيب الصفحات مع تكرار الخوارزمية‪ ،‬وعندما‬
‫نصل إلى عدد معين من التكرارات للخوارزمية‪ ،‬تصبح تلك القيم متقاربة أكثر‪ ،‬لذا عليك تشغيل‬
‫برنامج ‪ً sprank.py‬‬
‫عددا ً‬
‫كافيا من املرات حتى تتقارب قيم ترتيب الصفحات‪.‬‬
‫إذا أردت عرض ترتيب الصفحات الحالي للمواقع التي تعاملنا معها أعاله‪ ،‬شغل البرنامج ‪spjson.py‬‬
‫ً‬
‫لقراءة قاعدة البيانات وتخزين البيانات الخاصة بالصفحات األكثر ارتباطا وفق صيغة ‪JSON‬؛‬
‫ُلتعرض في املتصفح‪.‬‬
‫‪Creating JSON output on spider.json...‬‬
‫‪How many nodes? 30‬‬
‫‪Open force.html in a browser to view the visualization‬‬
‫بإمكانك عرض هذه البيانات بفتح ملف "‪ "force.html‬في املتصفح؛ لتشاهد الروابط والعقد مولدة‬
‫تلقائيا‪ ،‬حيث يمكنك السحب والنقر على أية عقدة‪ ،‬كما يمكنك ً‬
‫ً‬
‫أيضا إيجاد الرابط الذي تمثله‬
‫العقدة عبر النقر املزدوج عليها‪.‬‬
‫إذا أعدت تشغيل البرامج املساعدة األخرى‪ ،‬مثل برنامج ‪ ،spjson.py‬وحدثت الصفحة في املتصفح‪،‬‬
‫ستحصل على بيانات جديدة من ملف ‪.spider.json‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪293‬‬
‫ّ‬
‫اإللكتروني‬
‫‪ 3.16‬تحليل وعرض البيانات الواردة في البريد‬
‫ً‬
‫بعد أن أصبح التعامل مع امللفين "‪ "mbox-short.txt‬و"‪ "mbox.txt‬مألوفا بالنسبة لنا‪ ،‬حان الوقت‬
‫لتحسين مهارتنا في تحليل البيانات الواردة في البريد اإللكتروني‪.‬‬
‫ً‬
‫أحيانا إلى سحب البيانات من الخوادم‪ .‬قد تكون هذه البيانات‬
‫في التطبيقات العملية‪ ،‬قد تحتاج‬
‫مليئة باألخطاء‪ ،‬وغير متناسقة‪ ،‬وتتطلب الكثير من التعديل والترتيب‪ ،‬لذا قد تتطلب العملية ً‬
‫وقتا‬
‫ً‬
‫طويال‪.‬‬
‫سنتطرق في هذا القسم إلى أعقد تطبيق تعاملنا معه إلى حد اآلن‪ ،‬حيث سوف نسحب ‪ 1‬جيجابايت‬
‫من البيانات لتحليلها واستعراضها‪.‬‬
‫يمكنك تحميل التطبيق من خالل الرابط التالي‪https://www.py4e.com/code3/gmane.zip :‬‬
‫سوف نستخدم خدمة مجانية ألرشفة قوائم البريد اإللكتروني للحصول على البيانات‪ ،‬تدعى‬
‫‪ ،http://www.gmane.org.‬حيث تعد هذه الخدمة شائعة االستخدام في التطبيقات مفتوحة‬
‫املصدر؛ إذ تؤمن أرشيف يمكنك البحث فيه عن نشاط بريدهم اإللكتروني‪ً .‬‬
‫علما أنه ال يوجد حدود‬
‫ً‬
‫للتحميل‪ ،‬إذ يمكنك تحميل قدر ما تشاء من البيانات‪ ،‬لكن يفضل أال تسرف وتسبب ضغطا على‬
‫الشكل ‪ :29‬مجموعة كلمات موزعة على شكل غيمة مولدة من قائمة شركة ‪Sakai‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪294‬‬
‫خوادمهم‪ .‬يمكنك االطالع على شروط االستخدام من خالل زيارة الصفحة التالية‪:‬‬
‫‪http://www.gmane.org/export.php‬‬
‫من املهم استخدام هذه الخدمة بمسؤولية‪ ،‬وذلك من خالل إضافة تأخير زمني لطلبات الوصول‬
‫للخوادم‪ ،‬وتوزيع املهام التي تحتاج إلى وقت معالجة طويل على أطول فترة ممكنة‪ .‬لذلك‪ ،‬احرص على‬
‫عدم إساءة استخدام هذه الخدمة‪.‬‬
‫ُ‬
‫لدى ُّ‬
‫تعقب بيانات البريد اإللكتروني لشركة ‪ Sakai‬باستخدام هذا البرنامج‪ ،‬أنتج قرابة ‪ 1‬غيغابايت‬
‫من البيانات‪ ،‬واستغرق ذلك عمليات عديدة على مدار عدة أيام‪.‬‬
‫يحتوي امللف ‪ README.txt‬في املجلد املضغوط أعاله على إرشادات حول كيفية تحميل نسخة من‬
‫ملف ‪ content.sqlite‬مجموعة من رسائل البريد اإللكتروني لـ ‪ Sakai‬الجاهزة‪ ،‬حيث ال تضطر بذلك‬
‫إلى التعقب ملدة خمسة أيام متواصلة من أجل تشغيل البرامج‪ .‬لكن‪ ،‬حتى وإن حملت املحتوى الجاهز‬
‫ً‬
‫مسبقا‪ ،‬فال يزال عليك إجراء عملية تعقب ملتابعة أحدث الرسائل‪.‬‬
‫تتجلى الخطوة األولى في تعقب أرشيف ‪ ،gmane‬حيث إن عنوان ‪ URL‬األساس ي مضاف بشكل مباشر‬
‫في شيفرة ‪ ،gmane.py‬وفي قائمة مطوري ‪ .Sakai‬يمكنك تعقب أرشيف آخر عن طريق تغيير عنوان‬
‫‪ URL‬األساس ي‪ .‬تأكد من حذف ملف ‪ content.sqlite‬عند تبديل عنوان ‪ URL‬األساس ي‪.‬‬
‫يعمل ملف ‪ gmane.py‬بطريقة مسؤولة‪ ،‬حيث يعمل ببطء‪ ،‬ويسترد رسالة بريد إلكتروني واحدة في‬
‫َ‬
‫الثانية‪ ،‬وذلك كي ال يعلق في أرشيف ‪ .gmane‬كما يخزن جميع بياناته في قاعدة بيانات تتيح املقاطعة‬
‫وإعادة التشغيل كلما دعت الحاجة‪ .‬قد يستغرق تحميل جميع البيانات عدة ساعات‪ ،‬لذلك قد‬
‫تحتاج إلى إعادة التشغيل عدة مرات‪.‬‬
‫فيما يأتي ناتج عملية تشغيل ملف ‪ ،gmane.py‬حيث يسترد الرسائل الخمسة األخيرة من قائمة‬
‫مطوري ‪:Sakai‬‬
‫‪How many messages:10‬‬
‫‪http://download.gmane.org/gmane.comp.cms.sakai.devel/51410/51411 9460‬‬
‫‪nealcaidin@sakaifoundation.org 2013-04-05 re: [building ...‬‬
‫‪http://download.gmane.org/gmane.comp.cms.sakai.devel/51411/51412 3379‬‬
‫‪samuelgutierrezjimenez@gmail.com 2013-04-06 re: [building ...‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪295‬‬
‫‪http://download.gmane.org/gmane.comp.cms.sakai.devel/51412/51413 9903‬‬
‫‪da1@vt.edu 2013-04-05 [building sakai] melete 2.9 oracle ...‬‬
‫‪http://download.gmane.org/gmane.comp.cms.sakai.devel/51413/51414 349265‬‬
‫‪m.shedid@elraed-it.com 2013-04-07 [building sakai] ...‬‬
‫‪http://download.gmane.org/gmane.comp.cms.sakai.devel/51414/51415 3481‬‬
‫‪samuelgutierrezjimenez@gmail.com 2013-04-07 re: ...‬‬
‫‪http://download.gmane.org/gmane.comp.cms.sakai.devel/51415/51416 0‬‬
‫‪Does not start with From‬‬
‫يتصفح البرنامج قاعدة البيانات ‪ content.sqlite‬من البداية حتى رقم الرسالة األولى التي لم يتم‬
‫ً‬
‫مسبقا‪ ،‬ويبدأ بعد ذلك في تعقب تلك الرسالة‪ ،‬إذ يستمر في التعقب حتى يصل إلى العدد‬
‫تعقبها‬
‫املطلوب من الرسائل‪ ،‬أو يصل إلى صفحة ال تبدو أنها رسالة منسقة بشكل صحيح‪.‬‬
‫ً ُ‬
‫أحيانا تفقد رسالة في ‪ ،gmane.org‬ويعود السبب في ذلك إلى إمكانية حذفها من قبل املسؤولين‪ ،‬أو‬
‫احتمالية ضياع إحدى الرسائل‪ .‬إذا توقف املتعقب بشكل يوحي أنه وصل إلى رسالة مفقودة‪ ،‬عندها‬
‫انتقل إلى ‪ ،SQLite Manager‬وأضف ًّ‬
‫صفا مع كتابة رقم املعرف املفقود‪ ،‬مع إبقاء الحقول األخرى‬
‫فارغة‪ ،‬ثم أعد تشغيل ‪ .gmane.py‬سيؤدي هذا إلى تحرير ملف التعقب؛ مما يتيح له استمرارية‬
‫التعقب دون أن يعلق عند الرسالة املفقودة‪ .‬أما الرسائل الفارغة‪ ،‬فسيجري تجاهلها في املرحلة‬
‫التالية من العملية‪.‬‬
‫يمكنك تشغيل ‪ gmane.py‬مرة أخرى للحصول على رسائل جديدة عند إرسالها إلى القائمة‪ ،‬وذلك‬
‫بمجرد أن تتعقب جميع الرسائل وتضعها في ‪ ،content.sqlite‬حيث تعد هذه الخاصية من‬
‫الخصائص املفيدة‪.‬‬
‫تعد بيانات ‪ content.sqlite‬بيانات أولية‪ ،‬حيث يعد نموذج بياناتها غير فعال‪ ،‬كما أنها غير مضغوطة‪.‬‬
‫هذا متعمد‪ ،‬ألنه يسمح لك باالطالع على ‪ content.sqlite‬في ‪ SQLite Manager‬لتصحيح مشاكل‬
‫عملية التعقب‪ .‬من غير املحبذ إجراء طلبات على قاعدة البيانات هذه‪ ،‬ألن العملية ستكون بطيئة‬
‫للغاية‪.‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪296‬‬
‫أما الخطوة الثانية‪ ،‬فهي تشغيل برنامج ‪ ،gmodel.py‬إذ يقرأ هذا البرنامج البيانات األولية من‬
‫‪ ،content.sqlite‬وينتج نسخة منظمة ومنسقة من البيانات في ملف ‪ .index.sqlite‬سيكون هذا امللف‬
‫ًّ‬
‫أصغر بكثير ً‬
‫(غالبا ما يكون أصغر بعشر مرات) من ‪content.sqlite‬؛ ألنه يضغط كال من الترويسة‬
‫والنص األساس ي‪.‬‬
‫في كل مرة تشغيل لـ ـ‪ ،gmodel.py‬يحذف ‪ index.sqlite‬ويعيد تكوينه‪ ،‬مما يتيح إمكانية ضبط‬
‫معامالته‪ ،‬وتحرير جداول الربط في ‪ content.sqlite‬لتعديل عملية تنظيم البيانات‪.‬‬
‫َ‬
‫فيما يلي ناتج تشغيل برنامج ‪ ،gmodel.py‬حيث يعرض سطر في كل مرة تعالج ‪ 250‬رسالة بريد‪،‬‬
‫لتتمكن من مالحظة التغيير‪ .‬وبعد فترة من عمل البرنامج‪ ،‬يكون قد عالج قرابة ‪ 1‬جيجابايت من‬
‫بيانات البريد‪.‬‬
‫‪Loaded allsenders 1588 and mapping 28 dns mapping 1‬‬
‫‪1 2005-12-08T23:34:30-06:00 ggolden22@mac.com‬‬
‫‪251 2005-12-22T10:03:20-08:00 tpamsler@ucdavis.edu‬‬
‫‪501 2006-01-12T11:17:34-05:00 lance@indiana.edu‬‬
‫‪751 2006-01-24T11:13:28-08:00 vrajgopalan@ucmerced.edu‬‬
‫‪...‬‬
‫يتحمل برنامج ‪ gmodel.py‬عبء معالجة عدد من مهمات تنظيم البيانات‪ .‬على سبيل املثال‪ :‬اقتطاع‬
‫أسماء النطاقات إلى مستويين أو إلى ثالثة مستويات‪ .‬على سبيل املثال‪ ،‬يصبح ‪ si.umich.edu‬بالشكل‬
‫حول عناوين البريد اإللكتروني ً‬
‫‪ ،umich.edu‬ويصبح ‪ caret.am.ac.uk‬بالشكل ‪ُ ،cam.ac.uk‬وت َّ‬
‫أيضا‬
‫إلى حالة األحرف الصغيرة‪ ،‬كما ُت َّ‬
‫حول بعض العناوين التي تنتهي بـ ‪ ،@gmane.org‬مثل العناوين‬
‫اآلتية‪،arwhyte-63aXycvo3TyHXe+LvDLADg@public.gmane.org :‬‬
‫إلى العنوان الحقيقي كلما عث َر على عنوان بريد إلكتروني حقيقي مطابق في مكان آخر ضمن الرسالة‪.‬‬
‫يوجد في قاعدة البيانات ‪ mapping.sqlite‬جدوالن يسمحان لك بربط أسماء النطاقات وعناوين‬
‫البريد اإللكتروني الفردية التي تتغير خالل مدة توفر قائمة البريد اإللكتروني‪ .‬على سبيل املثال‪،‬‬
‫استخدم ستيف غيثينس ‪ Steve Githens‬عناوين البريد اإللكتروني أدناه مع تغير عمله‪:‬‬
‫‪s-githens@northwestern.edu‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪297‬‬
‫‪sgithens@cam.ac.uk‬‬
‫‪swgithen@mtu.edu‬‬
‫يمكننا إضافة اثنين من املدخالت إلى جدول الربط في ‪ mapping.sqlite‬حتى يربط ‪gmodel.py‬‬
‫اإليميالت الثالثة بعنوان واحد‪:‬‬
‫‪s-githens@northwestern.edu -> swgithen@mtu.edu‬‬
‫‪sgithens@cam.ac.uk -> swgithen@mtu.edu‬‬
‫يمكنك ً‬
‫أيضا إضافة مدخالت مماثلة في جدول ‪ DNSMapping‬إذا كان هناك العديد من أسماء ‪DNS‬‬
‫ُ‬
‫التي تريد ربطها إلى ‪ DNS‬واحد‪ .‬على سبيل املثال‪ ،‬أضيف الربط التالي إلى بيانات ‪:Sakai‬‬
‫‪iupui.edu -> indiana.edu‬‬
‫وبذلك‪ ،‬تكون جميع الحسابات من جميع أنحاء حرم جامعة إنديانا قد تم تعقبها‪.‬‬
‫ً‬
‫تنظيما‬
‫يمكنك إعادة تشغيل ‪ gmodel.py‬مر ًارا وتكر ًارا‪ ،‬وإضافة عمليات ربط لجعل البيانات أكثر‬
‫ودقة‪ .‬وعند االنتهاء‪ ،‬ستكون لديك نسخة منظمة من البريد اإللكتروني في ‪.index.sqlite‬‬
‫يؤمن هذا امللف آلية سريعة لتحليل البيانات‪.‬‬
‫إن أول وأبسط تحليل للبيانات هو تحديد "من الذي أرسل أكبر عدد من الرسائل؟"‪ ،‬و"ما هي املنظمة‬
‫التي أرسلت أكبر عدد من رسائل البريد؟"‪ .‬يتم ذلك باستخدام ‪:gbasic.py‬‬
‫‪How many to dump? 5‬‬
‫‪Loaded messages= 51330 subjects= 25033 senders= 1584‬‬
‫‪Top 5 Email list participants‬‬
‫‪steve.swinsburg@gmail.com 2657‬‬
‫‪azeckoski@unicon.net 1742‬‬
‫‪ieb@tfd.co.uk 1591‬‬
‫‪csev@umich.edu 1304‬‬
‫‪david.horwitz@uct.ac.za 1184‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪298‬‬
‫‪Top 5 Email list organizations‬‬
‫‪gmail.com 7339‬‬
‫‪umich.edu 6243‬‬
‫‪uct.ac.za 2451‬‬
‫‪indiana.edu 2258‬‬
‫‪unicon.net 2055‬‬
‫ً‬
‫ً‬
‫الحظ مدى سرعة تشغيل ‪ gbasic.py‬مقارنة بـ ‪ gmane.py‬أو حتى ‪ .gmodel.py‬يعملون‬
‫جميعا على‬
‫البيانات ذاتها‪ ،‬لكن ‪ gbasic.py‬هو األسرع‪ ،‬ألنه يستخدم البيانات املضغوطة واملنظمة في‬
‫‪ .index.sqlite‬إذا كان لديك الكثير من البيانات إلدارتها‪ ،‬فقد تتطلب العملية املوجودة في هذا‬
‫التطبيق ً‬
‫وقتا أطول للتطوير‪ً ،‬‬
‫نظرا إلى أنها عملية متعددة الخطوات‪ ،‬ولكنها ستوفر لك الكثير من‬
‫الوقت عندما تبدأ ًّ‬
‫فعليا في عملية استكشاف وعرض البيانات‪.‬‬
‫يمكنك إجراء تمثيل بسيط للبيانات الخاصة بتكرار الكلمات في سطور املوضوع بتشغيل امللف‬
‫‪:gword.py‬‬
‫‪Range of counts: 33229 129‬‬
‫‪Output written to gword.js‬‬
‫ينتج عن هذا التمثيل امللف ‪ gword.js‬الذي يمكنك عرضه باستخدام ‪ gword.htm‬إلنتاج مجموعة‬
‫كلمات (ذات أشكال وأحجام مختلفة) مشابهة لتلك املوجودة في بداية هذا القسم‪.‬‬
‫ينتج التمثيل الثاني عند تشغيل ‪gline.py‬؛ إذ يحسب عدد اإليميالت ً‬
‫تبعا للمنظمة‪:‬‬
‫‪Loaded messages= 51330 subjects= 25033 senders= 1584‬‬
‫‪Top 10 Oranizations‬‬
‫‪['gmail.com', 'umich.edu', 'uct.ac.za', 'indiana.edu',‬‬
‫‪'unicon.net', 'tfd.co.uk', 'berkeley.edu', 'longsight.com',‬‬
‫]'‪'stanford.edu', 'ox.ac.uk‬‬
‫‪Output written to gline.js‬‬
‫الفصل السادس عشر‪ :‬العرض املرئي للبيانات‬
‫‪299‬‬
‫تكتب مخرجاته في ‪ gline.js‬التي تعرض باستخدام ‪.gline.htm‬‬
‫يعد هذا التطبيق من التطبيقات َّ‬
‫املعقدة‪ ،‬واملتطورة ًّ‬
‫نسبيا‪ ،‬وله ميزات إلنجاز بعض عمليات استرداد‬
‫البيانات الحقيقية‪ ،‬وتنظيمها‪ ،‬وتمثيلها‪.‬‬
‫الشكل ‪ : 30‬توزع اإليميالت بالنسبة للمنظمة‬
‫امللحق آ‬
‫املساهمون‬
"Python for Everybody - ‫ املساهمون في كتاب "بايثون للجميع‬.1
Elliott Hauser, Stephen Catto, Sue Blumenberg, Tamara Brunnock, Mihaela Mack,
Chris Kolosiwsky, Dustin Farley, Jens Leerssen, Naveen KT, Mirza Ibrahimovic,
Naveen (@togarnk), Zhou Fangyi, Alistair Walsh, Erica Brody, Jih-Sheng Huang,
Louis Luangkesorn, and Michael Fudge
https://github.com/csev/py4e/graphs/contributors :‫ملزيد من التفاصيل‬
"Python for Informatics - ‫ املساهمون في كتاب "بايثون للمعلوماتية‬.2
Bruce Shields, Sarah Hegge, Steven Cherry, Sarah Kathleen Barbarow, Andrea Parker,
Radaphat Chongthammakun, Megan Hixon, Kirby Urner, Sarah Kathleen Barbrow,
Katie Kujala, Noah Botimer, Emily Alinder, Mark Thompson-Kular, James Perry, Eric
Hofer, Eytan Adar, Peter Robinson, Deborah J. Nelson, Jonathan C. Anthony, Eden
Rassette, Jeannette Schroeder, Justin Feezell, Chuanqi Li, Gerald Gordinier, Gavin
Thomas Strassel, Ryan Clement, Alissa Talley, Caitlin Holman, Yong-Mi Kim, Karen
Stover, Cherie Edmonds, Maria Seiferle, Romer Kristi D. Aranas (RK), Grant Boyer,
Hedemarrie Dussan.
"Think Python – ‫ مقدمة إلى كتاب "فكربطريقة بايثون‬.3
‫ملحة تاريخية عن الكتاب‬
ُ ،)‫مقرر (مدخل إلى لغة جافا‬
ُ 1999 ‫ يناير عام‬/‫في كانون الثاني‬
َّ
َّ ‫أتحضر لتدريس‬
‫وكنت قد‬
‫كنت‬
َ
َّ ‫درست هذا‬
‫ حتى‬،‫املقرر ثالث مرات سابق ٍة وبدأت أشعر بالضيق بسبب معدل الرسوب املرتفع‬
َ ُ
.‫ات تذكر‬
ٍ ‫الناجحين لم يحققوا إنجاز‬
ُ
َ
َ
‫تفاصيل‬
‫ بسبب ضخامتها واحتوائها على‬،‫الكتب هي إحدى أسباب انخفاض املعدالت‬
‫اكتشفت أن‬
‫ليست َ‬
‫ذات أهمية‪ ،‬وافتقارها إلى التوجيه حو َل كيفية كتابة البرامج‪ ،‬لقد َ‬
‫ُ‬
‫جميعهم في‬
‫وقع الطالب‬
‫فخ االستسالم‪ ،‬حيث يبدؤون القراءة ُبيسر ٍويتدرجون باملحتوى حتى الفصل الخامس وبعدها‬
‫َ‬
‫ينسحبون؛ ألن عليهم دراسة محتو ًى جديد بسرعة كبيرة‪ ،‬لذلك وقبل أسبوعين من بداية الفصل‬
‫الدراس ي قررت أن أقوم بتأليف كتابي لعدة أهداف منها‪:‬‬
‫ً‬
‫ً‬
‫ أن يكون‬‫صفحات أفضل من أن أعطيهم ‪ 50‬صفحة لن‬
‫مختصرا (أن يقرأ الطالب ‪10‬‬
‫ٍ‬
‫يلمسها أحد)‪.‬‬
‫ً‬
‫َ‬
‫تقليل املصطلحات التقنية مع ذكر تعريف لكل منها عند‬
‫ أن يكون بسيطا (فقد حاولت‬‫ورودها ألول مرة)‪.‬‬
‫يسهل ُ‬
‫ُ‬
‫فهمها)‪.‬‬
‫ أن يكون متدر ًجا (وزعت املحاور الصعبة إلى خطوات بسيطة‬‫ التركيز على البرمجة ال على لغة البرمجة (ضمنت أهم قواعد لغة جافا وتركت الباقي)‪.‬‬‫ُ‬
‫عنونت الكتاب "كيف تفكر كعالم حاسوب"‪ ،‬الطبعة األولى كانت صعبة لكن الطالب قرؤوها‬
‫كبيرا منها‪ ،‬مما مكنني من شرح املواضيع الصعبة في املحاضرات ومنحهم ً‬
‫وفهموا ً‬
‫جزءا ً‬
‫وقتا أكثر‬
‫للتدرب‪.‬‬
‫أطلقت الكتاب تحت رخصة ‪ GNU‬التي تمنح صالحية النسخ والتعديل والنشر‪.‬‬
‫ً‬
‫تبنى جيف إيلكنير (‪ )Jeff Elkner‬الكتاب وعدله ليكون‬
‫مناسبا لتعليم لغة بايثون‪ ،‬ثم أرسل إلي‬
‫نسخة من كتابه حيث استمتعت ً‬
‫جدا بقراءته‪ ،‬ثم راجعنا الكتاب ً‬
‫معا وأضفنا دراسة حالة أعدها‬
‫كريس مايرز (‪ ،)Chris Meyers‬وفي عام ‪ 2001‬أطلقنا الكتاب تحت عنوان "كيف تفكر كعالم‬
‫حاسوب‪ :‬تعلم لغة بايثون" وفق رخصة ‪ ،GNU‬وبعد نشره بعنا ً‬
‫عددا من النسخ الورقية عبر موقع‬
‫أمازون ومكتبات الجامعة‪.‬‬
‫في عام ‪ ،2003‬بدأت العمل كمدرس في جامعة أولين (‪ )Olin‬وكان علي أن أدرس لغة بايثون للمرة‬
‫األولى‪ ،‬وعلى خالف تعلم لغة جافا لم يعان الطالب ً‬
‫كثيرا بل تعلموا الكثير وعملوا على مشاريع مهمة‬
‫وممتعة‪.‬‬
‫ُ‬
‫ُ‬
‫حسنت ً‬
‫تابعت تطوير وتصحيح الكتاب في السنوات الخمس التالية؛ إذ َّ‬
‫وأضفت‬
‫بعضا من األمثلة‬
‫بعض املحتوى وخاصة التمارين‪.‬‬
‫شاملة للكتاب‪ ،‬وفي الوقت نفسه تواصلت معي دار نشر‬
‫اجعة‬
‫ٍ‬
‫في عام ‪ 2008‬شرعت بإجراء مر ٍ‬
‫جامعة كمبريدج وكانت مهتمة بنشر نسخة جديدة‪ ،‬وكم كانت مصادفة مذهلة!‬
‫أرجو أن تستمتع بالتعلم من هذا الكتاب‪ ،‬وأن يساعدك في تعلم البرمجة‪ ،‬وأن تكتسب بعض‬
‫مهارات التفكير كالتي يتميز بها علماء الحاسوب‪.‬‬
‫كلمة شكر‬
‫أ َّ‬
‫توجه بالشكر الكبير لـ جيف إيلكنير الذي عدل كتابي من تعليم جافا إلى تعليم بايثون‪ ،‬فقد كان‬
‫املحفز لهذا املشروع‪َ ،‬‬
‫وعرفني إلى اللغة التي أصبحت فيما بعد لغتي البرمجية املفضلة‪.‬‬
‫َ‬
‫كذلك أشكر مؤسسة‬
‫كما أود أن أشكر كريس مايرز الذي ساهم بعدة فصول من الكتاب‪،‬‬
‫البرمجيات الحرة (‪ )Free Software Foundation‬إلطالق رخصة ‪ GNU‬والتي سمحت للمؤلفين‬
‫الثالثة بالتعاون لتحقيق هذا اإلنجاز‪ .‬وال يسعني إال أن أشكر محرري الكتاب والطالب الذين قرؤوا‬
‫النسخ األولى منه وأرسلوا لي اقتراحاتهم ومالحظاتهم‪ ،‬وأشكر زوجتي ليزا لدورها في إنجاز الكتاب ودار‬
‫نشر غرين تي (‪ )Green Tea Press‬وكل من ساهم في هذا العمل‪.‬‬
‫آالن دويني‬
‫أستاذ في قسم علوم الحاسوب بكلية فرانكلين أولين للهندسة‬
‫‪ .4‬املساهمون في كتاب " فكربطريقة بايثون – ‪" Think Python‬‬
‫َ‬
‫أرسل ما يزيد عن مئة قارئ مالحظاتهم واقتراحاتهم لتحسين الكتاب على مدى سنوات‪ ،‬وقد كانت‬
‫مساهمتهم وحماسهم ذوي آثر كبير ‪.‬‬
‫لتتعرف على تفاصيل مساهمة كل فرد منهم راجع كتاب "فكر بطريقة بايثون"‪.‬‬
‫األسماء‪:‬‬
‫‪Lloyd Hugh Allen, Yvon Boulianne, Fred Bremmer, Jonah Cohen, Michael‬‬
‫‪Conlon, Benoit Girard, Courtney Gleason and Katherine Smith, Lee Harr, James‬‬
‫‪Kaylin, David Kershaw, Eddie Lam, Man-Yong Lee, David Mayo, Chris McAloon,‬‬
‫‪Matthew J. Moelter, Simon Dicon Montford, John Ouzts, Kevin Parks, David‬‬
Pool, Michael Schmitt, Robin Shaw, Paul Sleigh, Craig T. Snydal, Ian Thomas,
Keith Verheyden, Peter Winstanley, Chris Wrobel, Moshe Zadka, Christoph
Zwerschke, James Mayer, Hayden McAfee, Angel Arnal, Tauhidul Hoque and
Lex Berezhny, Dr. Michele Alzetta, Andy Mitchell, Kalin Harvey, Christopher P.
Smith, David Hutchins, Gregor Lingl, Julie Peters, Florin Oprina, D. J. Webre,
Ken, Ivo Wever, Curtis Yanko, Ben Logan, Jason Armstrong, Louis Cordier, Brian
Cain, Rob Black, Jean-Philippe Rey at Ecole Centrale Paris, Jason Mader at
George Washington University made a number Jan Gundtofte-Bruun, Abel
David and Alexis Dinno, Charles Thayer, Roger Sperberg, Sam Bull, Andrew
Cheung, C. Corey Capel, Alessandra, Wim Champagne, Douglas Wright, Jared
Spindor, Lin Peiheng, Ray Hagtvedt, Torsten Hübsch, Inga Petuhhov, Arne
Babenhauserheide, Mark E. Casida, Scott Tyler, Gordon Shephard, Andrew
Turner, Adam Hobart, Daryl Hammond and Sarah Zimmerman, George Sass,
Brian Bingham, Leah Engelbert-Fenton, Joe Funke, Chao-chao Chen, Jeff Paine,
Lubos Pintes, Gregg Lind and Abigail Heithoff, Max Hailperin, Chotipat
Pornavalai, Stanislaw Antol, Eric Pashman, Miguel Azevedo, Jianhua Liu, Nick
King, Martin Zuther, Adam Zimmerman, Ratnakar Tiwari, Anurag Goel, Kelli
Kratzer, Mark Griffiths, Roydan Ongie, Patryk Wolowiec, Mark Chonofsky,
Russell Coleman, Wei Huang, Karen Barber, Nam Nguyen, Stéphane Morin,
Fernando Tardio, and Paul Stoop.
‫امللحق ب‬
‫حقوق النشر‬
‫العمل مرخص وفق رخصة املشاع اإلبداعي من النمط )استخدام غير تجاري ‪ -‬إصدار العمل الجديد‬
‫بموجب ترخيص مطابق للترخيص األصلي( اإلصدار الثالث‪.‬‬
‫ملعلومات حول الرخصة‪. http://creativecommons.org/licenses/by-nc-sa/3.0/ :‬‬
‫ً‬
‫ً‬
‫مشاعا من رخصة املشاع اإلبداعي ذات النمط‬
‫مرخصا برخصة أكثر‬
‫لكم وددت أن يكون هذا العمل‬
‫(عزو العمل األصلي إلى املؤلف ‪ -‬إصدار العمل الجديد بموجب ترخيص مطابق للترخيص األصلي)‬
‫نسخ الكترونية غير‬
‫أو ‪ CC-BY-SA‬لكن مع األسف قد تستغل بعض الجهات ذلك لتعيد نشر وبيع ٍ‬
‫معدلة من الكتاب ضمن مواقع خدمة الطباعة عند الطلب مثل موقع ‪ LuLu‬وموقع ‪ .KDP‬األخير‬
‫ً‬
‫مشكورا سياسة ٌتعنى باالهتمام بمتطلبات صاحب الحقوق األصلي أكثر من الذين يحاولون‬
‫أضاف‬
‫إعادة نشر الكتب بدون حصولهم على أية حقوق ولكن قلة من مزودي هذه الخدمة اتبعوا نهج موقع‬
‫‪.KDP‬‬
‫أضفت بكل حزن ميزة استخدام غير تجاري إلى رخصة الكتاب ألتفادى هؤالء الذين سيستنسخون‬
‫الكتاب ويبيعونه بهدف الربح املادي‪ .‬هذه امليزة تقيد من حرية استخدام محتوى الكتاب وددت لو‬
‫منحتها بشكل كامل‪ .‬لذا سأشرح في هذا القسم الحاالت التي سأسمح فيها باستخدام محتوى الكتاب‬
‫بشكل تجاري‬
‫ً‬
‫ إذا أردت طباعة عدد محدود من نسخ الكتاب كامال أو أجزاء منه بهدف االستخدام بمقرر‬‫تعليمي فأمنحك رخصة املشاع اإلبداعي من النمط (عزو العمل األصلي إلى املؤلف) أو ‪CC-‬‬
‫‪BY‬‬
‫ إن كنت ً‬‫ً‬
‫جامعيا وترجمت الكتاب إلى لغة غير اإلنكليزية واستخدمت النسخة املترجمة‬
‫مدرسا‬
‫للتدريس‪ ،‬فتواصل معي ألمنحك رخصة املشاع اإلبداعي من النمط )استخدام غير تجاري ‪-‬‬
‫إصدار العمل الجديد بموجب ترخيص مطابق للترخيص األصلي( أو ‪ CC-BY-SA‬بما يتوافق‬
‫مع نسختك املترجمة حيث سأسمح لك باالستخدام التجاري للنسخة املترجمة‪.‬‬
‫إن كنت تبغي ترجمة الكتاب فأنصحك بالتواصل معي حتى أقدم لك كل ما تحتاج من محتوى‬
‫ليكون ً‬
‫متاحا لك لترجمته‪.‬‬
‫وفي حال لديك حالة تختلف عما ذكر أعاله فال تتردد بالتواصل معي فأنا منفتح على منح الرخصة‬
‫في حال هناك قيمة مضافة في طريقة إعادة استخدامك ملحتوى الكتاب‪.‬‬
‫تشارلز سيفيرنس‬
‫‪www.dr.chuck.com‬‬
‫مدينة أن أربور في والية ميشيغان في الواليات املتحدة األميركية‬
‫‪ 9‬أيلول‪ /‬سبتمبر ‪2013‬‬
Download