بايثون للجميع
التعامل مع البيانات باستخدام لغة بايثون 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العدد الصحيح في نهاية هذه األسطر) باستخدام نفس
الطريقة أعاله فبإمكاننا كتابة البرنامج التالي:
'=# Search for lines that start with 'Details: rev
'# 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: ^Xmbox.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
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )