Free Essay

Pythone

In: Computers and Technology

Submitted By ahhyalbi
Words 58244
Pages 233
‫‪Pages de variables‬‬

‫تعلم البرمجة مع بيثون 3‬
‫ُ‬ ‫تأليف : جرار سوين‬ ‫ِ‬ ‫ترجمة : هشام رزق الله وآخرون‬ ‫مراجعة و إخراج : مجتمع لينكس العربي‬

‫النسخة اللكترونية من هذه ص يمكنك الحصول عليهها )باللغة الفرنسية( مجانا وبحرية من:‬ ‫ً‬ ‫النصو‬ ‫ّ‬ ‫‪http://inforef.be/swi/python.htm‬‬

‫‪) How to think like a computer scientist‬كيف تفكر كعالم حاسوب(‬

‫بعض فقرات هذا الكتاب قد تم تكييفها وفقا لكتاب:‬

‫بواسطة: ‪ Allen B. Downey، Jeffrey Elkner‬و ‪Chris Meyers‬‬
‫أو: ‪http://www.openbookproject.net/thinkCSpy‬‬ ‫متاح على: ‪http://thinkpython.com‬‬

‫جميع حقوق الطبعة العربّية محفوظة لتجتمع لينكس العربي )2102 – 3102(‬ ‫جميع حقوق الكتاب اللصلي محفوظة للمؤلف جيالد سوينو )0002 – 2102(‬ ‫يتم توزيع هذا الكتاب بموجب ‪" Creative Commons‬رخصة البداع العامة غي التجارية الشاركة باللثل 0٫2".‬ ‫وهذا يعن أنك تستطيع نسخ وتعديل وإعادة توزيع هذه الصفحات بحرية تامة، ش ط أن تتبع عددا من قواعد هذا التخيص.‬ ‫ً‬ ‫وفي الساس، اعلم أنك ل يمكنك الحصول على ملكية هذا النص وإعادة تتتوزيعه )معتتدل أو غيتت معتتدل( محتتدِّدا لنفستتك حقتتوق‬ ‫تأليف ونش أخرى. الستند الذي قمت بإعادة توزيعه، معدل أو غي معدل، يجب أن يتضمن النص الكامتتل للرخصتتة أعله وهتتذا‬ ‫العشعار والتمهيد الذي يأتي بعده. الوصول إلى هذه اللحظات يجب أن يبقى ح را للجميع. يمكنك طلب مساهمة ماليتتة لتوزيتتع‬ ‫ً‬ ‫هذه اللحظات، لكن البلغ الطلتتوب يجتتب أن يرتبتتط بتكلفتتة النستتخ. ل يمكنتتك إعتتادة توزيتتع هتتذه اللحظتتات وجعلهتتا بحقتتوق‬ ‫تأليفك ونش،ك، ول يمكنك أن تحد من حقوق الستنساخ للنسخ الت قمت بتوزيعها.‬

‫.‬

‫الترخيص :‬
‫هذا العمل متاح ضمن رخصة الشاع البداعي 0٫2 : النسبة – الستخدام غي التجاري – الشاركة باللثل.‬ ‫لك الحرية في أن :‬
‫تشارك – أن تنسخ وتوزع وتنقل العمل.‬ ‫تع ّدل – أن تقوم بتطويع هذا العمل ليناسب احتياجات معينة.‬

‫ضمن الشوط التالية :‬
‫النسبة – يجب ان تنسب العمل بصفته الخاصة إلى اللؤلف أو الرخص.‬ ‫ّ‬ ‫عدم الستخدام تتجارياً – يجب أن ل تستخدم هذا العمل لهداف تجارية.‬ ‫الشاركة بالثل – إذا قمت بتعديل أو تغيي أو تحويل البناء على هذا العمل، فبإمكانك توزيع‬ ‫العمل الناتج ضمن نفس الرخصة أو ضمن رخصة مشابهة لها فقط، وليس ضمن أي رخصة‬ ‫أخرى.‬

‫مع العلم بما يلي :‬
‫التنازل – يمكن تخطي أي من الشو ط الذكورة أعله إذا حصلت على موافقة من صاحب اللكية.‬

‫النص القانوني للرخصة :‬ ‫ّ‬ ‫ّ‬
‫يمكن الحصول على النص القانوني للرخصة باللغة النجليية عب هذا الرابط :‬ ‫ّ‬ ‫ّ‬ ‫ّ‬
‫‪https://creativecommons.org/licenses/by-nc-sa/2.0/legalcode‬‬

‫‪III‬‬

‫.‬

‫تمهيد‬
‫نحمد الله على منته وفضله في إنتجاح هذا العمل، ونرجو أن يكون خالصككا لككوجهه الكريككم. ونشكككر متجتمككع لينكككس‬ ‫ً‬ ‫العربي الذي كان اللظلة الت عمل تحتها مشوع ترجمة هذا الكتاب، والنصة الت انطلق منها هككذا العمككل، والحاضككنة الككت‬ ‫احتضنت هذا الكتاب. ونتقدم بتجزيل الشكر لكل مكن سكاهم معنكا فكي ترجمكة أو تنقيكح ومراجعكة أو تنسكيق أو إخكراج هكذا‬

‫العمل. ول ننس أيضاً أن نتقدم بالشكر لمتجتمع البمتجيات الحّر ة ومفتوحة الصدر لتككوفيهم الدوات الكت اعتمككدنا عليهككا‬ ‫في تحرير هذا الكتاب. ونأمل أن يكون هذا الكتاب منار ة تني درب السالكي في طريق البمتجة، وبالخص البمتجككة بلغككة‬ ‫بيثككون، الكت تعكد لغكة هامكة للمكبمتجي فككي بيئككة نلظكام التشككغيل جنككو/لينككس وفكي إدار ة الخكوادم خالصكة، وفكي أنلظمكة‬

‫الكتاب، أو دعمه مادياً أو معنويا. وإلى كل من كان عوناً لنا بدعمنا معنوي ا أو إبكداء ملحلظكات سكاهمت علكى تحسكي سكي‬ ‫ً‬ ‫ً‬

‫الحاسوب عامة، وأن يشكل إضافة قيمة إلى الحتوى العربي التقن.‬ ‫ّ‬

‫وللمنهتجية الكت اتبعهكا الؤلكف فكي ترتيبكه، ولغنكاه بالمثلكة والتمكارين العمليكة علكى ككل موضكوع، ولتجكود ة هكذه المثلكة‬

‫لقكد اختنككا كتككاب 3 ‪ Aprendre à programmer avec Python‬لكا رأينككاه مكن جكود ة هكذا الكتككاب،‬

‫بمراسككككلتنا عككككب متجتمككككع لينكككككس العربككككي علككككى ‪ ،http://LinuxAC.org‬أو بمراسككككلة الككككتجم علككككى بريككككده >‬

‫الستطاع، ومع هذا يبقى عملً بشي ا يحتمل النقكص، فكإذا ككانت لكديك أيكة ملحلظكات حكول حكول هكذا الكتكاب، فل تكتدد‬ ‫ً‬ ‫‪. "أكب من" الكررة ثلثا هي إعشارة سيعة أو مو جه فوري يخب،ك أن بيلثون مستعد لتلقي الوامر.‬ ‫ِّ‬ ‫على سبيل اللثال، تستطيع استعمال الفس على أنتته آلتتة حاستبة بستتيطة لستتطح الكتتتب. أرجتتو منتتك أن تختتب الوامتتر التاليتتة‬ ‫بنفسك )تعود على استعمال كراس التمارين لكتابة النتائج الت تظهر على الشاعشة(:‬
‫3+5 >>>‬ ‫9 – 2 >>>‬ ‫4 * 3 + 7 >>>‬ ‫4*)3+7( >>>‬ ‫3 / 02 >>>‬ ‫3 // 02 >>>‬ ‫انتباه: هذا يعمل يبشكل مختلف في يبيثون 2 #‬ ‫المسافات اختيارية #‬ ‫التسلسل الهرمي للعمليات الحسايبية #‬

‫كما ترون، فإن العوامل الحسابية للجمع والطتترح والضتتب والقستتمة هتتي علتتى التتتوالي + و– و* و\. ومتتا بيتت القوستتي نتتتيجته‬ ‫متوقعة:‬
‫العلوم ات يرجى زي ارة موقع بياثون.‬ ‫ف نظ ام ترشغيل لينكس، نن نفضل شخصي ا العومل ف ن افذة اليطرفية البسييطة لةترشغيل مفسر بياثون أو ترشغيل السكريبةت ات،‬ ‫واسةتخدام مرر نص ع ادي ماثل ‪ Gedit‬أو ‪ Kate‬أو واحد أكاثر تصص ا ماثل ‪.Geany‬‬

‫الخطوات الولى‬ ‫فــي بيثــون 3، عامــل القســمة / يقــوم بقســمة حقيقيــة )عــدد حقيقــي(. وإذا أردت أن تحصــل علــى قســمة عــدد‬

‫21‬

‫بيثــون 3،ـ مقارنــة مــع الصــدارات الســابقة. فــإذا كنــت تســتخدم إحــدى هــذه الصــدارات، يرجــى ملحظــة أن‬ ‫حقيقي، إذا أدخلت ) على القل( عددا حقيقيا واحدا. لحسن الحظ تم التخلي عن السلوك القديم من بيثــون،‬ ‫لنها كانت تؤدي إلى خلل في بعض الحيان من الصعب اكتشافه.‬ ‫العامل / يقوم بقسمة عدد صحيح بشـكل إفتراضـي، إذا قمـت بتمريـر برامـترات أعـداد صـحيحة وقسـمة عـدد‬

‫صــحيح، يجــب عليــك اســتخدام المعامــل //. ويرجــى ملحظــة أن هــذه التغييــرات أدخلــت علــى تكــوين جملــة‬

‫3 / 5.02 >>>‬ ‫5 / 7,8 >>>‬ ‫!خطأ #‬

‫يرجى ملحظة أن هنالك قاعدة تُط ّبق في جميع لغات البمجة هي الصطلحات الرياضيات السارية في البلدان الناطقة باللغتتة‬ ‫الحاسوب يشار غالبا إلى العداد الحقيقية كأرقام "النقطة العائمة".‬ ‫البيانات لوالمتغيرات‬ ‫سيكون لدينا الفرصة لتعلم تفاصيل أكث لنواع مختلفة من البيانات الرقمية. ولكن قبل ذلك سنتناول الن مفهوما أكث أهميتتة.‬ ‫العمل الرئيس الذي يقوم به برنامج الحاسوب هو معالجة البيانات. ويمكتتن لهتتذه البيانتتات أن تكتتون متنوعتتة جتتدا )فتتي الواقتتع ،‬ ‫ً‬
‫4‬

‫النجليية و من بينها الفاصلة العشتية التت هتتي دائمتا نقطتة، وليستت فاصتلة كمتا عنتدنا. وستوف نلحتظ أيضتا أن فتتي عتالم‬

‫كلها رقمية (، لكن في ذاكرة الحاسوب تحول دائما في النهاية إلى تسلسل محدد من الرقام اللثنائي ة . للوصول إلى البيانات يقوم‬

‫برنامج الحاسوب )بغض النظر عن اللغة الستخدمة في كتابته( باستخدام أعداد كبية متتن التغيتتات مختلفتتة النتتواع. التغيتت‬ ‫يظهر في لغة البمجة كأي اسم متغي آخر تقريبا )أنظر أدناه(، ولكن عند الحاسوب يكون مرجعا يشي إلى عنوان ذاكرة، وهتتذا‬ ‫معناه موقع محدد في ذاكرة الوصول العشوائي )‪ .( ram‬في هذا الوقع يتم تخزين قيمة محددة )وهي البيانات( في سلسلة متتن‬ ‫الرقام اللثنائية، ولكن ليس بالضورة رقم واحد في نظر لغة البمجة الستخدمة، ويمكن أن يتم هذا عن طريق أي "كائن" ويتم‬ ‫وضعه في ذاكرة الحاسوب. علتتى ستبيل اللثتتال: عتدد صتتحيح، عتتدد حقيقتي، سلستلة نصتتية، ناقتتل، سلستتلة مطبعيتتة، جتدول أو‬ ‫وظيفة … إلخ، سوف نشح في الصفحات التالية التميي بي كل هذه الحتويات المكنة ولغة البمجة الستخدمة لنواع‬ ‫مختلفة من التغيات )عدد صحيح، عدد حقيقي، سلسلة نصية، قائمة … إلخ(.‬

‫4م اذا يكن فحصه ب الضبط؟ هذا السؤال مهم جدا، ويب عليك البحث ف دراسةتك ف العلوم الع امة.‬

‫31‬

‫أسماء المتغيرات والكلمات المحجوزة‬ ‫أسماءء المتغيرات لوالكلمات المحجوزة‬

‫أسماء التغيات هي السماء الت تستطيع تسميتها بحرية )تقريبا(، حاول اختيارهم بشكل جيتتد ويفضتتل أن يكتتون قصتتيا جتتدا‬ ‫وواضحا بقدر المكان؛ وذلك للتعبي بوضوح عما يفتض أن يحتوي التغي، على سبيل اللثال، أسماء التغيات ملثتتل الرتفتتاع‬ ‫أو الرتفاع البديل أكث ملئمة للتعبي من ارتفاع ‪.x‬‬

‫البمج التجيد هو الذي يتجعل أسطر برنامتجه سهلة القراء ة.‬
‫في بيلثون يجب أن تتبع أسماء التغيات بعض القواعد البسيطة:‬ ‫•اسم التغي يتكون من سلسلة من الحتتروف )‪ A‬إلتتى ‪ Z‬الكتتبية( و)‪ a‬إلتتى ‪ z‬الصتتغية( والرقتتام )0 إلتتى 9( ويجتتب أن يبتتدأ‬ ‫دائما بحرف.‬ ‫• ل يستتمح إل بتتالحرف العاديتتة ويمنتتع استتتعمال الستتاحات والرمتتوز )أحتترف خاصتتة ملثتتل!@#$%^&* ومتتا إلتتى ذلتتك(‬ ‫باستلثناء الرمز _ )خط تحت السطر(.‬ ‫•من الهم التميي بي الحرف الكبية والصغية.‬

‫انتبه: ‪ Joseph، joseph، JOSEPH‬متغيات مختلفة فكن حذرا .‬

‫تعود على كتابة معظم السماء بأحرف صغية. هذه مجرد اتفاقية ولكنها باحتام واسع. استخدم الحرف الكبية ضمن نفتتس‬ ‫السم، ذلك لزيادة سهولة القراءة، كما هو الحال في ‪.TableofContents‬‬ ‫بالضافة إلى تلك القواعد، يجب أن نضيف أيضا أنه ل يمكننا استخدام أسماء متغيات محجوزة )33 كلمة( البينة أدنتتاه؛ يتتتم‬ ‫استخدامها من قبل اللغة نفسها:‬
‫‪and‬‬ ‫‪del‬‬ ‫‪from‬‬ ‫‪None‬‬ ‫‪True‬‬ ‫‪as‬‬ ‫‪elif‬‬ ‫‪global‬‬ ‫‪nonlocal‬‬ ‫‪try‬‬ ‫‪assert‬‬ ‫‪else‬‬ ‫‪if‬‬ ‫‪not‬‬ ‫‪while‬‬ ‫‪break‬‬ ‫‪except‬‬ ‫‪import‬‬ ‫‪or‬‬ ‫‪with‬‬ ‫‪class‬‬ ‫‪False‬‬ ‫‪in‬‬ ‫‪pass‬‬ ‫‪yield‬‬ ‫‪continue‬‬ ‫‪finally‬‬ ‫‪is‬‬ ‫‪raise‬‬ ‫‪def‬‬ ‫‪for‬‬ ‫‪lambda‬‬ ‫‪return‬‬

‫تعيين قيمة متغير‬ ‫لقد أصبحنا نعرف الن كيف نختار اسم التغي بحكمة، الن سوف نشح كيفية تعيي قيمة للمتغي والصطلح "تعييتت قيمتتة"‬ ‫هي دللة على عملية إقامة صلة بي اسم التغي وقيمته )محتوياته(. في بيلثون، كما هو الحال في العديد من اللغتتات الختترى،‬ ‫تملثل هذه العملية بواسطة علمة الساواة )=(:‬

‫الخطوات الولى‬
‫7 = ‪>>> n‬‬ ‫"? ‪>>> msg = "Quoi de neuf‬‬ ‫95141.3 = ‪>>> pi‬‬ ‫اعطاء القيمة 7 للمتغير ‪# n‬‬ ‫تعيين القيمة )? ‪ (Quoi de neuf‬للمتغير ‪# msg‬‬ ‫اعطاء قيمة للمتغير ‪# pi‬‬

‫41‬

‫و توضح الملثلة أعله تعيي البيانات في بيلثون، بعد أن تم تنفيذها في ذاكرة الحاسوب، في أماكن مختلفة:‬

‫•أسماء ثلثة متغيات: ‪ n، msg‬و ‪pi‬‬
‫•تسلسل البيانات اللثلثة، والت يتم ترمي 7 بعدد صحيح وجملة ‪ ? Quoi de neuf‬بسلسلة والعدد 95141,3 بعدد‬ ‫صحيح.‬ ‫البيانات اللثلثة الذكورة أعله للتعيي، كان لكل منها أثر في تنفيذ عدة عمليات في ذاكرة الحاسوب:‬ ‫•إنشاء وتخزين اسم متغي.‬ ‫•تعيي نوع محدد جيد )سيتم توضيحه في الصفحة التالية(.‬ ‫•إنشاء وتخزين قيمة معينة.‬ ‫• ارتبا ط )عن طريق ملؤشات داخلية( بي اسم التغي وموقع الذاكرة من القيمة الطابقة.‬ ‫أفضل طريقة للشح هي تملثيل كل هذا برسم تخطيطي:‬

‫أسماء التغيات اللثلثة مخزنة ولديها مراجع في منطقة معينة من الذاكرة تسمى مساحة السماء، في حي تقتتع القيتتم النتتاظرة‬ ‫في أماكن أخرى، وأحيانا بعيدة جدا عن بعضها البعض، وسوف نوضح هذا الفهوم أكث في الصفحات القادمة.‬ ‫عرض قيمة متغير‬ ‫بعد التمارين الذكورة أعله، سيكون لدينا ثلثة متغيات ‪ n، msg‬و ‪ pi‬لعرض قيمة متغي على الشاعشة، هنالك طريقتان،‬ ‫الولى هي كتابة اسم التغي ثم النقر على مفتاح الدخال "‪ ،"Enter‬فسيستجيب بيلثون فيعرض القيمة:‬
‫‪>>> n‬‬ ‫7‬ ‫‪>>> msg‬‬ ‫'? ‪'Quoi de neuf‬‬ ‫‪>>> pi‬‬ ‫95141.3‬

‫51‬

‫عرض قيمة متغير‬

‫هذه مية ثانية للمفس، الذي يهدف إلى جعل الحياة أسهل عند القيام بتمارين بستيطة فتي ستطر الوامتر، فتي داختل البنامتج،‬ ‫سوف تستخدم دائما ‪: ()print‬‬
‫5‬

‫)‪>>> print(msg‬‬ ‫? ‪Quoi de neuf‬‬ ‫)‪>>> print(n‬‬ ‫7‬

‫لحظ الفرق الدقيق بي طرق العرض الت تم الحصول عليها مع كل طريقة. وظيفة ‪ ()print‬ل تظهر بدقة قيمة التغي كما أنه‬ ‫تم ترميها، في حيتت أن الطريقتة الختترى )وهتي فقتط إدختال استم التغيت( يعتترض ملثل علمتات القتبتاس لكتي يتذكركم أنكتم‬ ‫تتعاملون مع متغي ملثل سلسلة )سنتعرف إلى هذا في وقت آخر(.‬ ‫في الصدارات السابقة لبيثون، دور دالة الطباعة ‪ ()print‬هو التعليمة ‪ print‬الخاصة )ممــا يجعلهــا مــن‬ ‫‪ print n‬أو ‪ .print msg‬وإذا أردت لحقا اسـتخدام بيثـون 3 فـي برامـج مكتوبـة بإحـدى نســخ بيثـون‬

‫الكلمــات المحجــوزة(، وهــذه التعليمــة تســتخدم بــدون أقــواس. فــي التمــارين الســابقة ، يجــب عليــك إذا كتابــة‬ ‫ً‬ ‫القديمة، يجب عليك إضـافة القـواس بعــد كـل تعليمـة ‪ print‬لتحويلهـا إلـى دالـة )يمكــن للدوات المسـاعدة‬ ‫في هذه الصدارات القديمة، يتم معالجة السلسل النصـية بشـكل مختلـف )سـوف نتحـدث عـن هـذا بالتفصـيل‬ ‫القيام بذلك تلقائيا (.‬

‫لحقا(. واعتمادا على تكوين جهـاز حاسـوبك، سـوف تـواجه بعـض الرمـوز الغريبـة عنـدما تتعامـل مـع سلسـل‬
‫"‪>>> msg = "Mon prénom est Chimène‬‬ ‫‪>>> msg‬‬ ‫'‪'Mon pr\xe9nom est Chim\xe8ne‬‬

‫نصية تحتوي على أحرف معلمة، مثل:‬

‫أن يعــرف كي ــف يتــم ترمي ــز المحــارف الــتي ت ــواجهه ف ــي مص ــادر مختلفــة مــن البيان ــات، لن تحدي ــد هــذه‬

‫هذا الشياء الغريبة تنتمي إلى الماضي، ولكن سوف نرى لحقـا كيــف أن المبرمـج الجـدير بهـذا السـم يجـب‬ ‫الترميزات تغيرت على مر السنين، ويجب أن نعرف التقنيات لتحويلها.‬ ‫كتابة المتغيرات‬

‫في بيلثون ليس من الضوري كتابة أسطر معينة من التعليمات البمجيتتة لتعريتتف نتتوع التغيتت قبتتل استتتخدامها. لنتته ببستتاطة‬ ‫عند تعيي قيمة إلى اسم التغي يقوم بيلثون بوضع نوع التغي تلقائيا مع النوع الذي يطابق القيمة القدمة.‬ ‫في التمرين السابق، على سبيل اللثال، يتم إنشاء أنواع التغيات تلقائيا ملثل )‪ :n‬صحيح، ‪ :msg‬سلسلة، ‪ :pi‬عدد حقيقي(.‬ ‫هذه هي مية ملثية للهتمام في بيلثون، الت تتبع لعائلة معينة من اللغات حيتث يوجتد متن نفتس العائلتتة علتتى ستبيل اللثتال،‬ ‫ليسب وسكيم…إلخ، طريقة كتابة التغيات في بيلثون حيوية على عكس الكتابة اللثابتة الت هي على قاعدة ثابتة، على سبيل‬
‫سيةتم تديد اله ام ب الةتفصيل ف الفصول 6 و 7 )انظر الصفحة 15(.‬ ‫5‬

‫الخطوات الولى‬

‫61‬

‫اللثال في لغة س أو جافا يجب العلن أول مرة عن اسم ونوع التغي، عندها فقط يمكنك تعيي الحتوى، والذي يجب بتتالطبع‬ ‫أن يكون متوافقا مع النوع العلن.‬ ‫الكتابة اللثابتة هي الفضل في حالة اللغات التجمة؛ لنه يحسن عملية الجمع )الت نتيجتها برنامج بالبيناري(.‬ ‫ِ‬ ‫الطباعة الديناميكية أكث سهولة لكتابة بنيات النطقية لستوى عال )النعكاسية، متابروغراميك( ول سّيما فتتي ستتياق البمجتتة‬ ‫الكائنية )تعدد العشكال( كما يسهل استخدام هياكل البيانات الغنية ملثل القوائم والقواميس.‬ ‫تعدد المهام‬ ‫في بيلثون يمكنك تعيي قيمة لتغيات عدة في نفس الوقت، على سبيل اللثال:‬
‫7 = ‪>>> x = y‬‬ ‫‪>>> x‬‬ ‫7‬ ‫‪>>> y‬‬ ‫7‬

‫يمكنك أيضا إعطاء قيمة لكل متغي من التغيات في آن واحد معا:‬
‫33.8 ,4 = ‪>>> a, b‬‬ ‫‪>>> a‬‬ ‫4‬ ‫‪>>> b‬‬ ‫33.8‬

‫في هذا اللثال، تم تعيي قيم مختلفة لكل من ‪ a‬و ‪- b‬في وقت واحد- هي 4 و 33,8.‬ ‫الفرنكوف ــونيين )والع ــرب أيض ــا( ل ــديهم ع ــادة باس ــتخدام الفاص ــلة كفاص ــل عش ــري، وأم ــا لغ ــات البرمج ــة‬

‫فتســتخدم دائمــا التفاقيــة الحاليــة بيــن البلــدان الناطقــة باللغــة النكليزيــة، وهــذا معنــاه أن تســتخدم النقطــة‬

‫العشرية. والفاصلة , التي نستخدمها نحن ، تستخدم لفصل مختلف العناصر )برامــترات، إلـخ( وكمــا رأينــا‬

‫في مثالنا، لقيم المتغيرات التي قمنا بتعيينها.‬

‫تمارين‬
‫وضح ماذا يحدث عند كتابة كل واحدة من التعليمات اللثلثة للملثال في السفل:‬
‫02 = ‪>>> largeur‬‬ ‫3.9 * 5 = ‪>>> hauteur‬‬ ‫‪>>> largeur * hauteur‬‬ ‫039‬

‫2. 1‬

‫قم بتعيي 7،5،3 إلى التغيات ‪ .a،b،c‬ثم قم بتنفيذ ‪ a-b//c‬وفس النتيجة التحصل عليها.‬

‫2. 2‬

‫71‬

‫العوامل والتعايبير‬ ‫العوامل لوالتعابير‬ ‫قم بالتلعب بقيم التغيات مع العاملت لتشكيل التعبيات. على سبيل اللثال:‬

‫21 ,3.7 = ‪a, b‬‬ ‫5/‪y = 3*a + b‬‬

‫في هذا اللثال، بدأنا بتعيي للمتغيين ‪ a‬و ‪ b‬القيم 3,7 و 21.‬ ‫كما شحنا سابقا، يقوم بيلثون تلقائيا بتعيي نوع "حقيقي" للمتغي ‪ ،a‬والنوع "صحيح" للمتغي ‪.b‬‬

‫السطر اللثاني من ملثالنا، يقوم بتعيي للمتغي الجديد ‪ y‬نتيجة التعبي الذي يحتوي على العوامل *، + و/ مع العاملت ،‪a، b‬‬
‫3 و 5 . والعوامل هي رموز خاصة تستخدم لتملثيل العمليات الحسابية البسيطة ملثل الجمع والطرح والعاملت هتتي قيتتم تجمتتع‬ ‫بمساعدة العوامل.‬ ‫يقوم بيلثون بتقييم كل تعبي يقدم إليه، ولو كان معقد، ونتيجة هذا التقييم هو دائما قيمة، لهذه القيمة يتم تلقائيا تعيي نوعهتتا،‬ ‫وهي تعتمد على ما يوجد في التعبي. في اللثال أعله، سيكون ‪ y‬نوع حقيقي، لن التعبي الذي تتتم تقييمتته يحتتتوي علتتى القتتل‬ ‫عدد حقيقي.‬ ‫عوامل بيلثون ليست فقط العوامل الربعة الرياضية الساسية. ولقد رأينا بالفعل وجود عامل القسمة الصحيح //. ويوجتتد أيضتتا‬ ‫العامل ** للسس )القوة(، و يوجد العديد من العوامل النطقية، ملثل عوامل السلسل النصية، وعوامل اختبار الهويتة أو النتمتاء‬ ‫وإلخ. سوف نتحدث على كل هذا في الصفحات القادمة.‬ ‫وبالناسبة يوجد عامل مودولو )‪ ،(modulo‬الملثل بالرمز %. هذا العامل يقوم بتوفي ما تبقى من عملية القسمة لعتدد صتتحيح.‬ ‫ّ َ‬
‫)!لظحظ ما يحدث ( #‬

‫حاول على سبيل اللثال:‬

‫3 % 01 >>>‬ ‫5 % 01 >>>‬

‫هذا العامل سيكون مفيدا في وقت لحق، وخاصة لختبار ما إذا كان العدد ‪ a‬يقبل القسمة على ‪ .b‬ويكفي للتحقق كتابة % ‪a‬‬
‫‪ b‬ليعطي نتيجة صفر إذا كان يقبل القسمة.‬ ‫ِ‬ ‫اختب أسطر التعليمات، وصف ما يحدث:‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫95141.3 ,21 = ‪r , pi‬‬ ‫2**‪s = pi * r‬‬ ‫)‪print(s‬‬ ‫))‪print(type(r), type(pi), type(s‬‬

‫تمارين‬
‫2. 3‬

‫الخطوات الولى‬

‫81‬ ‫في رأيك، ما فائدة الدالة ‪()type‬؟‬ ‫)ملحظة: سيتم وصف الهام بالتفصيل في الفصلي 6 و 7(.‬ ‫ترتيب المعاملت‬

‫عندما يكون هنالك أكث من عامل في التعتبي، فيجتب علينتا أن نعترف ترتيتتب العمليتات التت تعتمتد علتتى القواعتد الوليتتة، فتي‬ ‫بيلثون، القواعد الولية هي نفس قواعد الرياضتتيات التتت كنتتت تدرستتها، ويمكنتتك حفظهتتا بستتهولة باستتتخدام خدعتتة ‪PEMDAS‬‬ ‫إختصارا لت:‬ ‫• ‪ P‬ما بي قوسي، ما بي القوسي له أولوية قصوى، حيث تستطيع أن ترتب التعبي بالتتيب الذي تريده.‬ ‫هكذا 2*)3-1( = 4، و)1+1(**)5-2( = 8.‬ ‫• ‪ E‬للسس )القوة(، الولوية اللثانية للسس قبل غيها من العمليات.‬ ‫هكذا 2**1+1 = 3 )ليس 4(، و 3*1**01 = 3 )ليس 94095!(.‬ ‫• ‪ M‬و ‪ D‬للضب والقسمة، الت لهما نفس الولوية. يتم تقيمهما قبل الجمع ‪ A‬والطرح ‪ S‬اللذان يجران آخر المر.‬ ‫هكذا 2*3-1 = 5 )بدل من 4(، و 3/2-1 = -3333.0... )بدل من 0.1(.‬ ‫ً‬ ‫ً‬ ‫• إذا كان هنا،ك أكث من عاملي لهما نفس الولوية، يتم التقييم من اليسار إلى اليمي.‬ ‫•وبالتتتالي فتتي التعتتبي 95*001//06، يجتتب إجتتراء الضتتب أول، ثتتم ينفتذ الجهتتاز 0095//06 التذي يعطتتي 89، إذا أجريتتت‬ ‫القسمة أول ستكون النتيجة 95 )تذكر هنا أن العامتتل // يقتتوم بعمليتتة قستتمة عتدد صتتحيح، وقتم بتتالتحقق متن خلل 95*)‬ ‫001//06((.‬ ‫البنية‬ ‫حت ال ن اطلعنا على مختلف عناص لغة البمجة وهي: التغيات، التعبيات والتعليمات ولكن دون معالجتتة، كيتتف يمكننتتا أن‬ ‫نوحدها بعضها مع بعض؟‬ ‫نأتي إلى ذكر واحدة من نقا ط القوة الكبية ل لغات البمجتتة عاليتتة الستتتوى هتتي أنهتتا تتيتتح بنتاء مجموعتتة تعليمتتات عتن طتترق‬ ‫ُِ‬ ‫تجميع أجزاء مختلفة، على سبيل اللثال، إذا كنت تعترف كيفيتتة إضتتافة رقميتت وكيفيتتة عتترض قيمتتة، يمكنتتك الجمتتع بيتت هتتاتي‬
‫)3 + 71(‪>>> print‬‬ ‫02 >>>‬

‫التعليمتي:‬

‫هذا قليل من كلثي، ستتوضح هذه الية عندما تقوم بخوارزميات معقدة بوضوح واختصار، على سبيل اللثال:‬

‫البنية 91‬
‫43 ,72 ,51 = ‪>>> h, m, s‬‬ ‫)‪ = ", h*3600 + m*60 + s‬عدد الثواني المنقضية منذ منتصف الليل "(‪>>> print‬‬

‫تنبيه: هنا،ك حد لا يمكن جمعه:‬ ‫في العبارة، يجب عليك أن تضع اسم التغي على الجانب اليس من علمة الساواة وليس التعبي وذلك لنهتتا ل تمتلتتك نفتتس‬ ‫العن كما في الرياضيات: كما لحظنا في وقت سابق وهذه هي مهمة هذا الرمز )وضع بعض الحتويات إلى متغي( وهتتو ليتتس‬ ‫رمزً ا للمساواة. وسوف نتحدث على رمز الساواة )على سبيل اللثال في الجمل الشطية( فيما بعد.‬ ‫على سبيل اللثال، العبارة ‪ m + 1 = b‬خاطئة.‬ ‫من السلبيات، كتابة 1 + ‪ a = a‬لنه أمر غي مقبتول فتتي الرياضتيات، فتي حيتت أن هتذا النتوع متن الكتابتتة عشتائع جتدا فتي‬ ‫البمجة. معن 1 + ‪ a = a‬هو زيادة قيمة التغي بقيمة 1.‬ ‫سوف نتحدث حول هذا الوضوع قريبا. نحن نحتاج أول إلى فهم مفهوم أكث أهمية.‬

‫3‬
‫3التحكم في تلقيم التنفيذ‬
‫في الفصل الول، عرفنا أن النشا ط الساس للمبمج هو إيجاد حلول للمشاكل، ومن أجل حل مشكلة في الحاسوب، يجب دائمتتا‬ ‫القيام بسلسلة من الجراءات بتتيب معي، ويطلق على هذه الجراءات والتتيب الذي ينبغي القيام به بالخوارزمية.‬ ‫في بيلثون يسمى هذا البنامج بتلقيم التنفيذ، وتسمى الهياكل الت تعدلها بتعليمات التحكم في التلقيم ببنية التحكم.‬ ‫وهي مجموعات من التعليمات الت تحدد ترتيب الجراءات الت يتتم تنفيتذها. وفتي البمجتتة الحديلثتة، توجتد ثلثتتة أنتواع فقتط:‬ ‫السلسلة والشو ط -الت سنناقشها في هذا الفصل- والتكرار الذي سنناقشه في الفصل القادم.‬

‫تسلسل التعليماتء‬ ‫الذي لم نذكره هو أنه يتم تنفيذ تعليمات البنامج الواحدة تلو الخرى بالتتيب كما هي مكتوبة في السكربت.‬ ‫قد يبدو لك هذا تافها للوهلة الولى، ومع ذلك فإن التجربة تدل على أن عددا كبيا متن الخطتتاء الدلليتتة فتتي برامتتج الحاستتوب‬ ‫هي نتيجة لتعليمات سيئة )خاطئة(. كلما تقدمت أكث في فن البمجة، سوف تدر،ك أكتتث حتتول الحتذر بشتتأن الكتتان التذي يجتتب‬ ‫وضع التعليمات الخاصة بك واحدة تلو الخرى. على سبيل اللثال، في تسلسل التعليمات التالية:‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫7 ,3 = ‪a, b‬‬ ‫‪a = b‬‬ ‫‪b = a‬‬ ‫)‪print(a, b‬‬

‫سوف تحصل على نتيجة عكسية إذا كنت قد بدلت بي السطر اللثاني واللثالث.‬ ‫بيلثون يدير التعليمات في الوضع الطتبيعي متن البدايتة إلتتى النهايتتة، إل إن واجته جمل شتتطية ملثتل ‪ if‬كمتتا هتتو واضتح أدنتاه‬ ‫ِ‬ ‫)سوف نتعرف على غيهتتا ول ستّيما الحلقتات التكراريتتة(، وهتذه التعليمتتات تستتمح للبنامتج بمتابعتتة الستتارات الختلفتتة تبعتتا‬

‫للظروف.‬

‫التحكم في تلقيم التنفيذ‬

‫22‬ ‫تحديد ألو تنفيذ شرط‬

‫إذا كنا نريد كتابة تطبيقات مفيدة، فنحن بحاجة إلى توجيه تقنيات تشغيل البنامج في اتجاهات مختلفة، تبعتتا للظتتروف التتت‬ ‫تواجه البنامج، وللقيام بذلك نحن بحاجة إلى تعليمات لختبار ش ط وتعديل سلو،ك البنامج وفقا لذلك.‬ ‫أبسط هذه الجمل الشطية هي التعليمة ‪ ،if‬ولختبار عملها يجب عليك إدخال هذين السطرين إلى محرر بيلثون:‬
‫051 = ‪>>> a‬‬ ‫:)001 > ‪>>> if (a‬‬ ‫...‬

‫المر الول هو لتعيي قيمة 051 إلى التغي ‪ .a‬حت الن ل شء جديد.‬ ‫و عند النتهاء من إدخال السطر اللثاني، ستجد أن بيلثون سيتفاعل بطريقة جديدة، في الواقتتع إذا لتتم تنتتس الرمتتز ":" فتتي نهايتتة‬ ‫َ‬ ‫السطر، ستجد أنه قد تم استبدال الوجه الرئيس ) a‬‬ ‫:)001 > ‪>>> if (a‬‬ ‫...‬ ‫)"‪print("a dépasse la centaine‬‬ ‫...‬

‫إذا كان لديك محرر ل تلقائي، يجب عليك الن إدخال تبويت )أو أدخل أربعة مسافات( قبل التتدخول إلتتى الستتطر التتتالي، بحيتتث‬

‫انقر مرة أخرى زر الدخال )‪ (Enter‬ستى أن البنامج سيعمل وستحصل على:‬
‫‪a dépasse la centaine‬‬

‫كرر نفس العملية لكن مع 02 = ‪ a‬في السطر الول: في هذه الرة، بيلثون لم يظهر عشيئا.‬ ‫التعبي الذي وضعته بي قوسي نسميه ش ط، تستخدم ‪ if‬لختبار صحة هذا الش ط، فإذا كتتان الشتت ط صتتحيحا فستتوف يتتتم‬ ‫ُ‬ ‫َ‬ ‫تنفيذ ما بعد الرمز ":" وإذا كان الش ط غي صحيح، ل يحدث شء، لحظ أن القواس الستخدمة هنا مع عبارة ‪ if‬اختياريتتة،‬ ‫لقد استخدمناها لتحسي إمكانية القراءة، في اللغات الخرى، قد تصبح إلزامية.‬ ‫أكرر مرة أخرى، بعد إضافة أول سطرين كما هو متبي فتي الستفل. تأكتد متن أن الستطر الرابتع بتدأ علتتى اليستار )بتدون مستافة‬ ‫البادئة(، ولكن مرة أخرى نضيف بادئة جديدة في السطر الخامس )ويفضل نفس مسافة بادئة السطر اللثالث(:‬
‫02 = ‪>>> a‬‬ ‫:)001 > ‪>>> if (a‬‬ ‫...‬ ‫)"‪print("a dépasse la centaine‬‬ ‫:‪... else‬‬ ‫...‬ ‫)"‪print("a ne dépasse pas cent‬‬ ‫...‬

‫أنقر مرة أخرى زر الدخال )‪ (Enter‬سيعمل البنامج وسيعرض:‬

‫32‬
‫‪a ne dépasse pas cent‬‬

‫تحديد أو تنفيذ شرط‬

‫كما فهمت أنت، العبارة ‪" else‬إذا" تسمح للمبمج بتعيي تنفيذ بديل في برنامج من احتمالي. ويمكننا فعتتل أفضتتل متتن هتتذا‬ ‫عن طريق استخدام العبارة ‪) elif‬دمج ‪:(else if‬‬
‫>>>‬ ‫>>>‬ ‫...‬ ‫...‬ ‫...‬ ‫...‬ ‫...‬ ‫...‬ ‫0 = ‪a‬‬ ‫: 0 > ‪if a‬‬ ‫)"‪print("a est positif‬‬ ‫: 0 < ‪elif a‬‬ ‫)"‪print("a est négatif‬‬ ‫:‪else‬‬ ‫)"‪print("a est nul‬‬

‫مقارنة المعاملت‬ ‫التعليمة ‪ if‬للتحقق من الشو ط، قد تحتوي على عوامل القارنة التالية:‬
‫‪x‬‬ ‫‪x‬‬ ‫‪x‬‬ ‫‪x‬‬ ‫‪x‬‬ ‫‪x‬‬ ‫‪== y‬‬ ‫‪!= y‬‬ ‫‪> y‬‬ ‫‪< y‬‬ ‫‪>= y‬‬ ‫‪>> a‬‬ ‫:)0 == 2 % ‪>>> if (a‬‬ ‫...‬ ‫)"‪print("a est pair‬‬ ‫...‬ ‫)"‪print("parce que le reste de sa division par 2 est nul‬‬ ‫:‪... else‬‬ ‫...‬ ‫)"‪print("a est impair‬‬ ‫...‬

‫لحظ أن عامل الساواة بي القيمتي يتكون من رمزي مساواة وليس واحدا. علمة مساواة واحدة هي عامل تعيي وليس عامتتل‬ ‫ّ‬ ‫ً‬ ‫مقارنة. وسوف تجد نفس الرمز في لغات أخرى كجافا وس بلس بلس.‬

‫ّ‬ ‫بيانات المشغل – عبارة الكتل‬ ‫البناء الذي استخدمته مع العبارة ‪ if‬هتو ملثالتك الول متن مشتت ّغل البيانتات. قريبتا ستوف تجمتع آخريتن. فتي بيلثتون، البيانتات‬ ‫الركبة لديها نفس البنية: نقطتان عموديتان تليهما عبارة أو أكث البادئة تحت خط العمود، على سبيل اللثال:‬
‫:‪Ligne d’en-tête‬‬ ‫‪première instruction du bloc‬‬ ‫... ...‬ ‫... ...‬ ‫‪dernière instruction du bloc‬‬

‫التحكم في تلقيم التنفيذ‬

‫42‬

‫إذا كان هنالك عبارات متعددة مسبوقة ببادئة تحت الخط العمودي، يجب أن يكونوا علتتى نفتتس الستتتوى )علتتى ستبيل اللثتتال 4‬ ‫ِ‬

‫مساحات فارغة(، بادئة هذه التعليمة هي ما نسميه الن كتلة العبارات. كتلة العبارات هي سلسلة متن التعليمتتات تُشتتِّكل وحتدة‬ ‫ِ‬

‫ا لنطق، والت ل يتم تنفيتتذها إل فتتي ظتتروف معينتتة يتتم تحديتتدها فتتي الختط العمتتودي. فتتي اللثتال فتتي الفقترة الستتابقة، ستطري‬ ‫ّ‬ ‫َ‬ ‫العبارة تحت السطر الذي يحتوي العبارة ‪ if‬هما كتلتتة النطتتق نفستها فستتيتم تنفيتتذ هتذين الستتطرين )علتتى حتد ستتواء( إذا كتان‬ ‫اختبار الش ط مع العبارة صحيحا وهذا معناه باقي القسمة على 2 ل شء.‬ ‫التداخلت‬ ‫من المكن أن تتتداخل في كل الركبات عدة تصاريح أخرى من أجل تنفيذ الش ّغل هياكل صنع القرار، على سبيل اللثال:‬
‫:"‪if embranchement == "vertébrés‬‬ ‫:"‪if classe == "mammifères‬‬ ‫:"‪if ordre == "carnivores‬‬ ‫:"‪if famille == "félins‬‬ ‫)"‪print("c’est peut-être un chat‬‬ ‫)"‪print("c’est en tous cas un mammifère‬‬ ‫:"‪elif classe == "oiseaux‬‬ ‫)"‪print("c’est peut-être un canari‬‬ ‫)"‪print("la classification des animaux est complexe‬‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫1‬ ‫2‬ ‫3‬ ‫4‬ ‫5‬ ‫6‬ ‫7‬ ‫8‬ ‫9‬

‫تحليل هذا اللثال، هذا الجتتزء متتن البنامتتج ل يطبتتع عبتتارة " ‪ " c’est peut-être un chat‬إل إن كتتانت نتائتتج اختبتتار أول‬ ‫أربعة شو ط صحيحة.‬ ‫ليتم عرض جملة " ‪ "c’est en tous cas un mammifère‬يجب أن يتحققتتا شتتطان. العبتارة الطبوعتتة فتتي هتذه الجملتتة‬ ‫)السطر الرابع( هي في الواقع على مستوى السافة البادئة لنفس التعليمات: ‪) "if ordre == "carnivores‬السطر‬ ‫اللثالث( وبالتالي هما -على حد سواء- جزء من الكتلة نفسها، والت تعرض إذا كانت نتائج اختبتتار الشتتو ط فتتي الستتطرين الول‬ ‫ُ‬ ‫واللثاني صحيحة.‬

‫ليتم عرض عبارة " ‪ "c’est peut-être un canari‬يجب أن يكون التغي ‪ embranchement‬يحتوي علتتى "‪،"vertébrés‬‬ ‫ومتغي ‪ classe‬يحتوي على "‪."oiseaux‬‬ ‫أما بالنسبة للجملة في السطر التاسع، فيتم عرضها في جميع الحالت، لنها جزء من كتلة نفس البيانات في السطر الول.‬ ‫بعض القواعد لبناء جملة في بيثون‬ ‫كل ما سبق يقودنا إلى بعض قواعد بناء جملة :‬

‫52‬

‫يبعض القواعد لبناء جملة في يبيثون‬ ‫تعريف حدود التعليمات والكتل بالتخطيط‬

‫في ال كلثي من لغات البمجة، يجب عليك إتمام كل ستطر متن التعليمتات برمتز ختاص )غالبتا متا يكتون الفاصتلة النقوطتتة (، فتي‬ ‫ّ‬ ‫بيلثون، هذا الحرف في نهاية السطر يلعب هذا الدور، )سنى لحقا كيفية استعمال هتتذه القاعتتدة لتوستيع مشتتغل البيانتات إلتى‬ ‫أسطر متعددة( وأيضا إستكمال خط التعليمة مع التعليق. تعليق بيلثون يبدأ دائما مع الحرف الخاص # ويتم تجاهل كل ما يتم‬ ‫و في معظم لغات البمجة الخرى، يجب أن تكون كتلتة البيانتات متع رمتوز معينتتة )حتت فتتي بعتض الحيتان تعليمتات البدايتة‬ ‫‪ begin‬والنهاية ‪ .(end‬في س بلس بلس وجافا على سبيل اللثال، يجب وضع كتلة البيانتتات داختتل أقتتواس، وهتتذا يستتمح‬ ‫لكتابة كتل من التعليمات واحدة تلو الخرى، متن دون قلتق أو فواصتل أو ستطر الستافة البادئتة ولكتن هتذا يمكتن أن يتلؤدي إلتى‬ ‫ارتبا،ك في كتابة البامج، فنحن البش من الصعب علينا قراءة هذه الفقرات. ولذلك ينصتح جميتع التبمجي التذين يستتتخدمون‬ ‫هذه اللغات باستخدام فواصل السطر والسافات البادئة لتسم كتل بصية.‬ ‫مع بيلثون، يجب استخدام فواصل السطر والسافات البادئة، ولكن في القابل ل يوجد ما يدعو للقلق من رموز كتلتتة التحديتدات‬ ‫الخرى. في النهاية، بيلثون يدفعك لكتابة عشفرة مصدرية قابلة للقراءة وأخذ العادات الجيدة الت كنت تحتفظ بها عند استخدام‬ ‫لغات أخرى.‬ ‫مشغل البيانات: الرأس، النقطتان وكتلة بادئة للبيانات‬ ‫ّ‬ ‫سيكون لدينا فرصا عديدة لستكشاف مفهوم "تعليمة الكتلة" والقيام بتمارين حول هذا الوضوع في الفصل التالي.‬ ‫و يلخص الرسم البياني أدناه البدأ.‬ ‫• ترتبط التعليمات دائما مع الخط العمودي الذي يحتوي علتتى تعليمتتات محتتددة‬ ‫للغاية ) ‪… if ،elif ، else، while ، def‬إلخ( الت تنتهي بنقطتي .‬ ‫• الكتل محددة من قبل مسافة البادئة: يجب أن تكون جميع السطر على طريقتتة‬ ‫)طتتول البادئتتة ( )و هتتذا يعنتت التحتتول إلتتى نفتتس العتتدد متتن الستتافات( يمكتتن‬ ‫استخدام أي عدد للمسافات ولكن معظم البمجي يستخدمون مضتتاعفات الرقتتم‬ ‫4.‬ ‫•لحظ أنه يمكن للكود الكتابة بعيدا )كتلتتة 1 ( فتتي حتتد ذاتهتتا يمكتتن إزالتهتتا متتن‬ ‫الهامش اليس )تداخل في أي شء (‬

‫ّ‬ ‫تضمينه والنتقال إلى السطر التالي من قبل الشغل.‬ ‫َِ‬

‫التحكم في تلقيم التنفيذ‬ ‫مهم‬ ‫استخدام المسافات في بعض الحيان، وفي بعض الحيان الخرى مسافات البادئةلتعريف أسطر نفــس الكتلــة.‬ ‫وحتى لو تبدو مطابقة على الشاشــة، فالمســافات وعلمــات التبـويت هـي رمـوز ثنائيــة منفصـلة : ولـذلك ينظـر‬ ‫بيثون إلى هـذه السـطر علـى أنهـا جـزء مـن كتـل مختلفـة. والـذي قـد يـؤدي إلـى أخطـاء يصـعب تصـحيحها.‬ ‫فمن الفضل تفعيل خيار "استبدال علمات التبويت بمسافات" .‬ ‫يمكنك أيضا وضع مســافة البادئـة مـن خلل علمـات التبـويت، ولكـن يجـب أن تكـون بعـد ذلـك حـذرا جـدا بعـدم‬

‫62‬

‫ولــذلك يفضــل معظــم المــبرمجين اســتخدام علمــات التبــويت. إذا كنــت تســتخدم محــرر نصــوص "ذكــي"،‬

‫المسافات والتعليقات عادة ما يتم تجاهلها‬ ‫بصف النظر عن تلك الستخدم لسافة البادئة )في بداية السطر(، الساحات الوضتتوعة داختتل التعليمتتات والتعتتبيات دائمتتا متتا‬ ‫يتم تجاهلها )ما لم تكن جزء من سلسلة نصية(. وهذا نفس الشء بالنسبة للتعليقات: فهي تبدأ برمز # وتمتد إلى نهاية السطر‬ ‫الحالي )يتم تجاهلها(.‬

‫4‬
‫4تعليمات التكرار‬
‫من الهام الت تبذل فيه اللت قصارى جهدها هي تكرار الهتام التماثلتتة متن دون خطتتأ. هنالتتك العديتد متن الطترق لبمجتتة هتتذه‬ ‫الهام التكررة. سنبدأ مع واحدة تعتب الكث أساسية وهي حلقة تكرار ‪.while‬‬

‫إعادة التعيين‬ ‫حت الن لم نخب،ك بأنه يجوز إعادة تعيي قيمة جديدة لتغي واحد، مرة واحدة أو عدة مرات على النحو الطلوب.‬ ‫عندما نقوم بإعادة تعيي، نحن نقوم باستبدال القيمة القديمة بقيمة جديدة لنفس التغي .‬
‫>>>‬ ‫>>>‬ ‫023‬ ‫>>>‬ ‫>>>‬ ‫573‬ ‫023 = ‪altitude‬‬ ‫)‪print(altitude‬‬ ‫573 = ‪altitude‬‬ ‫)‪print(altitude‬‬

‫هذا يجعلنا نلفت انتباهكم مرة أخرى إلى أنه يجب علينا أن ل نخلط بي رمز التعييتت فتتي بيلثتون ورمتز الستاواة كمتا يفهتم فتي‬ ‫الرياضيات ، لن هنالك العديد من العشخاص يفسون هذه العبتارة 023 = ‪ altitude‬كتأن هتتذا الرمتتز للمستتاواة، وهتي‬ ‫ليست كذلك!‬ ‫• أول الساواة هي عملية تبادلية، في حي أن التعيي ليس كذلك فملثل في الرياضيات كتابة 7 = ‪ a‬أو 7 = ‪ a‬نفتس‬ ‫الشء في حي أن في البمجة )على سبيل اللثال 573 = ‪ ( altitude‬سيكون غي منطقي.‬ ‫• ثانيا، الساواة تكون دائمة، في حي يمكتتن استتتبدال قيمتتة التغيتت فتتي بيلثتتون باستتتخدام رمتتز التعييتت كمتتا رأينتتا للتتتو. فتتي‬ ‫الرياضيات نلؤكد أن هذه مساواة أ = ب في بداية البهان، ثم نواصل لتكون مساوية لت ب في جميع التطورات القادمة .‬ ‫في البمجة، عبارة التعيي الولى هي معادلة قيمتين، والعبارة الخرى لستبدال قيمة الولى، على سبيل اللثال:‬

‫تعليمات التكرار‬
‫5 = ‪>>> a‬‬ ‫‪>>> b = a‬‬ ‫2 = ‪>>> b‬‬ ‫‪ b‬و ‪ a‬لديهم نفس القيمة #‬ ‫‪ b‬و ‪ a‬أصبحوا مختلفان اﻵن #‬

‫82‬

‫تذكروا أن بيلثون تسمح لك بتعيي عدة قيم متغيات في نفس الوقت :‬
‫7 ,5 ,4 ,3 = ‪>>> a, b, c, d‬‬

‫هذه مية من ميات بيلثون الكث إثارة للهتمام عند النظرة الولى.‬ ‫على سبيل اللثال، لنفتض أننا صنعنا التغيين ‪ a‬و ‪ c‬وهما يحتويان على القيمتي 3 و 5 نريتتد عكتتس القيمتتتي( كيتتف نفعتتل‬ ‫هذا؟‬

‫اكتب الكود اللزم لتحقيق هذه النتيجة )فوق(.‬ ‫هذه هي عملية مشتكة، إن لغات البمجة غالبا ما تقدم اختصتارات لداء )التعليمتات التخصصتتة علتى ستبيل اللثتال،‬ ‫ملثل تعليمة البادلة الساسية( في بيلثون، يمكن تعيي مساوي في البمجة التبادل بشكل أنيق وخاص:‬
‫‪>>> a, b = b, a‬‬

‫تمرين‬
‫4. 1‬

‫بعد القيام بالعملية القتحة أعله، سوف تجد بالتأكيد وسيلة، وسيطلب منك العلتتم علتتى الرجتتح التعليتتق فتتي الصتتف. لن‬

‫)ويمكن بالطبع عكس متغيات أكث )ملثل ثلثة( في نفس الوقت بنفس التعليمة(‬

‫حلقات التكرار – العبارة ‪while‬‬
‫في البمجة، نسمي حلقتتة التكترار بنظتام التعليمتتة التذي يكترر الهمتتة الحتددة عتدة متترات )أو بشتتكل ل نهتتائي( جميتتع العمليتتات‬ ‫.بيلثتتون يقتتتح عبتتارتي لستتتعمال الحلقتتات: العبتتارة ‪ … for … in‬قويتتة جتتدا وستتوف ندرستتها فتتي الفصتتل العاشتت والبيتتان‬ ‫‪ while‬الذي سندرسه الن.‬ ‫الرجاء ادخال الوامر التالية:‬
‫0 = ‪>>> a‬‬ ‫:)7 < ‪>>> while (a‬‬ ‫...‬ ‫1 + ‪a = a‬‬ ‫...‬ ‫)‪print(a‬‬ ‫)ل تنس النقطين !( #‬ ‫َ‬ ‫)ل تنس مسافة البادئة !( #‬ ‫َ‬

‫اضغط مرة أخرى على ‪.Enter‬‬ ‫ماذا حدث؟‬ ‫قبل قراءة التعليقات التالية، خذ وقتا لفتح دفت اللحظات ودون هذه السلستتلة متن الوامتتر. وصتف أيضتا نتيجتتة ذلتك وحتاول‬ ‫تفس كيف حدث هذا بأكب قدر ممكن من التفصيل.‬

‫92‬

‫ظحلقات التكرار – العبارة ‪while‬‬ ‫التعليقات‬

‫تعن كلمة ‪ while‬بالنكليية "عندما ". هذه العبارة الستخدمة في السطر اللثاني تخب بيلثون بأنه يجتتب عليتته تكتترار الكتلتتة‬ ‫التالية من البيانات باستمرار، عندما يكون التغي ‪ a‬أقل من 7.‬ ‫ملثل عبارات ‪ if‬والت ناقشناها في الفصل السابق، في حي تبتتدأ العبتتارة ‪ while‬بعبتتارة الجمتتع. النقتطيتت العتتاموديتي فتتي‬ ‫نهاية السطر تخب بيلثون أنه سيبدأ بدخول مجمع يجب تكراره والذي يجب أن يبدأ بمسافة. كما تعلمت في الفصل السابق يجب‬ ‫أن تكون بادئة جميع البيانات داخل الكتلة متساوية بالضبط في نفس الستوى )وهذا يعن البدء بالعدد نفسه من السافات(.‬ ‫لقد قمنا ببناء حلقتنا الولى، الت تكرر كتلة البادئة للبيانات عدة مرات، ولكن كيف تعمل:‬ ‫•مع العبتتارة ‪،while‬تت يبتتدأ بيلثتتون بالتأكتتد متن الشتت ط الوضتتوع داختتل القوستتي )القوستتي اختيتتاري ونحتتن استتتخدمناها‬ ‫للتوضيح فقط(.‬ ‫•إذا كان الش ط غي صحيح، يتم تجاهل الكتلة كلها ويتم إنهاء البنامج .‬
‫6‬

‫• إذا كان الش ط صحيحا، يقوم بيلثون بتنفيذ كتلة البايانات والت تشكل هيئة حلقة وهذا معناه:‬ ‫–التعليمة 1 + ‪ a = a‬معناها زيادة واحد إلى قيمة التغي )وهذا معناه إعادة تعيي قيمتتة لتغيتت بقيمتتته القديمتتة‬ ‫زائد واحد(.‬ ‫–استدعاء دالة الطباعة ‪ ()print‬لظهار قيمة الحالية للمتغي ‪.a‬‬ ‫• وعند تنفيذ هاتي التعليمتي يتم الرجوع مرة أخرى إلتتى عبتتارة التكتترار، وهتذا معنتتاه الرجتتوع إلتتى عبتتارة التكتترار وإجتتراء‬ ‫الش ط إذا كان صحيحا يكمل وإذا كان غي صحيح يخرج.‬ ‫في ملثالنا هذا، إذا كان الش ط 7 < ‪ a‬ليزال صحيحا، سيتم تنفيذ الحلقة مرات أخرى وتستمر الحلقة.‬ ‫ملحظات‬ ‫•يجب أن يكون التغي الذي يتم اختباره موجو دا بالفعتتل )أي أنتته يجتتب صتتنع التغيتت ويجتتب أن يكتتون يحتتتوي علتتى قيمتتة‬ ‫ً‬ ‫ملثل: 1(‬ ‫• إذا كان الش ط غي صحيح من البداية، لن يتم تنفيذ ما داخل الحلقة أبدا )الكتلة(‬ ‫• إذا كان الش ط صحيحا دائما، يتم تكرار الحلقة إلى مال نهاية )عندما تكون بيلثون يعمل( .لذا يجب علينا أن نضع في‬ ‫الكتلة حلقة واحدة على القل تغي قيمة التغي الذي يلؤثر على الحلقة في الوقت الناسب )حت يصبح هذا الش ط غي‬
‫6 على القل ف هذا الاث ال. سوف نرى فيوم ا بعد أن الةتنفيذ يسةتومر مع أول تعليومة تلي كةتلة الب ادئة, والت هي جزء من نفس كةتلة‬ ‫العب ارة ‪ while‬نفسه ا .‬

‫تعليمات التكرار‬ ‫صحيح وتنتهي الحلقة(.‬ ‫ملثال على الحلقة اللنهائية )تجنبها !(:‬
‫3 = ‪>>> n‬‬ ‫:5 < ‪>>> while n‬‬ ‫...‬ ‫)"! ‪print("hello‬‬

‫03‬

‫تطوير الجداول‬ ‫أعد كتابة التمرين الول مع تغيي طفيف أدناه:‬
‫0 = ‪>>> a‬‬ ‫:21 < ‪>>> while a‬‬ ‫...‬ ‫1+ ‪a = a‬‬ ‫...‬ ‫)3**‪print(a , a**2 , a‬‬

‫يجب عليك أن تحصل على قائمة من الربعات والكعبات من 1 إلى 21.‬ ‫اعلم أنك تستطيع أن تمرر أكث من برامت في دالة الطباعة ‪ ()print‬لظهار عدة تعبيات في نفس الوقت واحدة تلو الخرى‬ ‫على نفس الخط: فقط ضع فاصل بي كل واحدة وأخرى. بيلثون سيضع مسافة بي العناص العروضة.‬

‫البناء الرياضي‬ ‫البنامج الصغي الذي بالسفل يعرض أول عشة أرقام من تسلسل يسمى بت "تسلسل فيبواناتش". هذه سلسلة من الرقام كل‬ ‫رقم من هذه السلسلة يساوي مجمتتوع رقميتت ستابقي متن نفتس السلستتلة. جترب تحليتتل هتذا البنامتج )التذي يستتتخدم التعييتت‬ ‫الوازي( وصف أكب قدر ممكن دور كل سطر من التعليمات.‬
‫1 ,1 ,1 = ‪>>> a, b, c‬‬ ‫: 11 < ‪>>> while c‬‬ ‫...‬ ‫)" "= ‪print(b, end‬‬ ‫...‬ ‫1+‪a, b, c = b, a+b, c‬‬

‫عندما تشغل البنامج ستحصل على ما يلي:‬
‫98 55 43 12 31 8 5 3 2 1‬

‫يتتتم عتترض تسلستتل فيبوناتشتت علتتى نفتتس الستتطر. هتتذا متتا ستتنفهمه حتتت البتتارامت اللثتتاني ‪" "= end‬التتت بهتتا دالتتة الطباعتتة.‬ ‫افتاضيا، دالة الطباعة ‪ ()print‬تقوم بإضافة رمز خاص ل يظهر ليقوم بالقفز إلى السطر التالي عندما نقوم بعرض شء ما.‬ ‫والبارامت ‪ " "= end‬يخب بيلثون أن يستبدل القفزة بمسافة صغية. إذا حذفت هذا البارامت، سيتم عرض الرقتتام واحتتدا تحتتت‬ ‫الخر.‬

‫13‬

‫ظحلقات التكرار – العبارة ‪while‬‬

‫في برامجك الستقبلية، سوف تضع في برامجك في كلثي من الحيان حلقات تكرارية كما الت حللنها هنا. وسيتبادر إلى ذهنك‬ ‫سلؤال أساس، هل ستتعلم البمجة بإتقان. تأكد أنك ستصل إلى ذلك تدريجيا، بفضل التمارين.‬ ‫عندما تختب مشكلة من هذا النوع، يجب عليك النظتتر إلتتى أستتطر التعليمتتات، بطبيعتتة الحتتال، لكتن انظتتر خاصتتة فتتي التغيتتات‬ ‫الختلفة الشاركة في الحلقة. هذا ليس سهل دائما، على العكتتس ذلتك لستاعدتك علتى النظتر بوضتتوح، بتدون تكبتد مشتقة رستم‬ ‫جدول على الورق وضعنا في السفل جدول يشح برنامجنا "سلسلة فيبوناتش":‬
‫التغيات‬ ‫القيم الولية‬ ‫القيم الت تعيينها خلل‬ ‫التكرارات‬ ‫‪a‬‬ ‫1‬ ‫1‬ ‫2‬ ‫3‬ ‫5‬ ‫...‬ ‫عبارة الستبدال‬ ‫‪b‬‬ ‫‪b‬‬ ‫1‬ ‫2‬ ‫3‬ ‫5‬ ‫8‬ ‫...‬ ‫‪a+b‬‬ ‫‪c‬‬ ‫1‬ ‫2‬ ‫3‬ ‫4‬ ‫5‬ ‫...‬ ‫1+‪c‬‬

‫في هذا الجدول، الذي صنعناه إلى حد ما "بأيدينا"، مشيا سطرا بسطر التغيات الت تأخذ كل واحدة متن هتذه التغيتات كمتتا‬ ‫في التكرارات القادمة. سنبدأ بال كتابة في أعلى الجدول أسماء التغيات العنية. في السطر التالي، القيم البدئية لهذه التغيتتات‬ ‫)القيم قبل بداية الحلقة(. أخيا في الجزء السفلي من الجدول، نضع التعبيات الستخدمة داختل الحلقتتة لتغيتت قيمتتة كتل متغيتت‬ ‫في كل تكرار.‬ ‫امل بضعة السطر القابلة للتكرار الول. لصنع متغي لسطر، فقط طبق ما فعناه في السطر السابقة، والتعبي عتتن الستتتبدال‬ ‫موجود أسفل كل عمود. افحص واحصل على نتيجة البحث. إذا لم تكن في هذه الحالة جيدة، يجب عليك البحث عن تعبي آخر.‬

‫تمارين‬
‫اكتب برنامجا يعرض أول 02 نتيجة لعملية الضب في 7.‬ ‫اكتب برنامجا لعرض جدول لتحويل اليورو إلى التتدولر الكنتتدي، تبتتدأ بالزيتتادة إلتتى الجتتدول ستتتكون "هندستتية"، ملثتتل‬ ‫التالي:‬ ‫1 يورو = 56.1 دولر‬ ‫2 يورو = 03.3 دولر‬ ‫4. 2‬ ‫4. 3‬

‫تعليمات التكرار‬ ‫4 يورو = 06.6 دولر‬ ‫8 يورو = 02.31 دولر‬

‫23‬

‫إلخ. )توقف عند 48361 يورو.(‬ ‫اكتب برنامجا يعرض 21 رقما كل واحد من هذه الرقام يساوي 3 مرات الرقم الذي قبله.‬ ‫4. 4‬

‫سكريبتك اللول، ألو كيفية حفظ برامجنا‬ ‫حت الن، نحن نستخدم بيلثون في وضع تبادلي )وهذا معناه أنه كل مرة أدخلت الوامر لم يتم حفظها(. وهذا يسمح لك بتعلتتم‬ ‫أساسيات اللغة بسعة، من خلل التجارب مباشة هذه الطريقة لديها عيب واحد كبي : كل التعليمات التتت تكتبهتتا تختفتتي عنتتد‬ ‫إغلق الفس. قبل مواصلة دراستك، حان الوقت لتعلم كيفية حفظ برامجك في ملفات على القرص الصلب أو مفتاح يو أس بي‬ ‫)‪ ، (USB‬بطريقة تستطيع بها إعادة عمل الراحل ، ونقلها على حواسيب أخرى ، ...إلخ‬ ‫للقيتتام بتتذلك، ستتوف تكتتتب الن التعليمتتات الخاصتتة بتتك علتتى أي محتترر )ملثتتل ‪ Kate‬و ‪ Geany‬و ‪... Gedit‬فتتي لينكتتس و‬ ‫‪ wordpad‬و ‪ Komodo‬و ‪... Geany‬علتتى وينتدوز، أو اكتتتب فتتي واجهتة التطتتوير الرستتومية ‪ IDLE‬التت تتتوزع متتع بيلثتتون فتتي‬ ‫ويندوز(‬ ‫و هكذا تكتب السكريبت، وثم تستطيع حفظه وتغيه ونقله وإلخ … ملثل أي مستند آخر مكتوب بالحاسوب.‬ ‫بعدها، عندما ترغب في اختبار تنفيذ البنامج الخاص بك ، يجتب عليتك فتتح مفست بيلثتون واكتتب )اكتتب كتأنه بتارامت( استم‬ ‫اللف الذي يحتوي على السكريبت. على سبيل اللثال، إذا كتبت السكريبت داخل ملف يدعى "'‪ ،"MyScript‬يكفتتي أن تكتتتب هتتذا‬ ‫المر ليشتغل :‬
‫‪python3 MonScript‬‬
‫7‬

‫من الفضل أن تتأكد من أن اسم ملف البنامج ينتهي بت .‪py‬‬
‫إذا اتبعت هذه النصيحة ، يمكنك تشغيل اللف النص لبنامج ، وذلك ببساطة عن طريق النقتتر علتتى استتمه أو رمتتزه فتتي متتدير‬ ‫اللفات)و هو ‪ Explorer‬في ويندوز، أو ‪ Nautilus‬أو ‪ Konqueror‬على لينكس …(‬ ‫مديرو اللفات هلؤلء يعرفون أنهم يفتحون بيلثون مع أي ملف ينتهي بت .‪) py‬و هذا بالطبع يجب أن يكون قد تتتم تكوينهتتا بشتتكل‬ ‫صحيح(. نفس الشء مع الحررات "الذكية" الت تعرف تلقائيا سكريبتات بيلثون وتتكيف مع بناء التعليمات.‬ ‫الشكل التالي يوضح استخدام محرر ‪ Gedit‬على لينكس "أبنتو" لكتابة السكريبت :‬
‫7إذا ت تاثبيت بياثون 3 على جه ازك كومفسر بياثون افةتراضي, يب أن تكون ق ادرا على أن تكةتب ببس اطة : ‪.python MonScript‬‬ ‫لكن انةتبه : إذا ك انت هن الك إصدارات مةتعددة من بياثون ماثبةتة على جه ازك, رب ا سيةتم اسةتخدام إصدار س ابق من بياثون )الصدار 2(‬ ‫.‬

‫33‬

‫سكريبتك الول، أو كيفية ظحفظ يبرامجنا‬

‫سكريبت بيلثون يحتوي على سلسلة تعليمات مماثلة لتلك الت اختبناها الن. وسوف تخزنها وبعد مدة سوف تشغلها وتقرأها‬ ‫من قبلك أو من قبل الخرين ، وينصح وبشدة توضيح النصوص الخاصة بك إلى أقص حتد ممكتن ، ويجتب أن تتضتمن الكتلثي‬ ‫من التعليقات ، والصعوبة الحقيقية في تطوير البامج هي الخوارزميات الصحيحة ، بحيث يمكتن التأكتد متن هتذه الخوارزميتات‬ ‫وتصحيحها وتغييها وما إلى ذلك ، في أفضل ظروف ، ومن الضوري أن يصف البمتج الكلمتتات جيتتدا وبتتأكب قتتدر ممكتتن متن‬ ‫الوضوح .‬ ‫المبرمج الجيد يدخل دائما أكبر عدد من التعاليق في سكريبتاته. وبذلك، ليسهل فهم الخوارزميات للقــراء‬

‫المحتملين الخرين فقط، ولكنه يفرض أن سكريبته يكون أكثر وضوحا .‬ ‫و أفضل مكان لهذا الوصف هو في جسم السكريبت )بحيث ل يضيع(‬

‫يمكننا إدراج تعليقات من أي نوع في أي مكان تقريبتتا فتتي البنامتتج النصتت. ببستتاطة ضتتع قبتتل التعليتتق الرمتتز # حيتتث يعتتتب‬ ‫الفس هذا الرمز هو دللة على تجاهل كل ما يأتي بعد هذا الرمز إلى نهاية السطر.‬ ‫يرجى منك أن تفهم أنه يجب عليك أن تضع التعليقات كلما تقدمت في عملك في البمجة. ل تنتظر حت تنتهتتي متتن الستتكريبت‬ ‫الخاص بك. عليك أن تدر،ك أن البمج ينفق الكلثي من الوقت لقتتراءة التعليمتتات البمجيتتة الخاصتتة بتتك )علتتى ستتبيل التغييتت،‬ ‫والبحث عن الخطاء ، إلخ …( وسيكون هذا سهل إذا وضعت العديد من التعليقات واللحظات والتفسيات.‬ ‫افتح الحرر النص ، واكتب السيناريو التالي :‬
‫.أول اختبار لسكريبت يبيثون #‬ ‫.يبرنامج صغير ويبسيط يعرض تسلسل فيبوناتشي #‬ ‫. كل عدد في هذه السلسلة يساوي مجموع اثنين سايبقين #‬ ‫1 ,1 ,1 = ‪a, b, c‬‬ ‫‪b‬و ‪ a‬لحساب العداد المتتالية #‬

‫تستخدم‬

‫تعليمات التكرار‬
‫‪ c‬هو عداد يبسيط #‬ ‫عرض العدد الول #‬ ‫سوف نعرض 51 عدد #‬

‫43‬

‫)‪print(b‬‬ ‫:51>> a, b, c‬‬ ‫:05< ‪>>> while c‬‬ ‫))‪print(c, ":", b, type(b‬‬ ‫1+‪a, b, c = b, a+b, c‬‬ ‫...‬ ‫...‬ ‫)‪... (affichage des 43 premiers termes‬‬ ‫...‬ ‫>'‪44 : 1134903170 >> phrase1 = 'les oeufs durs‬‬ ‫',‪>>> phrase2 = '"Oui", répondit-il‬‬ ‫"‪>>> phrase3 = "j'aime bien‬‬ ‫)1‪>>> print(phrase2, phrase3, phrase‬‬ ‫.‪"Oui", répondit-il, j'aime bien les oeufs durs‬‬

‫التغيات اللثلثة 2‪ phrase1، phrase‬و 3‪ phrase‬متغيات من نوع سلسلة .‬ ‫لحظ استخدام علمات القتباس لتحديد السلسلة الت توجد فيها علمة تنصيص مفردة، أو استخدم علمتتة القتبتتاس الفتتردة ،‬ ‫لحظ أيضا مرة أخرى أن دالة الطباعة تدرج مسافة بي العناص العروضة .‬ ‫الرمز الخاص "\” )الخط الائل( يسمح ببعض الميات الضافية :‬
‫11‬ ‫و لذلك فإن ا واحدة من الوميزات الرئيسية للصدار الديد لبياثون )بياثون 3( مق ارنة ب الصدارات الس ابقة. وف هذه النسخة,‬ ‫البي ان ات من نوع ‪ string‬ك انت سلسلة من الب ايةت ات وليس سلسلة من الروف. وهذا ل يرشكل مرشكلة كبية ف الةتع امل مع النصوص‬ ‫الت تةتوي فقط على الروف الرئيسية للغ ات أروب ا الغربية, لنه ك ان من الومكن ترميز كل هذه الحرف ف ب ايت واحد )على سبيل‬ ‫الاث ال, معي ار 1-‪ .( Latin‬وهذا أدى إل صعوبة كبية إذا أردن ا جيع الحرف ف نص واحد من الروف الجبدية الخةتلفة, أو‬ ‫ببس اطة اسةتخدام الروف الجبدية الت تةتوي على أكاثر من 652 من الروف والرموز الري اضية ال اصة ...إل. يكنك العاثور‬ ‫على الزيد من العلوم ات حول هذا الوضوع ف الفصل 01 .‬

‫34‬

‫المعطيات اليبجدية‬

‫• أول، لنها تتيح لك كتابة أسطر متعددة الت من عشأنها أن تأخذ وقتا طويل لحتواها على سطر واحد)هذا ينطبق على أي‬ ‫نوع من التعليمات(‬ ‫• ضمن السلسة يتم استخدامها لدخال عدد من الرموز الخاصة)سطر جديد، علمة تنصيص مفردة، علمات القتبتتاس، إلتتخ‬ ‫…( أملثلة على ذلك :‬
‫'.‪>>> txt3 = '"N\'est-ce pas ?" répondit-elle‬‬ ‫)3‪>>> print(txt‬‬ ‫.‪"N'est-ce pas ?" répondit-elle‬‬ ‫\ ‪>>> Salut = "Ceci est une chaîne plutôt longue\n contenant plusieurs lignes‬‬ ‫\‪... de texte (Ceci fonctionne\n de la même façon en C/C++.\n‬‬ ‫...‬ ‫"‪Notez que les blancs en début\n de ligne sont significatifs.\n‬‬ ‫)‪>>> print(Salut‬‬ ‫‪Ceci est une chaîne plutôt longue‬‬ ‫‪contenant plusieurs lignes de texte (Ceci fonctionne‬‬ ‫.++‪de la même façon en C/C‬‬ ‫‪Notez que les blancs en début‬‬ ‫.‪de ligne sont significatifs‬‬

‫ملحظات‬ ‫•إن الرمز \‪ n‬في السلسة معناه القفز إلى سطر جديد.‬ ‫•إن الرمز \' لدراج علمة تنصيص مفردة في سلسلة محددة بواسطة علمة تنصيص مفردة ونفتتس الشتتء متتع \" لدختتال‬ ‫علمات القتباس في سلسلة محددة بواسطة علمات القتباس .‬ ‫• تذكر قواعد أسماء التغيات ) يجب أن نحدد بدقة حالة الحرف كبية أو صغية (‬ ‫االقتباس الثليثي‬ ‫لدراج أحتترف خاصتتة أو غريبتتة بستتهولة فتتي السلستتلة دون استتتخدام رمتتز الختتط الائتتل أو باستتتعمال رمتتز الائتتل نفستته فتتي‬ ‫السلسلة ، يمكن للمرء استعمال سلسلة بعلمة اقتباس ثلثية أو علمات التنصيص الفردة اللثلثية :‬
‫""" = 1‪>>> a‬‬ ‫...‬ ‫‪Exemple de texte préformaté, c'est-à-dire‬‬ ‫...‬ ‫‪dont les indentations et les‬‬ ‫...‬ ‫‪caractères spéciaux \ ' " sont‬‬ ‫‪... conservés sans‬‬ ‫...‬ ‫""".‪autre forme de procès‬‬ ‫)1‪>>> print(a‬‬ ‫‪Exemple de texte préformaté, c'est-à-dire‬‬ ‫‪dont les indentations et les‬‬ ‫‪caractères spéciaux \ ' " sont‬‬ ‫‪conservés sans‬‬ ‫.‪autre forme de procès‬‬ ‫>>>‬

‫أهم أنواع البيانات‬

‫44‬ ‫الوصول إلى الحرف الفردية في السلسلة‬

‫منه أكث بساطة في حالة وجود سلسلة ، على سبيل اللثال، وهذه متن الواضتح أنتته أبستط متن الحتتروف نفستتها. تبعتا للظتتروف‬ ‫نحن نرغب بمعالجة السلسلة، وأحيانا الكائن الواحد ، وأحيانتتا مجموعتتة أحتترف. لغتتة البمجتتة بيلثتتون تستتمح بالوصتتول بشتتكل‬

‫السلسل تملثل حالة خاصة من أنواع البيانات الكث عمومية تدعى مركب. الركب العيتت هتتو التتذي يجمتتع فتتي واحتتدة مجموعتتة‬ ‫ُ‬

‫منفصل إلى كل من الحرف في السلسة، كما ستى، وهذه ليست معقدة للغاية .‬ ‫بيلثون تفتض أن السلسلة هي كائن من فئة السلسل، وهي الت طلبت مجموعات من العناص. وهذا معناه ببستتاطة أن أحتترف‬ ‫السلسلة ترتب دائما في ترتيب معي. ولذلك ، يمكن لكل حرف في السلسلة أن يكون له تسمية فتتي مكتتانه فتتي السلستتلة، وذلتتك‬ ‫باستخدام اللؤش .‬ ‫للوصول إلى حرف محدد، يجب علينا وضتع استم التغيتت التذي يحتتتوي علتتى السلستتلة ونضتتع رقتم اللؤشتت )و هتتو رقتم موضتتع‬ ‫الحرف في السلسلة( داخل معقوفي .‬ ‫انتبه : سوف يكون لديك فرصة للتحقق )لحقا( من أن العداد الرقمتتة تبتتدأ دائمتتا متتن الصتتفر )و ليتتس واحتتد(. وهتتذا هتتو الحتتال‬ ‫بالنسبة لحروف السلسلة .‬ ‫على سبيل اللثال :‬
‫"‪>>> ch = "Christine‬‬ ‫)]5[‪>>> print(ch[0], ch[3], ch‬‬ ‫‪C i t‬‬

‫تستطيع إعادة التمرين في العلى ، وهذه الرة استخدم حرفا أو حرفي غي أكس ‪ .non-ASCII‬علتتى عكتتس متتا قتتد يحتتدث فتتي‬ ‫بعض الحالت مع إصدارات بيلثون قبل الصدار 0.3، تحصل هنالك مفاجئة في النتيجة التوقعة :‬
‫"‪>>> ch ="Noël en Décembre‬‬ ‫)]21[‪>>> print(ch[1],ch[2],ch[3],ch[4],ch[8],ch[9],ch[10],ch[11],ch‬‬ ‫‪o ë l‬‬ ‫‪D é c e m‬‬

‫ل داعي للقلق في الوقت الحالي حول كيفية قيام بيلثون بالتخزين والتعامل مع الحرف في ذاكرة الحاسوب. فقتط اعلتم أن هتذه‬ ‫التقنية تستغل العايي الدولية يونيكود. فيستطيع تميي أي حرف من الحروف البجدية. لذلك يمكنك في نفس السلستتلة خلتط‬ ‫اللتينية واليونانية والسييلية والعربية ..إلخ والرموز الرياضية و إلخ …‬ ‫سوف نـرى فـي الفصـل 01 )انظـر للصـفحة 921( كيفيـة عـرض الحـرف غيـر الـتي يمكـن الوصـول إليهـا‬ ‫مباشرة من لوحة المفاتيح .‬

‫54‬

‫المعطيات اليبجدية‬ ‫العمليات اللسالسية على السللسل‬

‫بيلثون يحتوي على العديد من الدالت الت تلؤدي إلى تعاملت مختلفة على سلسل )الحتترف الكتتبية \ الصتغية، قطتتع أجتتزاء‬ ‫من السلسلة والبحث عن كلمات … إلخ (. مرة أخرى يجب أن تصبوا لنه سيتم وضع شح هذه الدالت في الفصل 01 )انظتتر‬ ‫الصفحة 921(.‬ ‫الن ، يمكننا أن نعرف ببساطة أنه يمكن الوصتتول إلتى كتل حترف فتتي السلستتلة، كمتتا هتتو موضتتح فتتي الفقترة الستتابقة ، دعونتتا‬ ‫نضيف قليل على ما سبق :‬ ‫• نجمع العديد من السلسل الصغية لبناء واحدة كبية. هذا ما يسمى التسلسل وهذا يتحقق في بيلثتتون باستتتخدام الرمتتز +‬ ‫)هذا الرمز معناه إضافة سلسلة لسلسلة أخرى كما في الرياضيات وهذا يعمل في السلسلة النصية ( ملثال :‬
‫'‪a = 'Petit poisson‬‬ ‫'‪b = ' deviendra grand‬‬ ‫‪c = a + b‬‬ ‫)‪print(c‬‬ ‫‪petit poisson deviendra grand‬‬

‫•تحديد طول السلسة )أي عدد الحرف ( وذلك باستخدام ‪: ()len‬‬
‫'‪>>> ch ='Georges‬‬ ‫))‪>>> print(len(ch‬‬ ‫7‬

‫هذه الدالة تعمل بشكل جيد حت لو كانت السلسلة تحتوي على أحرف أخرى :‬
‫'‪>>> ch ='René‬‬ ‫))‪>>> print(len(ch‬‬ ‫4‬

‫•تحويل رقم يملثل سلسلة نصية إلى عدد رقمي ، على سبيل اللثال :‬
‫'7468' = ‪>>> ch‬‬ ‫)54 + ‪>>> print(ch‬‬ ‫)‪>>> n = int(ch‬‬ ‫)56 + ‪>>> print(n‬‬ ‫2178‬
‫#‬

‫خطأ *** : ل يمكن إضافة سلسلة إلى رقم *** →‬
‫نعم : يمكننا إضافة رقم إلى رقم آخر‬ ‫حقيقي، وذلك باستخدام ‪.()float‬‬ ‫اكتب سكريبت يحدد إذا كانت السلسلة تحتوي على حرف "‪ "a‬أو ل .‬

‫في هذا اللثال، دالة ‪ ()int‬تحول السلسلة إلى عدد صحيح. سيكون ذلك من المكن أيضا تحويل سلستتلة أحتترف إلتتى عتتدد‬

‫تمارين‬
‫5. 6‬ ‫5. 7‬

‫اكتب سكريبت يحسب عدد تواجد الحرف "‪ "a‬في السلسلة .‬

‫أهم أنواع البيانات‬ ‫اكتب سكريبت يقوم بنسخ سلسلة )في متغي جديد( وإدراج نجمة بي الحرف.‬ ‫على سبيل اللثال ، "‪ "gaston‬تصبح "‪"g*a*s*t*o*n‬‬ ‫اكتب سكريبت يقوم بنسخ السلسلة )في متغي جديد( في اإتجاه العاكس.‬ ‫على سبيا اللثال : "‪ "Hisham‬تصبح "‪."mahsih‬‬

‫64‬ ‫5. 8‬ ‫5. 9‬

‫5.01 استنادا إلى التمارين السابقة ، اكتب سكريبت يحدد إذا كانت السلسلة تعطي سياق متناظر أو ل )أي أن سلسلة يمكن‬ ‫قراءتها من التجاهي( ، ملثل "‪ "Radar‬أو "‪. "SOS‬‬ ‫القوائم )النهج اللول(‬ ‫قدمت السلسل الت ناقشناها في الجزء السابق ملثال أولي من البيانات الركبة. هياكل البيانات الت تستتتخدم لتجميتتع مجموعتتة‬ ‫من القيم. وسوف تتعلم تدريجيا طريقة استخدام غيها من مركبات عدة أنواع من البيانتات. بمتا فتي ذلتك ، القتوائم والقتواميس‬ ‫والصفوفة الغلقة . و سوف نناقش هنا أول هذه النواع اللثلثة، وهذا وهذا مختصتت إلتى حتد متا. لكنتته بالفعتتل موضتتوع واستع‬
‫21‬

‫جدا، وسنعود إليه مرارا وتكرارا .‬ ‫في بيلثون، يمكننا تحديد قائمة من العناص مفصولة بفواصل موضوعة كلها داخل نصفي مربع ، على سبيل اللثال :‬
‫]'‪>>> jour = ['lundi', 'mardi', 'mercredi', 1800, 20.357, 'jeudi', 'vendredi‬‬ ‫)‪>>> print(jour‬‬ ‫]'‪['lundi', 'mardi', 'mercredi', 1800, 20.357, 'jeudi', 'vendredi‬‬

‫في هذا اللثال، التغي ‪ jour‬هو قائمة.‬ ‫كما يمكن أن نرى في نفس اللثال، فإن العناص الفردية الت تشكل القائمة قد تكون من أنواع مختلفة. في هذا اللثال، في الواقع،‬ ‫أول ثلثة عناص من السلسلة هي حروف والعنص الرابع هو عدد صحيح والخامس هو عدد حقيقي وما إلى ذلك. )سنناقشها‬ ‫لحقا ، يمكن للقائمة أن يكتتون أحتتد عناصتتها قائمتتة !( فتتي هتتذا الشتتأن ، القائمتتة قتتد تكتتون "”مصتتفوفة" )‪ (array‬أو " متغيتت‬ ‫إنديسا" حسب لغة البمجة .‬ ‫لحظ أيضا ، انه كما في السلسل ، فإن القوائم هي سلسلة وهذا يعن أنها مرتبة. مختلف العناص الت تشكل القائمة هتتي فتتي‬ ‫الواقع دائما أعدت في نفس التتيب. ويمكن الوصول إلى كل واحدة منها على حدة إذا كنا نعرف ملؤشها في القائمة. كمتتا كتتان‬ ‫حال الحرف في السلسلة ، يجب أن نعرف أن التقيم يبدأ من الصفر وليس واحد .‬

‫أمثلة :‬
‫]'‪>>> jour = ['lundi', 'mardi', 'mercredi', 1800, 20.357, 'jeudi', 'vendredi‬‬ ‫)]2[‪>>> print(jour‬‬ ‫‪mercredi‬‬

‫21 يكنك إنرش اء أنواع من البي ان ات الركبة بنفسك, عندم ا تةتحكم ف مفهوم الصنف )انظر إل صفحة 571(.‬

‫74‬
‫)]4[‪>>> print(jour‬‬ ‫753.02‬

‫القوائم )النهج الول(‬

‫على عكس السلسل ، والت هي نوع من البيانات غي قابلة للتعديل )سيكون لدينا العديد من الفرص للعودة إليها مرة أختترى (‬ ‫، فإنه من المكن تغيي العناص الفردية للقائمة :‬
‫)‪>>> print(jour‬‬ ‫]'‪['lundi', 'mardi', 'mercredi', 1800, 20.357, 'jeudi', 'vendredi‬‬ ‫74+ ]3[‪>>> jour[3] = jour‬‬ ‫)‪>>> print(jour‬‬ ‫]'‪['lundi', 'mardi', 'mercredi', 1847, 20.357, 'jeudi', 'vendredi‬‬

‫يمكننا استبدال بعض عناص القائمة بأخرى ، كما هو مبي أدناه :‬
‫'‪>>> jour[3] = 'Juillet‬‬ ‫)‪>>> print(jour‬‬ ‫]'‪['lundi', 'mardi', 'mercredi', 'Juillet', 20.357, 'jeudi', 'vendredi‬‬

‫دالتة ‪،()len‬ت التت استتعملناها بالفعتل فتي السلستل ، ينطبتق نفتس مفهومهتا علتى القتوائم ، لكتن تقتوم بإظهتتار عتدد العناصتت‬ ‫الوجودة في القائمة :‬
‫))‪>>> print(len(jour‬‬ ‫7‬

‫:‬

‫31‬

‫دالة أخرى تقوم بحذف عنص من القائمة )باستخدام اللؤش(. وهذه الدالة هي ‪()del‬‬

‫)]4[‪>>> del(jour‬‬ ‫)‪>>> print(jour‬‬ ‫]'‪['lundi', 'mardi', 'mercredi', 'juillet', 'jeudi', 'vendredi‬‬

‫و من المكن إضافة عنص إلى القائمة، ولكن للقيام بذلك، يجب علينا أن نعتتتب القائمتتة كتتائن، وستتوف نستتتخدم إحتتدى الطتترق،‬ ‫سيتم شح مفاهيم الحاسوب للكائن والساليب في وقت لحق ، ولكن ما يهمنا الن "كيف تعمل" في القائمة :‬
‫)'‪>>> jour.append('samedi‬‬ ‫)‪>>> print(jour‬‬ ‫]'‪['lundi', 'mardi', 'mercredi', 'juillet', 'jeudi', 'vendredi', 'samedi‬‬ ‫>>>‬

‫في السطر الول من اللثال أعله ، قمنا بطريقة ‪ ()append‬لضافة السبت للقائمة ‪ .jour‬لتن ل يعتترف كلمتتة "‪"append‬‬ ‫تعن إضافة في النكليية. ونحن نستطيع أن نفهم أن ‪ ()append‬هو أسلوب يتم بطريقة أو بأخرى دمج أو إضافة عنص‬ ‫إلى القائمة. البامت الذي يستخدم مع هذه الدالة هو بالطبع العنص الذي نريد إضافته إلى نهاية القائمة .‬

‫31 ف الواقع يوجد عدد مةتنوع من الةتقني ات الت تسومح لك بقيطع ق ائومة إل شرائح, وإدراج موموع ات من العن اصر, أو إزالة‬ ‫موموع ات أخرى ...إل. وذلك ب اسةتخدام تكوين جل خ اص يةتضومن الؤشر .‬ ‫و تسومى هذه الجوموعة من الةتقني ات )و الت يكن أيض ا تيطبيقه ا على السلسل( ب الةترشريح. بوضع عدة مؤشرات بدل من الواحد بي‬ ‫قوسي )نصف مربع( ث نضيف اسم الةتغي ؟ ماثل 3:1[‪ [jour‬الذي هو ]’ ‪. [’mardi’, ’mercredi‬‬ ‫و سيةتم شرح ب الةتفصيل هذه الةتقني ات لحق ا )انظر لصفحة 921 وم ا يليه ا(.‬

‫أهم أنواع البيانات‬

‫84‬

‫سوف نرى لحقا مجموعة كبية من هذه الطرق )و هذا معناه دالت بنيت، أو بالحرى "غلفت" في نوع قائمة(. لحظ أنتته يتتتم‬ ‫تطبيق أسلوب الكائن من خلل ربطه مع النقطة. )السم الول للمتغي التذي يشتي للكتائن ، ثتم نقطتة ثتم استم الستلوب، وهتذا‬ ‫يكون دائما برفقة زوج من القواس( .‬ ‫كالسلسل، سيتم التعمق في القوائم في وقت لحق )انظر الصفحة 051(. نحن ل نعرف ما يكفي للبتدء فتتي استتخدام برنامجنتا.‬ ‫يرجى قراءة اللثال. لتحليل السكريبت الصغي أدناه والتعليق على كيفية عمل ذلك :‬
‫]'‪jour = ['dimanche','lundi','mardi','mercredi','jeudi','vendredi','samedi‬‬ ‫0 ,0 = ‪a, b‬‬ ‫:52>> print("Bonjour", "à", "tous", sep‬‬ ‫‪Bonjour*à*tous‬‬ ‫)""= ‪>>> print("Bonjour", "à", "tous", sep‬‬ ‫‪Bonjouràtous‬‬

‫و يمكنك استبدال القفز إلى سطر جديد باستخدام البارامت ‪: end‬‬
‫0= ‪>>> n‬‬ ‫:6>> while n‬‬ ‫...‬ ‫)""= ‪print("zut", end‬‬ ‫...‬ ‫1+‪n = n‬‬ ‫...‬ ‫‪zutzutzutzutzut‬‬

‫41 ف بياثون, يسةتخدم مصيطلح "دالة" للش ارة إل الدالت القيقية ويسةتخدم أيض ا للش ارة إل الجراءات. وسوف نرشرح لحق ا‬ ‫الةتومييز بي هذين الفهومي الةترش ابي .‬

‫الدالت المعرفة مسبقا‬

‫25‬

‫التفاعل مع المستخدم : الدالة )(‪input‬‬
‫حاليا معظم مدخلت الستخدم تتم عن طريق )إدخال برامتات، النقر بواسط الفأرة، الضغط على زر في لوحة الفاتيح، إلتخ.(.‬ ‫توقف البنامج لتدعو الستتتخدم لدختتال حتتروف متن لوحتتة الفاتيتح ويجتتب أن ينتهتتي متع الضتتغط علتتى زر الدختتال ) ‪.(Enter‬‬ ‫وعندما يضغط الستخدم زر الدخال تقوم الدالة بأخذ ما كتبه الستخدم ويمكن إسناد قيمة لي متغي بهذه الدالة أو تحويله .‬ ‫يمكن للمبمج استدعاء دالة ‪ ، ()input‬وتر،ك القواس فارغة ويمكنه أيضا أن يضع بارامت به رسالة تفستتيية للمستتتخدم ،‬ ‫على سبيل اللثال :‬
‫)" : ‪prenom = input("Entrez votre prénom‬‬ ‫)‪print("Bonjour,", prenom‬‬

‫في سكريبت الوضع النص )ملثل الت صنعناها حت الن( ، أبسط طريقة هتتي استتتخدام الدالتتة ‪ .()input‬هتتذه الدالتتة تستتبب‬

‫أو :‬
‫)" "=‪print("Veuillez entrer un nombre positif quelconque : ", end‬‬ ‫)(‪ch = input‬‬ ‫)‪nn = int(ch‬‬ ‫تحويل السلسلة إلى عدد صحيح #‬ ‫)2**‪print("Le carré de", nn, "vaut", nn‬‬

‫لحظ أن دالة ‪ ()input‬تقوم دائما بإرجاع سلسلة نصية . فتت إذا كنتتت تريتتد أن يقتوم الستتتخدم بإدختال قيمتتة رقميتتة، ستوف‬
‫51‬

‫تحتاج إلى تحويل قيمة الدخلت )و الت ستكون سلسلة نصية( إلى النوع الرقمي الذي يناسبك، متتن خلل وضتتع دالتتة ‪()int‬‬ ‫)إذا كنت تتوقع عدد صحيح( أو ‪) ()float‬إذا كنت تتوقع عدد حقيقي( .على سبيل اللثال :‬
‫)" : ‪>>> a = input("Entrez une donnée numérique‬‬ ‫73.25 : ‪Entrez une donnée numérique‬‬ ‫)‪>>> type(a‬‬ ‫>'‪>> afficher3fois('zut‬‬ ‫‪zut zut zut‬‬ ‫)]7 ,5[(‪>>> afficher3fois‬‬ ‫]7 ,5[ ]7 ,5[ ]7 ,5[‬ ‫)2**6(‪>>> afficher3fois‬‬ ‫63 63 63‬

‫في هذا اللثال، قد تجد أن الدالة ‪ ()afficher3fois‬تقبل جميع أنواع البامتات الت يتتم تمريرهتا علتى مختلتف أنواعهتتا،‬ ‫وهي رقم، سلسلة نصية، قائمة أو حت تعتتبي. فتتي الحالتتة الخيتتة، بيلثتتون يقتتوم بفحتتص التعتتبي، ويقتتوم بتمريتتر ناتتتج عمليتتة‬ ‫التعبي كبامت للدالة .‬ ‫القيمء الفتراضية للبرامترات‬ ‫في تعريف الدالة، من المكن )و مرغوب في الكلثي من الحيان( تعريف قيمة برامتتت افتاضتتية لكتتل برامتتت. وهتتذا يعطتتي الدالتتة‬ ‫الت نستطيع تسكينها مع مجموعة فقط من البامتات النتظرة. على سبيل اللثال :‬
‫:)'‪>>> def politesse(nom, vedette ='Monsieur‬‬ ‫...‬ ‫)".‪print("Veuillez agréer ,", vedette, nom, ", mes salutations cordiales‬‬ ‫...‬

‫الدالت الصلية‬
‫)'‪>>> politesse('Dupont‬‬ ‫.‪Veuillez agréer , Monsieur Dupont , mes salutations cordiales‬‬ ‫)'‪>>> politesse('Durand', 'Mademoiselle‬‬ ‫.‪Veuillez agréer , Mademoiselle Durand , mes salutations cordiales‬‬

‫08‬

‫عند استدعاء هذه الدالة، القيمة الولى قد وضعناها أما القيمة اللثانيتتة ستتتأخذ القيمتتة الفتاضتتية. وإذا أدخلنتتا قيمتتتي، القيمتتة‬ ‫الفتاضية اللثانية سوف تلغى.‬ ‫يمكن تعيي قيمة افتاضية لكن البامتات، أو جتزء منهتا فقتط. فتتي هتذه الحالتة ، ومتع ذلتك ، البامتتات بتدون قيتم يجتتب أن‬ ‫تسبق بقية القيم. على سبيل اللثال، اللثال في السفل غي صحيح :‬
‫:)‪>>> def politesse(vedette ='Monsieur', nom‬‬

‫ملثال آخر :‬
‫:)'!.‪>>> def question(annonce, essais =4, please ='Oui ou non, s.v.p‬‬ ‫...‬ ‫:0> ‪while essais‬‬ ‫...‬ ‫)‪reponse = input(annonce‬‬ ‫...‬ ‫:)'‪if reponse in ('o', 'oui','O','Oui','OUI‬‬ ‫...‬ ‫1 ‪return‬‬ ‫...‬ ‫:)'‪if reponse in ('n','non','N','Non','NON‬‬ ‫...‬ ‫0 ‪return‬‬ ‫...‬ ‫)‪print(please‬‬ ‫...‬ ‫1-‪essais = essais‬‬ ‫...‬ ‫>>>‬

‫يمكن استدعاء هذه الدالة بطرق مختلفة، على سبيل اللثال :‬
‫)' ? ‪rep = question('Voulez-vous vraiment terminer‬‬

‫أو :‬
‫)3 ,' ? ‪rep = question('Faut-il effacer ce fichier‬‬

‫أو :‬
‫)'! ‪rep = question('Avez-vous compris ? ', 2, 'Répondez par oui ou par non‬‬

‫خذ وقتا في تشيح هذا اللثال .‬ ‫برامترات مع علمات‬ ‫في معظم لغات البمجة، البامتات الت نضعها عند استدعاء الدالة تكون في نفس مكانها في تعريف الوظيفة.‬

‫18‬

‫يبرامترات مع علمات‬

‫بيلثون تسمح بقدر كبي من الرونة. إذا حصتلت البامتتات فتتي تعريفهتا فتي الدالتة علتى قيمتتة ، كمتا هتو موضتح أعله، يمكننتا‬ ‫استدعاء الدالة عتن طريتتق تقتديم البامتتات علتى أي ترتيتب، علتتى شت ط أن نكتتتب استم البامتت بشتكل صتحيح، علتتى ستبيل‬ ‫اللثال :‬
‫:)'‪>>> def oiseau(voltage=100, etat='allumé', action='danser la java‬‬ ‫...‬ ‫)‪print('Ce perroquet ne pourra pas', action‬‬ ‫...‬ ‫)'! ‪print('si vous le branchez sur', voltage, 'volts‬‬ ‫...‬ ‫)‪print("L'auteur de ceci est complètement", etat‬‬ ‫...‬ ‫)'‪>>> oiseau(etat='givré', voltage=250, action='vous approuver‬‬ ‫‪Ce perroquet ne pourra pas vous approuver‬‬ ‫! ‪si vous le branchez sur 250 volts‬‬ ‫‪L'auteur de ceci est complètement givré‬‬ ‫)(‪>>> oiseau‬‬ ‫‪Ce perroquet ne pourra pas danser la java‬‬ ‫! ‪si vous le branchez sur 100 volts‬‬ ‫‪L'auteur de ceci est complètement allumé‬‬

‫تمارين‬
‫7.41 عدل الدالة 3‪ (volBoite(x1,x2,x‬الت تم تعريفها في التمرين السابق، بحيث يمكن استدعاؤها بباماتر واحد‬ ‫أو اثني أو ثلثة برامتات، أو بدون برامتات. استخدم القيم الفتاضية للقيم هي 01، على سبيل اللثال :‬ ‫نتيجته : 0001‬ ‫نتيجته : 0.025‬ ‫نتيجته : 0.651‬
‫))(‪print(volBoite‬‬ ‫))2.5(‪print(volBoite‬‬ ‫))3 ,2.5(‪print(volBoite‬‬

‫7.51 عدل الدالة 3‪ (volBoite(x1,x2,x‬الت في العلى بطريقة بحيث يمكننا استدعاؤها مع برامت واحد أو اثنيتت‬ ‫أو ثلثة برامتات. في حالة استخدام برامت واحد، يكون الصندوق على عشتتكل مكعتتب )البامتتتات يجتتب أن تعتتب عتتن‬ ‫الحافة(. إذا تم استخدام برامتين، يبدو كأنه مربع منشور )في هذه الحالة البامتتت الولتتى للجتتانب واللثانيتتة لرتفتتاع‬ ‫النشور(. وإذا كانت ثلثة، تكون على عشكل متوازي، على سبيل اللثال :‬
‫))(‪print(volBoite‬‬ ‫))2.5(‪print(volBoite‬‬ ‫))3 ,2.5(‪print(volBoite‬‬ ‫))4.7 ,3 ,2.5(‪print(volBoite‬‬

‫)نتيجته : -1 )يشي إلى خطأ‬ ‫نتيجته : 806.041‬ ‫نتيجته : 21.18‬ ‫نتيجته : 44.511‬

‫الدالت الصلية‬

82

‫ فتي‬ca2 ‫ بحتروف‬ca1 ‫( التت تبتدل كتل حتروف‬changeCar(ch,ca1,ca2,debut,fin ‫7.61 عرف دالتة‬ ‫،ت هذان البامتان الخيان يمكننا تركهما )وفي هتتذه‬fin ‫ وإلى اللؤش‬debut ‫،ت بداية من اللؤش‬ch ‫سلسة نصية‬ : ‫الحالة يتم التعامل مع سلسلة واحدة من البداية إلى النهاية (، أملثلة على الدالة التوقعة‬
>>> phrase = 'Ceci est une toute petite phrase.' >>> print(changeCar(phrase, ' ', '*')) Ceci*est*une*toute*petite*phrase. >>> print(changeCar(phrase, ' ', '*', 8, 12)) Ceci est*une*toute petite phrase. >>> print(changeCar(phrase, ' ', '*', 12)) Ceci est une*toute*petite*phrase. >>> print(changeCar(phrase, ' ', '*', fin = 12)) Ceci*est*une*toute petite phrase.

، ‫( الت تقوم بإرجاع القيمة العلتتى فتتي السلستتلة التتت تتتم تمريرهتتا‬eleMax(liste,debut,fin ‫7.71 عرف الدالة‬ .(‫ يشيان إلى اللؤشات الت ينبغي البحث عنها، ويمكن حذفها )كما في التمريتن الستابق‬fin ‫ و‬debut ‫البامتان‬ : ‫أملثلة على الدالة التوقعة‬
>>> >>> 9 >>> 7 >>> 8 >>> 6 serie = [9, 3, 6, 1, 7, 5, 4, 8, 2] print(eleMax(serie)) print(eleMax(serie, 2, 5)) print(eleMax(serie, 2)) print(eleMax(serie, fin =3, debut =1))

‫38‬

‫يبرامترات مع علمات‬

‫8‬
‫8 استخدام النوافذ والرسوةمات‬
‫الساسية للغة، قبل أن نبدأ تعلم أعشياء أكث صعوبة وتطورا )ملثل النوافذ والصور والصوات، إلتتخ ...(يمكننتتا الن التوغتتل فتتي‬ ‫حت الن ، استخدمنا بيلثون فقتط فتي "الوضتع النصت" لنتته يجتتب علينتا أن نتعلتم أول عتددا متن الفتاهيم الساستية والبنيتة‬ ‫ً‬ ‫بيلثون والدخول إلى حقل واسع من الواجهات الرسومية ، لكن هذا لن يكون سوى البداية : على الرغم متن أننتا لتم نتعلتم الكتلثي‬ ‫ومازال أمامنا الكلثي من الساسيات يجب أن نتعلمها، وربما أصبح "الوضع النص " محبوبا لدى الكلثي منكم .‬

‫لواجهات المستخدمء الرسومية )‪(GUI‬‬ ‫إن كنت تجهل هذا حت الن ، اعلم أن مجال الواجهات الرسومية في غايتتة التعقيتتد والصتتعوبة. لكتتل نظتتام تشتتغيل يتتتوفر عتتدة‬ ‫"مكتبات" لوظائف الرسم الساسية ، الت تضاف )في كلثي من الحيان( إلى العديتتد متتن الكملت ، )أكتتث أو أقتتل بحستتب لغتتات‬ ‫البمجة( وتعرض جميع هذه الكونات بشكل عام فئات للكائن )كلس أوبجيكت( والت سندرس سماتها وأساليبها.‬ ‫مع بيلثون ، الكتبة الرسومية الكث استخداما حت الن ) هذا الكتاب قديم ( مكتبة تكنت التتذي هتتو تكييتتف لكتبتتة تاكتتا وضتتعت‬ ‫أصل للغة برمجة ‪ Tcl‬و ‪ : wxPython‬وهنا،ك أيضا عدة مكتبات رسومية للغة برمجة بيلثون ملثل ‪ PyQT‬و ‪... Pygtk‬إلخ‬ ‫و هنا،ك إمكانية لستخدام مكتبات جافا ومكتبتات ميكروستتوفت أم أف ست لنظتام وينتدوز. إضتتافة إلتى هتذا نحتتن ستتنتعلم فقتط‬ ‫البمجة باستخدام تكنت الت توجد لحسن الحظ نسخ لعدة أنظمة تشغيل )وبشكل مجاني( منها ويندوز ولينكس وما،ك‬

‫الخطوات اللولى مع ‪Tkinter‬‬
‫للمزيد من اليضاح ، نحن نفتض بالطبع أن وحدة ‪ Tkinter‬ملثبتة مسبقا على نظامك. لتكون قادرا على استخدام مميتتات‬ ‫تكنت يجب عليك أن تستدعيه )بسطر واحد فقط( بإضافة هذا السطر إلى ملف البنامج :‬
‫* ‪from tkinter import‬‬
‫72‬

‫72ف إصدارات بياثون الس ابقة )قبل الصدار الاث الث( تبدأ اسم الوحدة برف كبي‬

‫58‬

‫الخطوات الولى مع ‪Tkinter‬‬ ‫كالعادة ، ليس من الضوري على بيلثون كتابة سكريبت بل تستطيع فعل هذا متتن خلل ستتطر‬ ‫الوامر )بعد تشغيل بيلثون( في ملثالنا التالي سوف نقتتوم بإنشتتاء نافتتذة بستتيطة ، ثتتم نضتتيف‬ ‫فيها أداتي ، أداة جزء من النص )عنوان( وزر.‬
‫82‬

‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬

‫* ‪from tkinter import‬‬ ‫)(‪fen1 = Tk‬‬ ‫)'‪tex1 = Label(fen1, text='Bonjour tout le monde !', fg='red‬‬ ‫)(‪tex1.pack‬‬ ‫)‪bou1 = Button(fen1, text='Quitter', command = fen1.destroy‬‬ ‫)(‪bou1.pack‬‬ ‫)(‪fen1.mainloop‬‬

‫اعتمادا على هذه النسـخة مـن بيثـون ، سـوف نـرى نافـذة التطـبيق تظهـر مباشـرة بعـد إدخـال المـر الثـاني فـي‬

‫مثالنا هذا أو بعد السطر السابع فقط92.‬

‫دعونا الن نبحث عن المزيد في كل ألسطر الوامر المنفذة‬ ‫1. كما ستبق شتتحه أعله، فتإنه متن الستهل بنتاء وحتدات بيلثتون الختلفتة، والتت تحتتوي علتتى ستكريبتات، تعريفتات التدالت،‬ ‫أصناف الكائنات، إلخ ... يمكننا إذا استتدعاء جتزء أو كتل متن هتذه الوحتدات لي برنامتج، حتت لتو كنتا داختل مفست يعمتل‬ ‫بالوضع التفاعلي) هذا معناه مباشة إلى سطر الوامر(. هذا ما فعلناه في السطر الول للثالنا :‬ ‫‪ * from tkinter import‬معناه استدعاء جميع الصناف في وحدة ‪.tkinter‬‬ ‫2. سيكون لدينا الزيد حول هذه الفئات. في البمجة، تسمي مولدات الكائنات، وهي جزء من البنامج يمكن إعتتادة استتتخدامه.‬ ‫نحن ل نريد أن نعطيك التعريف الحدد والدقيق للكئنات والصناف، لكن أقتح أن نستخدمهم بشكل مباشتت وليتتس جزئتتي.‬ ‫سوف نفهم هذا تدريجيا.‬ ‫في السطر اللثاني من ملثالنا : ‪ ،()fen1 = Tk‬نحن استخدمنا صنفا للوحدة ‪ ،tkinter‬والصنف ‪ ،()Tk‬ونحن أنشأنا ملثيل‬ ‫)اسم آخر يصف كائنا محددا(، أي النافذة 1‪.fen‬‬ ‫هذه عملية تملثيل كائن من العمليتتات الساستتية فتتي التقنيتتات الحاليتتة للبمجتتة. هتتذه الطريقتتة فتتي الواقتتع الكتتث استتتخداما‬ ‫وتعرف باسم البمجة الشيئية )أو ‪ OOP‬أي البمجة الوجهة(.‬

‫82 الودجة هي نةتيجة لنكوم اش عب ارة ن افذة الداة. ف بعض لغ ات البمة , هذه ليست م ا ييطلق عليه ا السييطرة أو الكون الرسومي‬ ‫هذا الصيطلح يرشي إل أي شئ يكن وضعه ف إط ار الةتيطبيق : ماثل الزر والصور إل … وأحي ان ا الن افذة نفسه ا.‬ ‫92 إذا قومت بإجراء هذه العوملية تت نظ ام ويندوز , يب عليك اسةتخدام ويفضل أن يكون الصدار القي اسي من بياثون ف إط ار‬ ‫دوس ف بيئة تيطوير مةتك املة ‪ IDLE‬أو ‪ PythonWin‬بدل من ذلك. يكنك أن ترى أفضل , م ايدث بعد إدخ ال كل أمر .‬

‫استخدام النوافذ والرسومات‬ ‫الصنف هو نموذج عام يبدأ من أن نطلب من اللة بناء كائن حاسوبي معي. الصنف يحتتتوي علتتى مجموعتتة متتن التعريفتتات‬

‫68‬

‫للخيارات الختلفة، نحن لن نستخدم سوى جزء من الكائن الذي صنعناه إبتداءا منها. وبالتالي الصنف ‪ ،()Tk‬الذي يعد من‬ ‫الفئات الرئيستتية لكتبتة ‪ ، tkinter‬ويحتتتوي علتتى كتل متا هتتو مطلتتوب لتوليتتد أنتتواع مختلفتتة متن نوافتذ التطبيقتات، مختلفتتة‬ ‫الحجام واللوان، مع أو بدون شيط أوامر ... إلخ.‬ ‫نحن نستخدمها هنا لصناعة كائن رسومي أساس، أي نافذة تحتوي علتتى كتتل متتا تبقتتى. فتتي أقتتواس ‪،()Tk‬تت يمكننتتا تحديتتد‬ ‫خيارات مختلفة، لكن سنت،ك هذا إلى وقت آخر.‬

‫تجسيد التعليمة يشبه تعيي بسيط لتغي. أفهم من ذلك أنه يحدث هنا عشيئان في وقت واحد :‬ ‫إنشاء كائن جديد، )و الذي قد يكون معقدا للغاية في بعض الحالت، وبالتالي يحتل مساحة كبية في الذاكرة(‬ ‫تعيي التغي، والذي سيعمل الن كمرجع لعالجة الكائن .‬
‫03‬

‫○‬ ‫○‬

‫3. في السطر اللثالث :‬
‫,)'‪tex1 = Label(fen1, text='Bonjour tout le monde !', fg='red‬‬

‫كما يوحي لنا اسمه، هذا الصنف يعرف جميع أنواع التسميات )أو العلمات(. في الواقع، هو ببستتاطة هتتو جتتزء متتن النتتص،‬ ‫يستخدم لعرض معلومات ورسائل مختلفة داخل النافذة.‬ ‫سنسعى جاهدين لتمريتتر الطريقتتة الصتتحيحة للتعتتبي عتتن العشتتياء، نقتتول هنتتا أننتتا صتتنعنا الكتتائن 1‪ tex‬بواستتطة ملثيتتل‬ ‫الصنف ‪.()Label‬‬ ‫لحظ أننا قمنا باستدعاء الصنف، بنفس الطريقة الت استدعينا فيها الدالة : وهذا معنتتاه تقتتديم عتتدد متتن البامتتتات داختتل‬ ‫القواس. سوف نرى لحقا أن الصنف هو نوع من أنواع "الحاويات، والت تم تجميع فيها مجموعة من الدالت والعطيات.‬ ‫ما هي البامتات الت قدمناها لهذا اللثيل ؟‬ ‫الباماتر الول الذي تم تمريره هو )1‪،(fen‬ت يشي إلى أن الودجتتة الول التذي قمنتتا بصتنعه داختتل الودجتتدة االستتابقة،‬
‫○‬

‫نحن سنصنع كائنا آخر )ودجة(، وهذه الرة من الصنف ‪.()Label‬‬

‫التي وضعناها هنا ملثل "سيده" : الكائن 1‪ fen‬هو الودجة السيد للكائن 1‪ .tex‬نستطيع أن نقول أن الكائن 1‪tex‬‬
‫هو ودجة تابعة للكائن 1‪.fen‬‬
‫03‬ ‫هذا الخةتص ار ف اللغة هو نةتيجة لدين اميكية الكةت ابة من الةتغيات الس ارية ف بياثون، تسةتخدم اللغ ات الأخرى تعليومة خ اصة‬ ‫)نو ‪ ،(new‬لإنرش اء ماثيل ك ائن جديد. ماث ال:‬ ‫‪ ،maVoiture = new Cadillac (instanciation d’un objet de classe Cadillac‬الرش ار إليه ا ف الةتغي‬ ‫‪.(maVoiture‬‬

‫78‬

‫الخطوات الولى مع ‪Tkinter‬‬
‫○‬

‫هذان البامتان يستخدمان ليصفان بالضبط ماذا يجب أن تأخذ الودجة. هذا في الواقع اختياران للصنع، قدم لكل واحد‬ ‫في عشكل سلسلة نصية / في البدايتتة نتتص التستتمية، ثتتم اللتتون )‪ foreground‬أو باختصتتار ‪ .(fg‬نحتتن نريتتد أن يظهتتر‬ ‫النص بشكل جيد، لذلك لوناه باللون الحمر.‬ ‫و يمكننا أيضا تحديد الزيد من الخصائص الخرى : ملثل الخط أو اللون الخلفي على سبيل اللثتتال. كتتل هتتذه الخصتتائص‬ ‫لديها قيم افتاضية في تعريف الصنف ‪ .()Label‬ل يمكننا تحديد جميع الخيتتارات التاحتتة للخصتتائص الختلفتتة عتتن‬ ‫النموذج القياس.‬

‫4. في السطر الرابع من ملثالنا : ‪،()tex1.pack‬ت فّعلنتتا الستلوب الرتبتط بالكتتائن 1‪ : tex‬الستتلوب ‪ .()pack‬لقتد التقينتتا‬ ‫بالفعل مع هتتذا الستتلوب )عتن القتتوائم خاصتت ة(. وهنالتتك أستتلوب الدالتتة مضتتمنة فتتي الكتتائن ) نقتتول أيضتتا كمتتا يتتتم تغليتتف‬ ‫ً‬ ‫الكائن(. وسوف نعلم عما قريب أن الكائن الحاسوبي هو في الواقع عنص لبنامج يحتوي دائما على :‬ ‫عدد من البيانات )رقمية أو غيها(، تحتوي في داخل التغيات من أنواع مختلفة : نسميها خصائص الكائن.‬ ‫و يطلق على مجموعة من الجراءات والدالت )والت هي خوارزمية( : أساليب الكائن.‬ ‫السلوب ‪ ()pack‬هو مجموعة من الساليب الت تطبق ليتتس فقتتط علتتى ودجتتة الصتنف ‪،()Label‬تت بتتل تطبتتق فتتي‬ ‫معظم الودجات الخترى لتت ‪ ،tkinter‬و التت تتلؤثر علتتى ترتيبهتا فتي الطتتار الهندست فتي النافتذة. كمتتا يمكنتتك أن تترى‬ ‫بنفسك إذا قمت بإدخال أوامر ملثالنا واحتدا تلتو الختر، الستلوب ‪ ()pack‬يقلتل تلقائيتا حجتم نافتذة - الستيد - بحيتث‬ ‫تكون كبية لضافة ما يكفي من الويدجات - التابعة - الحددة مسبقا.‬ ‫5. في السطر الخامس :‬
‫,)‪bou1 = Button(fen1, text=’Quitter’, command = fen1.destroy‬‬

‫○‬ ‫○‬

‫صنعنا الودجة اللثانية - "تابع" - : وزر‬ ‫كما فعلنا مع الودجة السابقة، نحن استدعينا الصنف ‪ ()Button‬مصتتحوبا بقوستتي بتتداخلها البامتتتات. لنتته فتتي هتتذه‬ ‫الحالة من الكائن التفاعلي، يجب علينتتا أن نضتع خيتتار متاذا ستيحدث عنتتدما يقتتوم الستتخدم بالضتغط علتتى التزر. فتتي هتتذه‬ ‫الحالة، وضعنا خيار إغلق مرتبط بالكائن 1‪ ،fen‬الذي ينبغي أن يتسبب بإغلق النافذة .‬
‫13‬

‫6. في السطر السادس استخدمنا السلوب ‪ ()pack‬حت يتكيف هندسيا في النافذة مع الكائن الجديد لدمجه.‬

‫13‬ ‫تذير : إسةتدع اء السلوب " ‪ "destroy‬ل يةتم هن ا )أي داخل تعليومة وصف الزر( . و لذلك ل يب إل ا ق أقواس بإسه. لن‬ ‫‪ tkinter‬هو الذي سيةتول إسةتدع اء ‪ ()destroy‬عندم ا يقوم السةتخدم بضغط الزر.‬

‫استخدام النوافذ والرسومات‬

‫88‬

‫7. في السطر السابع : ‪ ()fen1.mainloop‬مهم للغاية، لنه يتسبب ببدء الحداث الرتبطة بالنافذة. هذه التعليمتتة ضتتورية‬ ‫للغاية لتطبيقنا سواء لت - الطلع - على نقرات الفأرة، أو للضغطات على لوحة الفاتيح، إلتتخ ... إذا هتتذه التعليمتتة بتعتتبي‬ ‫آخر - تجعله يعمل -.‬ ‫مستمر، في انتظار رسائل من قبل نظام التشغيل اللثبت على الحاسوب. ينتظر فتتي الواقتتع بشتتكل مستتتمر فتتي بيئتتته، أجهتتزة‬ ‫الدخال )الفأرة، لوحة الفاتيح، إلخ ...(. عندما يتم الكشف عن أي حالة، يتم إرسال رسائل مختلفة التت تصتتف الحالتتة إلتتى‬ ‫البنامج. سنتعرف على التفاصيل قريبا.‬ ‫برامج تتوجه حسب الحداث‬ ‫لقد صنعت برنامجك الول مستخدما الواجهة الرسومية. هذا النتتوع متتن البامتتج يتنظتتم بطريقتتة مختلفتتة عتتن الستتكريبتات التتت‬ ‫درسناها سابقا.‬ ‫جميتتع برامتتج الحاستتوب لتتديك تعمتتل بلثلثتتة مراحتتل رئيستتية : مرحلتتة التهيئتتة، التتت تحتتتوي علتتى‬ ‫التعليمات الت ت ّعد العمل الطلوب )استدعاء الوحدات الخارجية اللزمة،فتح ملفات، التصال بختتادم‬ ‫قواعد البيانات أو في عشبكة النتنات، إلخ ..(، الرحلة الوسطى )الركزية( حيث نجد هنتتا،ك التتدالت‬ ‫الرئيسية للبنامتج )هتذا معنتتاه كتل شتء متن الفتتض أن يفعلتته البنامتج : عترض البيانتات علتى‬ ‫الشاعشة، تنفيذ العمليتتات الحستتابية، تحريتتر محتويتتات للتف، طباعتتة، إلتخ ...(، وفتي النهايتتة مرحلتتة‬ ‫النتهاء والذي تعمل على إغلق العتتاملت - بشتتكل صتتحيح - )هتتذا معنتتاه إغلق اللفتتات الفتوحتتة،‬ ‫قطع التصالت الخارجية، إلخ ...(‬ ‫في البنامج - بالوضع النص - ، يتم ترتيب هذه الراحل اللثلثتتة ببستتاطة فتتي نمتتط خطتتي كمتتا تتتم‬ ‫توضيحه. وبناء على ذلك، تتمي هذه البامج بتفاعلها الحدود جدا مع الستخدم. هتذه متن الناحيتتة‬ ‫ً‬ ‫العملية ليس لديك أي حرية : يطلب منك من وقت لخر إدخال بعتتض البيانتتات متتن لوحتتة الفاتيتتح،‬ ‫لكن دائما في ترتيب محدد سابقا لسلسلة من تعليمات البنامج.‬ ‫فتي حالتتة أن البنامتج يستتخدم الواجهتتة الرستومية، يكتون التنظيتم التداخلي هتو الختلتف. نقتول أن البنامتج يتتوجه بواستطة‬ ‫الحداث. بعد مرحلة التهيئة، البنامج من هذا النوع يبقى ينتظتتر، ويمتترر الستتيطرة علتتى برنامتتج آختتر، والتت هتتي أكتتث أو أقتتل‬ ‫اندماجا مع نظام التشغيل الوجود على الحاسوب.‬ ‫كما يوحي اسمها ) ‪،(mainloop‬ت هو أسلوب للكائن 1‪،fen‬ت الذي يفّعل حلقتة البنامتج، التذي يعمتل فتي الخلفيتتة بشتتكل‬

‫98‬

‫يبرامج تتوجه ظحسب الظحداث‬

‫هذا متلقي الحداث يقوم باستمرار بفحص اللحقات )لوحة الف اتيح، الفأرة، الساعة، التتودم، إلتتخ ...( ويتفاعتتل فتتور الكشتتف عتتن‬ ‫حصول حدث. ويمكن أن يكون هذا الحدث من الستتتخدم : تحريتتك الفتتأرة، الضتتغط علتتى مفتتتاح فتتي لوحتتة الفاتيتتح، إلتتخ ... أو‬ ‫يمكن حدث خارجي أو تلقائي ) انتهاء اللؤقت، على سبيل اللثال( .‬

‫عندما يتم كشف حدث، يرسل التلقي رسالة معينة إلى البنامج ، الذي هو مصمم ليد وفقا لذلك.‬
‫23‬

‫مرحلة التهيئة لبنامج يستخدم واجهة رسومية تتضمن مجموعة من التعليمات الت تضع مكونات الواجهة التفاعلية في مكانهتتا‬ ‫)النوافذ، الزرار، الخانات، إلخ ...(. الزيد من تعليمات الت تعرف رسائل الحداث تكتتون مدعومتتة : فتتي الواقتتع، يمكتتن للمتترء أن‬ ‫يقرر ردة فعل البنامج على أحداث معينة ويتجاهل البقية.‬ ‫بينما الرحلة الوسطى في البنامج النص، تتكون من سلستتلة متتن التعليمتتات التتت تصتتف ترتيتتب الهتتام التتت ينبغتتي أن يلؤديهتتا‬ ‫البنامج )حت لو تم تقديمها في مسارات مختلفة استجابة للظروف الت تتواجهه(، ل توجتد مرحلتة وستطى فتي البنامتج التذي‬ ‫يستخدم الواجهة الرسومية بل تكون مجموعة من الدالت الستقلة. وتستدعى كل دالة خاصة عندما يتم الكشف عن حدث معيتت‬ ‫من قبل نظام التشغيل : يتم تنفيذ الدالة لتقوم بالعمل التوقع للبنامج في استجابة لهذا الحدث، ثم ل شء آخر .‬
‫33‬

‫23هذه الرس ائل غ الب ا م ا تدل على ‪) WM‬رس ائل الن افذة( ف بيئة رسومية تةتكون من نوافذ )مع من اطق فع الة كاثية : الزرار, خ ان ات‬ ‫الخةتي ار, القوائم, إل(. ف وصف الوارزمي ات, كوم ا يدث ف كاثية من الحي ان تةتلط هذه الرس ائل مع الحداث نفسه ا .‬ ‫33ب العن الدقيق للكلومة, أي دالة ل ترجع أية قيومة هي إجراء )انظر إل صفحة07(.‬

‫استخدام النوافذ والرسومات‬

‫09‬

‫بالتوازي مع الدالة الولى الت لم تكمل عملها بعد . يمكن لنظمة التشغيل ولغتات البمجتتة الحديلثتة أن تعمتتل بتالتوازي والتت‬
‫43‬

‫إذا حدث ح ْدث آخر، يمكن أن يكون الترد متن الدالتة اللثانيتة )أو اللثاللثتة، أو الرابعتتة، إلتخ...(التت ستوف يتتم تفعيلهتتا لتبتدأ عملهتتا‬ ‫َ َ َ‬ ‫نسميها أيضا تعدد الهام.‬ ‫في الفصل السابق، لحظنا بالفعل أن بنية اللتتف النصتت لبنامتتج غيتت مشتتابه لبنيتتة اللتتف عنتتدما يتتتم تنفيتتذه. هتتذه اللحظتتة‬

‫تنطبق أيضا على البنامج مع الواجهة الرسومية، حيث ترتيب الدالت الت يتم إستدعائها غي مسجلة بأي جزء متن البنامتج.‬ ‫الحداث هي الت تتحكم !‬ ‫كل هذا قد يبدو معقدا قليل. سوف نوضح هذا في بعض أملثلة.‬ ‫مثال رلسومي : رلسم خطوط على اللوحة‬ ‫الستتكريبت التتذي بالستتفل يصتتنع نافتتذة متتع ثلثتتة أزرار ولوحتتة.‬ ‫بمصتتتتتطلحات ‪ ،tkinter‬اللوحتتتتتة - ‪ - canevas‬هتتتتتي مستتتتتاحة‬ ‫مستطيلة محددة، يمكن أن يوضتتع بهتتا مختلتتف التصتتاميم والصتتور‬ ‫باستخدام أساليب محددة .‬
‫53‬

‫عنتتد الضتتغط علتتى زر "رستتم ختتط" - " ‪،"Tracer une ligne‬‬ ‫سيظهر سطر ملون جديد على اللوحة، كل واحد لتتديها ميتتل مختلتتف‬ ‫عن سابقتها.‬ ‫إذا تم الضغط على زر "لون آختتر" - " ‪ ،" Autre couleur‬ستتيتم‬ ‫اختيار لون جديد من سلسلة اللوان الحددة. هذا اللون سيتم استخدامه في الرسم القادم.‬ ‫زر "خروج" - " ‪ " Quitter‬لنهاء التطبيق عن طريق غلق النافذة.‬
‫‪ tkinter‬تمرين صغير يستخدم مكتبة الرسومية #‬ ‫* ‪from tkinter import‬‬ ‫‪from random import randrange‬‬ ‫-- : تعريف دالت لمعالجة الظحداث --- #‬‫:)(‪def drawline‬‬ ‫"1‪"Tracé d'une ligne dans le canevas can‬‬ ‫‪global x1, y1, x2, y2, coul‬‬ ‫)‪can1.create_line(x1,y1,x2,y2,width=2,fill=coul‬‬

‫43 نفس الدالة يكن أن يةتم اسةتدع اؤه ا عدة مرات ردا على وقوع بعض الحداث نفسه ا, ث يةتم تنفيذ نفس الهومة بنسخ مةتلفة ,‬ ‫سوف نرى لحق ا أنه يكن أن يؤدي إل "آث ار ح افة" مزعجة.‬ ‫53ف النه اية سيةتم تريك هذه الرسوم ف مرحلة لحقة .‬

‫19‬
‫: تعديل الظحداثيات للسطر التالي #‬ ‫01-1‪y2, y1 = y2+10, y‬‬

‫يبرامج تتوجه ظحسب الظحداث‬

‫:)(‪def changecolor‬‬ ‫"‪"Changement aléatoire de la couleur du tracé‬‬ ‫‪global coul‬‬ ‫]'‪pal=['purple','cyan','maroon','green','red','blue','orange','yellow‬‬ ‫)8(‪c = randrange‬‬ ‫توليد رقم عشوائي يبين 0 و 7 >= #‬ ‫]‪coul = pal[c‬‬ ‫------ البرنامج الرئيسي ------#‬‫: سيتم استخدام المتغيرات التالية يبشكل عام #‬ ‫01 ,091 ,091 ,01 = 2‪x1, y1, x2, y‬‬ ‫إظحداثيات السطر #‬ ‫'‪coul = 'dark green‬‬ ‫لون السطر #‬ ‫: إنشاء الودجة الرئيسية )"السيد "( #‬ ‫)(‪fen1 = Tk‬‬ ‫: إنشاء الودجة )"التايبع "( #‬ ‫)002=‪can1 = Canvas(fen1,bg='dark grey',height=200,width‬‬ ‫)‪can1.pack(side=LEFT‬‬ ‫)‪bou1 = Button(fen1,text='Quitter',command=fen1.quit‬‬ ‫)‪bou1.pack(side=BOTTOM‬‬ ‫)‪bou2 = Button(fen1,text='Tracer une ligne',command=drawline‬‬ ‫)(‪bou2.pack‬‬ ‫)‪bou3 = Button(fen1,text='Autre couleur',command=changecolor‬‬ ‫)(‪bou3.pack‬‬ ‫)(‪fen1.mainloop‬‬ ‫)(‪fen1.destroy‬‬ ‫يبدء إستقبال الظحداث #‬ ‫تدمير )غلق( النافذة #‬

‫وفقتتتتا لتتتا شتتتتحناه فتتتتي صتتتفحات الستتتتابقة، وظيفيتتتتة هتتتذا البنامتتتج تقتتتتوم علتتتتى دالتتتتتي أساستتتيتي ‪ ()drawline‬و‬ ‫‪ ،()changecolor‬الت يتم تفعيلها من خلل الحداث، لنها تم تفعيلها في مرحلة التهيئة.‬ ‫في هذه الرحلة - مرحلة التهيئة -، نحن نبدأ باستدعاء وحدة ‪ tkinter‬بالضافة إلى وحدة ‪ random‬التتت تقتتوم باختيتتار رقتتم‬ ‫عشوائي. ثم صنعنا الويدجات الختلفة ملثل ‪ ()Tk()، Canvas‬و ‪ .()Button‬لحظ أن بتتالتمرير للصتنف ‪()Button‬‬ ‫صنعنا مجموعة من الزرار، الت هي مشابهة لبعضها جدا، مع خيارات لكل واحدة منهتتا لصتتناعتها، والزرار تستتتطيع أن تعمتتل‬ ‫بشكل مستقل عن الخرى .‬ ‫مرحلة التهيئة تنتهي مع التعليمة ‪ ()fen1.mainloop‬التتت تبتتدأ بتلقتتي الحتتداث. التعليمتتات التتت تتتأتي بعتتدها ستتتعمل‬ ‫عندما يتم الخروج من الحلقة، ستخرج من خلل أسلوب ‪) ()fen1.quit‬انظر أدناه(.‬ ‫خيار المر الستخدم في عبارة تجسيد الزرار الت ترسم الدالة االتتت ستيتم استتتدعائها عنتتدما يعمتتل هتتذا الحتتدث " ضتتغط علتتى‬ ‫الزر اليس للفأرة على الودجة". في الواقع يجب عمل اختصار لهذا الحتتدث حاصتتة، والتتذي يتتتم تقتتديمه متتن ‪ tkinter‬لراحتتتك‬

‫استخدام النوافذ والرسومات‬

‫29‬

‫لن هذا الحدث يرتبط بشكل طبيعي مع الودجة من نوع زر. سوف نرى لحقا أن هنالك تقنيات أختترى أكتتث عموميتتة لربتتط أي‬ ‫نوع من الحداث إلى أي قطعة.‬ ‫يمكن للدالت في هذا السكريبت تعديل - تحرير - قيم التغي العرفة في الجزء الرئيس من البنامج. ولقد أصبح هذا ممكنا مع‬ ‫التعليمة ‪ global‬الستخدمة لتعريف هذه الدالت. نحن نسمح لنفسنا أن نفعل ذلك لبعض الوقت ) حت لو كان فقط للتعود‬ ‫على التميي بي التغيات الحلية والعامة(، لكن كما ستفهم في وقت لحق، هذه المارسة غي مستحسنة، خاصتة عنتدما تكتتتب‬ ‫برامج كبية. سوف نتعلم أفضل التقنيات عندما نصل لدراسة الصناف )بداية من الصفحة 571(.‬ ‫في دالتنا ‪ ،()changecolor‬يتم اختيار لون عشوائي من القائمة. وللقيام بذلك قمنا باستخدام الدالة ‪()randrange‬‬ ‫الت تقوم باستدعاء الوحدة ‪ .random‬الت يتم استدعاؤها مع البامت ‪،N‬تت هذه الدالة تقوم بإرجاع عدد صحيح، متتا بيتت 0 و‬ ‫1-‪.N‬‬ ‫زر المر مرتبتط بتت - ‪ - Quitter‬ختروج - التت تستتدعي الستوب ‪ ()quit‬لنافتذة 1‪ .fen‬ويستتخدم هتذا الستلوب لغلق -‬ ‫خروج - من متلقي الحداث )‪ (mainloop‬الرتبط بهذه النافذة. عندما يتم تفعيل هذا السلوب، سيتواصل تنفيتتذ البنامتتج‬ ‫مع التعليمة بعد استدعاء الت ‪ .mainloop‬في ملثالنا، سيتم إزالة النافذة .‬ ‫كيف يتم تغيي البنامج لكي تكون ألوان الخطو ط : ‪ cyan‬و ‪ maroon‬و ‪green‬؟‬ ‫كيف يتم تغيي البنامج لكي تكون جميع الخطو ط أفقية وعمودية ؟‬ ‫كتتب حجتتم اللوحتتة لتصتتبح عرضتتها 005 وحتتدة وارتفاعهتتا 056 وحتتدة. وغيتت أيضتتا حجتتم الخطتتو ط، لتكتتون حتتوافهم‬ ‫تتساوى مع حواف اللوحة.‬ ‫أضف دالة 2‪ drawli ne‬الت تتبع خطي أحمرين بعلمة أكس في وسط اللوحة، واحدة أفقية والخرى عمودية.‬ ‫وأضف أيضا زر "منظار"، عند الضغط عليه سوف تظهر علمة أكس.‬ ‫كرر كتابة البنامج الول. أستبدل السلوب ‪ create_line‬بت ‪ .create_rectangle‬ماذا سيحدث ؟‬ ‫و بنفس الطريقة حاول مع ‪ create_arc، create_oval‬و ‪.create_polygon‬‬ ‫لكل أسلوب، اكتب خياراته في البامتات. )ملحظتتة : بالنستتبة للمضتتلع، فمتتن الضتتوري القيتتام بتعتتديل صتتغي علتتى‬ ‫البنامج ليعمل !(‬ ‫ احذف السطر 2‪ global x1, y1, x2, y‬في دالة ‪ drawline‬في البنامج الصلي. ماذا حدث؟ ولاذا؟‬‫ إذا وضعت "2‪ "x1, y1, x2, y‬داخل القواس، في سطر تعريف الدالة ‪،drawline‬تت بطريقة لتمريتتر التغيتتات‬‫للدالة كبامتات، هل يعمل البنامج ؟ ل تنس أيضا تغيي السطر الذي يستدعي هذه الدالة !‬ ‫َ‬ ‫8. 6‬ ‫8. 5‬ ‫8. 4‬

‫تمارين‬
‫8. 1‬ ‫8. 2‬ ‫8. 3‬

‫39‬

‫يبرامج تتوجه ظحسب الظحداث‬

‫إذا عرفت 01 ,093 ,093 ,01 = 2‪ x1, y1, x2, y‬بدل 1‪،...e global x1, y‬ت ماذا سيحدث ؟ ولاذا ؟‬ ‫ّ‬ ‫ماذا استنتجت من هذا ؟‬ ‫للخروج من الافذة.‬ ‫ب( عدل البنامج أعله بإضافة خمسة أزرار كل زر يرسم حلقة من الحلقات الخمس.‬ ‫في دفت اللحظات، خطط جدول من عمودين. ستكتب على اليسار تعريفتتات الصتتناف التتت قتتد درستتناها )متتع قائمتتة‬ ‫البامتات(، وعلى اليمي الساليب الرتبطة بهتتذه الصتتناف )متتع برامتاتهتتا(. اتتتر،ك بعتتض الجتتال لكمتتاله فتتي وقتتت‬ ‫لحق.‬ ‫مثال رلسومي : رلسمان متناوبان‬ ‫اللثال التالي يظهر لك كيفية الستفادة من العلومات والعرفة الت قد حصلت عليها للقوائم الحلقات والدالت، لرسم العديتتد متتن‬ ‫الرسومات بأسطر قليلة. هذا البنامج الصغي يظهر واحد من الرسمي الوجودين بالسفل، على حسب الزر الضغو ط :‬ ‫8. 8‬ ‫أ( اكتب برنامجا قصيا يرسم الحلقات الولبيتة الخمتس فتتي مستتتطيل أبيتض )‪ .(white‬بالضتافة إلتى زر ‪Quitter‬‬ ‫8. 7‬

‫* ‪from tkinter import‬‬ ‫:)'‪def cercle(x, y, r, coul ='black‬‬ ‫"‪"tracé d'un cercle de centre (x,y) et de rayon r‬‬ ‫)‪can.create_oval(x-r, y-r, x+r, y+r, outline=coul‬‬ ‫:)(1_‪def figure‬‬ ‫"‪"dessiner une cible‬‬ ‫: أظحذف أول أي رسم سايبق #‬ ‫)‪can.delete(ALL‬‬ ‫: أرسم خطين )أفقي وعمودي ( #‬ ‫)'‪can.create_line(100, 0, 100, 200, fill ='blue‬‬ ‫)'‪can.create_line(0, 100, 200, 100, fill ='blue‬‬ ‫: أرسم عدة دوائر متحدة المركز #‬ ‫51 = ‪rayon‬‬ ‫:001 < ‪while rayon‬‬

‫استخدام النوافذ والرسومات‬
‫)‪cercle(100, 100, rayon‬‬ ‫51 =+ ‪rayon‬‬ ‫:)(2_‪def figure‬‬ ‫"‪"dessiner un visage simplifié‬‬ ‫: أظحذف أول أي رسم سايبقا #‬ ‫)‪can.delete(ALL‬‬ ‫خصائص كل دائرة #‬ ‫: موضوعة في قائمة من القوائم #‬ ‫,]'‪cc =[[100, 100, 80, 'red‬‬ ‫الوجع #‬ ‫,]'‪[70, 70, 15, 'blue‬‬ ‫العينان #‬ ‫,]'‪[130, 70, 15, 'blue‬‬ ‫,]'‪[70, 70, 5, 'black‬‬ ‫,]'‪[130, 70, 5, 'black‬‬ ‫,]'‪[44, 115, 20, 'red‬‬ ‫الخدان #‬ ‫,]'‪[156, 115, 20, 'red‬‬ ‫,]'‪[100, 95, 15, 'purple‬‬ ‫النف #‬ ‫الفم # ]]'‪[100, 145, 30, 'purple‬‬ ‫: يتم رسم جميع الدوائر يبمساعدة ظحلقة #‬ ‫0= ‪i‬‬ ‫:)‪while i < len(cc‬‬ ‫تدوير الحلقة #‬ ‫]‪el = cc[i‬‬ ‫كل عنصر هو في ظحد ذاته قائمة #‬ ‫)]3[‪cercle(el[0], el[1], el[2], el‬‬ ‫1 =+ ‪i‬‬ ‫############ : البرنامج الرئيسي #####‬ ‫)(‪fen = Tk‬‬ ‫)'‪can = Canvas(fen, width =200, height =200, bg ='ivory‬‬ ‫)5= ‪can.pack(side =TOP, padx =5, pady‬‬ ‫)1_‪b1 = Button(fen, text ='dessin 1', command =figure‬‬ ‫)3= ‪b1.pack(side =LEFT, padx =3, pady‬‬ ‫)2_‪b2 = Button(fen, text ='dessin 2', command =figure‬‬ ‫)3= ‪b2.pack(side =RIGHT, padx =3, pady‬‬ ‫)(‪fen.mainloop‬‬

‫49‬

‫ابدأ بتحليل البنامج الرئيس، في نهاية السكريبت :‬ ‫لقد قمنا بإنشاء نافذة، بتملثيل كائن للصنف ‪ ()Tk‬في التغي ‪.fen‬‬ ‫وزران. ولقد أنشأنا اللوحة في التغي ‪ ،can‬الزران في التغي 1‪ b‬و 2‪ .b‬كما فتتي الستتكريبت الستتابق، الويتدجات تتم وضتتعهم‬ ‫•الخيار ‪ side‬الذي يقبل القيم ‪ TOP، BOTTOM، LEFT‬أو ‪،RIGHT‬تت لوضع الودجة في الجانب الناسب في النافتتذة.‬ ‫هذه السماء تكتب بأحرف كبية وهم جزء من متغيات التت تتم استتدعاؤها متع الوحتدة ‪ ،tkinter‬ويمكتن أن تعتتبه ،ك‬ ‫"عشبه ثوابت ".‬ ‫لقد قمنا بإنشاء نافذة، بتملثيل كائن للصنف ‪ ()Tk‬في التغي ‪،can‬تت ثم قمنا بوضع ثلثتتة ويتتدجات فتتي هتتذه النافتتذة : لوحتتة‬ ‫في أماكنهم في النافذة بمساعدة السلوب ‪ ،()pack‬لكن هذه الرة استخدمنا هذه الخيارات :‬

‫59‬

‫يبرامج تتوجه ظحسب الظحداث‬

‫•الخياران ‪ padx‬و ‪ pady‬اللذان يقومان بحجز مساحة صغية حول الودجة. هذه الساحة تعب عن عدد البيكسلت :‬ ‫‪ padx‬تحجز الساحة على يمي ويسار الودجة، و ‪ pady‬تقوم بحجز الساحة فوق وتحت الودجة.‬ ‫•الزرار تتحكتتم فتتي إظهتتار الرستتمي، باستتتدعاء التتدالتي 1_‪ ()figure‬و 2_‪ .()figure‬بمتتا أننتتا سنستتم العديتتد متتن‬ ‫الدوائر في هذه الرسومات، ففكرنا أنه من الفيد أن نبدأ بتعريتف دالتة ‪ ()cercle‬لرستم التدوائر. فتي الحقيقتتة، وربمتا لتم‬ ‫)و بالطبع دوائر أيضا(، لكن هذا السلوب يجب أن يحتوي عتتل أربعتتة برامتتتات التتت هتتي إحتتداثيات أعلتتى وأستتفل ويميتت‬ ‫ويسار مستطيل وهمي، في أي عشكل بيضوي تريتتد أن ترستتمه. وهتتذا ليتتس عمليتتا فتتي حتتالت معينتتة متتن التدائرة : والكتتث‬ ‫طبيعية هو أن يتم تمرير طول الركز ونصف قطر الدائرة وهذا ما سنحصتتل عليتته فتتي دالتنتتا ‪ ،()cercle‬والتتت تستتتدعي‬ ‫السلوب ‪ ()create_oval‬عن طريق إجراء تحويل للتنسيق. لحظ أيضا أن هتذه الدالتة يجتب إعطاؤهتا لتون التدائرة‬ ‫الت تريدها )اللون الفتاض هو السود(.‬ ‫و عمل هذه الطريقة سهل وواضح في الدالة 1_‪،()figure‬تت لقد صنعنا دالة بسيطة لتكتترار رستتم جميتتع التتدوائر )بنفتتس‬ ‫الركز وبنفس القطر متايد(. ملحظة أخرى وهي استخدام العامل += الت تزيد قيمة التغي )في ملثالنا، التغيتت ‪ r‬يتتزداد‬ ‫51 قيمة في كل تكرار(.‬ ‫الرسم اللثاني هو أكث تعقيدا نوعا ما، لنه يتكون من دوائر مختلفة الحجام في أماكن مختلفة. نستطيع رسم كتل هتذه التدوائر‬ ‫بمساعدة حلقة تكرار واحدة، إذا عرفنا كيفية الستفادة من القوائم.‬ ‫في الحقيقة أن الفرق بي الدوائر الت رسمناها يتلخص في ثلثة خصائص :‬ ‫إحداثيات ‪ x‬و ‪ y‬للوسط، والركز واللون. لكن دائرة، نستطيع أن نضع هذه الخصائص في قائمة صغية، ثتتم نقتتوم بجمتتع كتتل‬ ‫هذه القوائم الضغية في قائمة أكب. هذا سيتيح لنا قائمة من القوائم، وبمساعدة حلقة التكرار ستتيتم رستم التدوائر فتتي المتتاكن‬ ‫الصحيحة .‬ ‫ستوحي بعض الفكار من الستتكريبت الستابق لكتابتتة برنامتتج لظهتار لوحتتة لعبتتة التداما ) الرستم يتكتتون متن مربعتتات‬ ‫تكن تعرف سابقا أن اللوحة في ‪ tkinter‬لديها أسلوب ‪ ()create_oval‬تستطيع من خلله رسم أية أعشكال بيضوية‬

‫تمالرين‬
‫8. 9‬

‫سوداء وبيضاء( عندما نضغط على الزر‬

‫استخدام النوافذ والرسومات‬

‫69‬

‫8.01 من برنامتج التمريتن الستابق، أضتف زرا ستوف يظهتر بيتادق بشتكل عشتوائي فتي‬ ‫ً‬ ‫لوحة الداما ) كل ضغطة على الزر سوف تظهر بيدق بشكل عشوائي(.‬

‫مثال رلسومي : آلة حالسبة بسيطة‬ ‫على الرغم من أن الكود قصي للغاية، السكريبت التتذي بالستتفل ملثتتل التتة حاستتبة كاملتتة أي‬ ‫أنه يمكنك الحساب حت مع القتتواس والرمتتوز العلميتتة. ل يوجتتد أي شتء غيتت عتتادي. كتل‬ ‫هذه الوضائف تستخدم مفس بدل من متجم لتنفيذ برامجك.‬ ‫كمتتا تعلتتم، فتتإن التتتجم ل يتتأتي إل لتترة واحتتدة، لتحويتتل الكتتود الصتتدري لبنامجتتك إلتتى‬ ‫برنامج قابل للتنفيذ. أي أن دوره ينتهي قبل تنفيذ البنامج. أما الفس يبقى نشطا خلل تنفيتتذ البنامتتج وبالتتتالي هتتو متتتوفر‬ ‫لتجمة أي كود مصدري جديد، ملثل عبارة رياضية يتم إدخالها عن طريق لوحة الفاتيح من الستخدم.‬ ‫أي أن لغات البمجة الت تعتمد على الفس، يكون مفسها موجود دائما ليفحص سلسلة نصتتية ملثتتل تعليمتتة متتن اللغتتة نفستتها.‬ ‫يصبح من المكن بناء بضعة أسطر برمجية متن الهيكتل البامتج دينتاميكي للغايتتة. فتتي اللثتال بالستتفل، نحتن استتخدمنا الدالتتة‬ ‫‪ ()eval‬لفحص التعبي الرياض الذي تم إدخاله من قبل الستخدم، ثم نظهر نحن نتيجة .‬
‫تمرين يستخدم مكتبة رسومية ‪ tkinter‬ووظحدة ‪# math‬‬ ‫* ‪from tkinter import‬‬ ‫* ‪from math import‬‬ ‫تعريف الحركة التي يجب اتخاذها عندما يفعله المستخدم #‬ ‫مفتاح الدخال عة الذي يقوم يبتحرير ظحقل الدخال : #‬ ‫:)‪def evaluer(event‬‬ ‫))))(‪chaine.configure(text = "Résultat = " + str(eval(entree.get‬‬ ‫---- : البرنامج الرئيسي ----- #‬‫)(‪fenetre = Tk‬‬ ‫)‪entree = Entry(fenetre‬‬ ‫)‪entree.bind("", evaluer‬‬ ‫)‪chaine = Label(fenetre‬‬ ‫)(‪entree.pack‬‬ ‫)(‪chaine.pack‬‬ ‫)(‪fenetre.mainloop‬‬

‫في بداية السكريبت، بدأنا باستدعاء الوحدتي ‪ tkinter‬و ‪،math‬ت هذا الخي ضوري في اللتة الحاستبة متن أجتل تتوفي‬ ‫جميع الدالت الرياضية والعلمية العتادة : الجيب، جيب التمام، الجذر التبيعي، إلخ.‬

‫79‬

‫يبرامج تتوجه ظحسب الظحداث‬

‫بعد ذلك نحن عرفنا الدالة ‪ ،()evaluer‬وهو في الواقع أمر ينفذه البنامج بعد أن يضغط الستخدم على زر الدخال بعد أن‬ ‫يدخل التعليمة الرياضية في حقل الدخال.‬ ‫قيمة جديدة، الحدد بما كتبناه على يميتت علمتتة الستتاوات : موجتتود بهتا سلستتلة نصتية بنيتتت بشتتكل حيتتوي، بمستتاعدة دالتتتي‬ ‫هذه الدالة تستخدم السلوب ‪ ()configure‬لودجة ‪، chaine‬تت لتعديل سمة النص. الستتمة فتتي الستتلؤال يحصتتل إذا علتتى‬
‫63‬

‫مدمجتي في بيلثون : ‪ ()eval‬و ‪ ،()str‬ومرتبطة بودجة لت ‪ : tkinter‬السلوب ‪.()get‬‬ ‫يستخدم ‪ ()eval‬لفحص تعبي بيلثون المرر إليه في سلسلة نصية ، ناتج هذا الفحص في عشكل "رجوع" )إرجاع قيمة(. علتتى‬ ‫سبيل اللثال :‬
‫"3/)8 + 52(" = ‪chaine‬‬ ‫)‪res = eval(chaine‬‬ ‫)5+ ‪print(res‬‬ ‫سلسلة تحتوي على تعبير رياضي #‬ ‫تقييم التعبير الموجود في السلسلة #‬ ‫محتوي المتغير ‪ res‬رقمي >= #‬

‫يستخدم ‪ ()str‬لتحويل تعبي رقمي إلى سلسلة نصية. لقد قمنا باستدعاء هتتذه الدالتتة لن العائتتد الستتابق يقتتوم بإرجتتاع قيمتتة‬ ‫رقمية، ويجب علينا تحويلها إلى سلسلة نصية لنكون قادرين على دمجها مع رسالة ‪.= Résultat‬‬ ‫السلوب ‪ ()get‬يرتبط مع الويدجات للصنف ‪ .Entry‬في برنامجنا الصغي )ملثال(، نحن استخدمنا الودجة من هذا النتتوع‬ ‫للستماح للمستتخدم بإدختال أي عبتارة رقميتتة بمستاعدة لوحتة مفتاتيحه ويقتوم الستلوب ‪ ()get‬بأختذ متدخلت الستتخدم فتتي‬ ‫الودجة.‬

‫نص البنامج الرئيس يحتوي على مرحلة التهيئة، الت تنتهي مع مستقبل الحتتداث )‪ .(mainloop‬ويوجتتد ملثيتتل للنافتتذة‬ ‫‪،()Tk‬تت تحتتتوي علتتى الودجتتات ‪ chaine‬لتملثيتتل بدايتتة متتن الصتتنف ‪ ،()Label‬والودجتتة تتتدخل ملثيتتل بدايتتة متتن الصتتنف‬ ‫‪.()Entry‬‬ ‫تحذير : الودجة الخية تقوم حقا بعملهتتا، وهتذا معنتتاه نقتتل التعتتبي التذي أدخلتته الستتتخدم إلتتى البنامتج، ونحتتن ربطنتتاه متتع‬ ‫الحدث بمساعدة السلوب ‪: ()bind‬‬
‫73‬

‫)‪entree.bind("",evaluer‬‬

‫هذه التعليمة تعن : ربط الحدث - الضغط على زر الدخال - مع الكائن - الدخال -، وتعالجها الدالة ‪.evaluer‬‬

‫63يكن تيطبيق السلوب ‪ ()configure‬لي ودجة موجودة لةتغيي خص ائصه ا‬ ‫73كلومة ‪ bind‬معن اه ا ربط.‬

‫استخدام النوافذ والرسومات‬

‫89‬

‫تم وصف الحتدث فتتي سلستلة نصتية معينتتة )فتي ملثالنتا، يقصتد السلستلة ">‪ ."210: x1, dx, dy = 210, 0, 15 if y1 >210: y1, dx, dy = 210, -15, 0 if x1 ‫ضعه في الحلقة يبعد 05 ميلي ثانية‬ def stop_it(): "arrêt de l'animation" global flag flag =0 def start_it(): "démarrage de l'animation" global flag if flag ==0: # ‫لكي ل يتم تشغيل سوى ظحلقة واظحدة‬ flag =1 move() #========== ‫============= البرنامج الرئيسي‬ # ‫: سيتم استخدام هذه المتغيرات كمتغيرات عامة‬ x1, y1 = 10, 10 # ‫الظحداثيات الولية‬ dx, dy = 15, 0 # ‫خطوة الزاظحة‬ flag =0 # ‫العداد‬ ّ # ‫: صنع ودجة الرئيسية الصل‬ fen1 = Tk() fen1.title("Exercice d'animation avec tkinter") # ‫: صنع ودجة الفطفال‬ can1 = Canvas(fen1,bg='dark grey',height=250, width=250) can1.pack(side=LEFT, padx =5, pady =5) oval1 = can1.create_oval(x1, y1, x1+30, y1+30, width=2, fill='red') bou1 = Button(fen1,text='Quitter', width =8, command=fen1.quit) bou1.pack(side=BOTTOM) bou2 = Button(fen1, text='Démarrer', width =8, command=start_it) bou2.pack() bou3 = Button(fen1, text='Arrêter', width =8, command=stop_it) bou3.pack() # ‫: )يبدء متلقي الظحداث )الحلقة الساسية‬ fen1.mainloop()

110

‫111‬

‫رسوم متحركة تلقائية‬

‫الشء الجديد في هذا السكريبت يقع عند نهاية تعريف الدالة ‪ : ()move‬هتتل لحظتتت استتتخدام الستتلوب ‪ .()after‬يمكتتن‬ ‫تطتتتبيق هتتتذا الستتتلوب علتتتى أي ودجتتتة. هتتتذا يتستتتبب فتتتي استتتتدعاء الدالتتتة بعتتتد فتتتتة زمنيتتتة معينتتتة. علتتتى ستتتبيل اللثتتتال،‬ ‫‪ (window.after(200,qqc‬تقوم الودجة ‪ window‬باستدعاء الدالة ‪ ()qqc‬بعد توقف دام 002 ميلي ثانية.‬ ‫في السكريبت الخاص بنا، الدالة الت تم استدعاؤها متتن قبتتل الستتلوب ‪ ()after‬هتتي الدالتتة ‪ ()move‬نحتتن استتتخدمنا هنتتا‬ ‫ما يحدث عندما تستدعي الدالة نفسها. وبالطبع سوف نحصل على حلقتتة يمكتتن أن تستتتمر إلتى متا لنهايتتة إذا لتم تضتع طريقتتة‬ ‫لوقفها.‬ ‫دعونا نرى كيف يعمل في ملثالنا.‬ ‫يتم استدعاء الدالة ‪ ()move‬للمرة الولى عندما يتم النقر علتتى زر البتتدء ) ‪ .(Démarrer‬ستتتبدأ عملهتتا )و هتتذا معنتتاه وضتتع‬ ‫الكرة(. ثم، من خلل السلوب ‪،()after‬تت الت يتم استدعاؤها بعد فاصل قصي. ثم تبدأ التتدورة اللثانيتتة، التتت ستتوف تستتتدعي‬ ‫نفسها مرة أخرى، وهكذا إلى أجل غي مسمى.‬ ‫هذا على القل ما سيحدث إذا لم نتخذ الحتياطات اللزمة لوضع تعليمتتة الختتراج فتتي مكتان متتا. فتتي هتذه الحالتتة، هتتذا اختبتار‬ ‫شطي بسيط : في كل حلقة، نحن نفحص محتويات التغي ‪ flag‬بمساعدة العبارة ‪ .if‬فإذا كان محتوى التغي ‪ flag‬سوف‬ ‫تتوقف الحلقة ويتوقف تحريك الرسوم. لحظ أننا حرصنا على تعريتف التغيتت ‪ flag‬علتتى أنته متغيتت عتام. وبالتتالي يمكننتتا‬ ‫تغيي قيمته بسهولة بمساعدة دالت أخرى، ملثل تلك الرتبطة بأزرار بدء وإيقاف.‬ ‫حصلنا على ألية بسيطة لتشغيل وإيقاف الرسوم التحركة : عند الضغطة الولى على زر البدء سيتم تعيي قيمتتة ليستتت لصتتفر‬ ‫للمتغي ‪،flag‬ت ثم سيتم استدعاء لول مرة الدالة ‪ .()move‬الت ستتعمل، وستستتدعي نفستتها كتل 05 ميلتتي ثانيتتة، إلتتى أن‬ ‫يكون قيمة التغي ‪ flag‬صفر. فإذا استمررت بالضغط على زر البتدء ، لتن يتتم استتدعاء الدالتتة ‪ ()move‬لن قيمتتة التغيتت‬ ‫الزر توقف )‪ (Arrêter‬يعي للمتغي ‪ flag‬القيمة صفر، وتتوقف الحلقة .‬ ‫‪ flag‬هي 1. ولذلك سوف تبدأ حلقة مرات عديدة.‬ ‫للمرة الولى تقنية برمجة قوية جدا وتدعى )الستدعاء الذاتي - ‪ .(récursivité‬لجعله بسيط، نقتول إن الستتدعاء التذاتي هتو‬

‫تمارين‬
‫8.22 في الدالة ‪ ،()start_it‬احذف التعليمة 0 == ‪) :if flag‬و السطرين التاليي اللذين يبدأن بمسافة البادئة (. ماذا‬ ‫حدث ؟ )اضغط مرات عديدة على زر البدء. حاول أن تتكلم بأكب قدر من الوضوح لتفسي لاذا حدث .‬ ‫8.32 عدل البنامج بحيث يتغي لون الكرة في كل دورة.‬ ‫8.42 عدل البنامج بحيث تجعل حركات الكرة منحرفة كما كرة البلياردو )متعرج(.‬

‫استخدام النوافذ والرسومات‬

‫211‬

‫8.52 عدل البنامج لتحصل على حركات أخرى. على سبيل اللثال حركة دائرية )كما في التمرين صفحة 901(.‬ ‫8.62 عدل البنامج، أو اكتب واحدا مشابها له، لحاكاة سقو ط الكرة )بسبب الجاذبية( وارتدادها. تنبيه : هذه الرة يجب أن‬ ‫تكون الحركة متسارعة )تزداد السعة مع الوقت(.‬ ‫8.72 بداية من السكريبتات الذكورة أعله، يمكنك الن كتابة لعبة تعمل على النحتتو التتتالي : كتترة تتحتتر،ك بشتتكل عشتتوائي‬ ‫على اللوحة، بسعة بطيئة. يجب على اللعب الضغط على الكرة باستتتخدام الفتتأرة. فتتإذا نجتتح، يحصتتل علتتى نقطتتة،‬ ‫لكن الكرة تزداد سعتها، وهكذا. أوقف اللعبة بعد عدد معي من النفرات وقم بعرض النتيجة .‬ ‫8.82 غي من السكريبت السابق : في كل مرة ينجح فيها اللعب في القبض على الكترة يصتبح حجمهتتا أصتتغر )يمكتن أيضتا‬ ‫تغيي لونها(.‬ ‫8.92 اكتب البنامج الذي به العديد من الرات مختلفة اللون، والت تقفز في كل مكان، وعلى الجدران .‬ ‫8.03 اصنع لعبة ملثالية من خلل السكريبتات السابقة، من خلل دمج الخوارزميات أعله. يجب على اللعب الضتتغط فقتتط‬ ‫على الكرات الحمراء. وإذا نقر بالخطأ على كرة من لون آخر يفقد بضعة نقا ط.‬ ‫8.13 اكتتتب البنامتج التذي يحتاكي اثنيتت متن الكتتواكب التت تتدور حتول الشتمس فتي متدارات دائريتة مختلفتة )أو إثنيتت متن‬ ‫اللكتونات الت تدور حول نواة الذرة ...(.‬ ‫8.23 اكتب برنامجا للعبة اللثعبان : ثعبان )يتكون من خط قصي من الربعات( يتحر،ك علتتى اللوحتتة فتتي أربعتتة اتجاهتتات :‬ ‫يسار ويمي وأعلى وأسفل. يمكن لللعب تغيي اتجاه اللثعبان من خلل السهم في لوحة الفاتيح. وفي القماش يوجتتد‬ ‫أيضا "الفريسة" )دوائر صغية مرتيتتة عشتتوائيا(. يجتتب علتتى اللثعبتتان أن يأكتتل الفريستتة دون أن يصتطدم متتع حتتواف‬ ‫اللوحة. في كل مرة يأكل فيها فريسة يزداد اللثعبان طول، ويربح اللعب نقطة ، وتظهر الفريسة جديدة في مكان آخر.‬ ‫اللعبة تتوقف عندما يلمس اللثعبان أحد الجدران أو عندما يصل إلى طول محدد.‬ ‫8.33 طور اللعبة السابقة بإضافة : تتوقف اللعبة إذا تداخل اللثعبان .‬

‫9‬
‫9التعاةمل ةمع الملفات‬
‫حت الن، جميع البامج الت صنعناها ل تتعامل سوى مع كمية صغية جدا من البيانات. وفتي كتتل مترة نريتتد أن نتعامتتل متتع‬ ‫هذه البيانات نضعها في جسم البنامج نفسه)على سبيل اللثال في قائمة(. هذه الطريقة غي كافيتتة إلتتى حتتد بعيتتد عنتتدما نريتتد‬ ‫التعامل مع كمية أكب ومهمة من العلومات .‬

‫فائدة الملفات‬ ‫لنفتض على سبيل اللثال أننا نريد كتابتتة برنامتتج صتتغي يظهتتر علتتى الشاعشتتة أستتئلة متعتتددة الخيتتارات، متتع معالجتتة تلقائيتتة‬ ‫لردود الستخدم. كيف يمكننا تخزين نص السئلة ؟‬ ‫أبسط فكرة هي وضع كل نص في متغي، في بداية البنامج، مع عبارات التعيي، ملثل :‬
‫"? ‪a = "Quelle est la capitale du Guatemala‬‬ ‫"? ‪b = "Qui à succédé à Henri IV‬‬ ‫"? 34 ‪c = "Combien font 26 x‬‬ ‫.‪... etc‬‬

‫للسف هذه الفكرة بسيطة جدا. وسيصبح باقي البنامج معقدا جدا، هتتذا معنتتاه أن التعليمتتات التتت ستتيتم استتتخدامها لختيتتار‬

‫سلؤال أو أكتث بشتكل عشتتوائي ليتتم تقتديمه للمستتخدم. ستوف تستتخدم علتتى ستبيل اللثتال مجموعتتة طويلتة متن عبتارات ... ‪if‬‬
‫‪ ... elif ... elif‬كما في اللثال في السفل وهو بالتأكيد ليس الحل الجيد )و سيكون متعبتا جتدا فتي الكتابتتة، ل تنستت أيضتا‬ ‫كتابة معالجة )إجابة( كل هذه السئلة! ( :‬
‫:1 == ‪if choix‬‬ ‫‪selection = a‬‬ ‫:2 == ‪elif choix‬‬ ‫‪selection = b‬‬ ‫:3 == ‪elif choix‬‬ ‫‪selection = c‬‬ ‫.‪... etc‬‬

‫511‬

‫فائدة الملفات‬ ‫سيكون أفضل إذا استخدمنا القوائم :‬

‫,"? ‪liste = ["Qui a vaincu Napoléon à Waterloo‬‬ ‫,"? ‪"Comment traduit-on ’informatique’ en anglais‬‬ ‫]... ‪"Quelle est la formule chimique du méthane ?", ... etc‬‬

‫يمكن للمرء أن يستخرج أي عنص من هذه القائمة باستخدام اللؤش. على سبيل اللثال :‬
‫)]2[‪print(liste‬‬ ‫>===‬ ‫"? ‪"Quelle est la formule chimique du méthane‬‬

‫تذكير‬ ‫العداد يبدأ من الصفر‬ ‫في حي أن هذه الطريقة أفضل بكلثي من الطريقة السابقة، لكن مازلنا نواجه العديد من الشاكل الزعجة :‬ ‫• إن قابلية قراءة هذا البنامج تتدهور بسعة كبية عندما يصبح عدد السئلة كبي جدا. وطبعا، سوف نزيد متتن احتماليتتة‬ ‫إدراج خطأ في تعريف هذه القائمة الطويلة . بعض الخطاء قد يصعب جدا العلثور عليها.‬ ‫• إضافة أسئلة جديدة، أو تعديل على السئلة الوجودة ، يجب علينتتا فتتي كتل مترة فتتح النتص الصتدري للبنامتج. وطبعتا‬ ‫سيصعب إعادة صياغة التعليمات البمجية في النص الصدري، لنه يشمل العديد من السطر الت بها معطيات معقدة.‬ ‫• تبادل البيانات مع برامج أخرى )ربما كتبت بلغات برمجة أخرى( هو بكتتل بستتاطة مستتحيل، لن هتذه البيانتات هتي جتزء‬ ‫من البنامج نفسه .‬ ‫ملحظة أخية : حان الوقت لنتعلم فصل البيانات والبامج الت تعالجها في ملفات مختلفة.‬ ‫ليكون هذا ممكنا، سوف نقدم مجموعة متنوعة من الليات لنشاء اللفات وإرسال البيانات وإستجاعها في وقت آخر.‬ ‫لغات البمجة تعرض تعليمات أكث أو أقل تعقيدا لداء هذه الهام. عندما يتم التعامل مع مجموعات كبية متن البيانتات، يكتون‬ ‫من الهم )ضوري( تنظيم العلقة بي هذه البيانات ، وعلينا وضع أنظمة تسمى بقواعد البيانات، يمكن أن تكون إدارتها معقدة‬ ‫للغاية. عندما تواجه مشاكل من هذا القبيل، يجب أن تفوض هتذا إلتتى العديتد متتن البامتج التخصصتتة فتتي هتتذا ملثتتل : ،‪Oracle‬‬ ‫‪.... IBM DB2، Sybase، Adabas، PostgreSQL، MySQL‬إلخ. بيلثون يمكنها التواصل مع هذه النظمة، لكن سنت،ك هذا‬ ‫لوقت آخر )انظر : إدارة قواعد البيانات، صفحة 203(.‬ ‫طموحاتنا متواضتعة جتدا. البيانتات التت لتدينا ليستت بمئتات اللف، نكتفتي بأليتة بستيطة لحفتظ البيانتات فتي ملتف متوستط‬ ‫الحجم، ومن ثم استخراجها عندما نحتاجها .‬

‫التعامل مع الملفات‬

‫611‬ ‫العمل مع الملفات‬

‫استخدام اللف يشبه إلى حد كبي استخدام كتاب. لستخدام كتاب، يجب أن تجده أول )بمساعدة اسمه(، ثم يجتتب عليتتك فتحتته.‬ ‫وعندما تنتهتي متن استتخدامه، تقتوم بتإغلقه. وعنتدما يكتون مفتوحتا، يمكنتتك قتراءة العلومتات الختلفتتة، ويمكنتتك أيضتا كتابتتة‬ ‫تعليقات توضيحية، لكن عموما لن تقوم بعمل الثني في وقت واحد. في جميع الحالت، يمكنتتك معرفتتة أيتتن وصتتلت فتتي داختتل‬ ‫الكتاب، وذلك بمساعدة أرقام الصفحات. تقرأ معظتتم الكتتاب باتبتاع نظتتام الصتفحات، لكتن يمكنتتك أيضتا قتتراءة أي فقتترة بشتتكل‬ ‫مضطرب.‬ ‫كل ما قلناه عن الكتب ينطبق أيضا على ملفات الحاسوب .اللف يتكون متن بيانتات مخزنتتة علتتى القتترص الصتلب، أو فتتي قترص‬ ‫مرن، أو في إصبع ‪ usb‬أو فتتي قتترص مدمتج )‪ .( cd‬والتتت يمكنتتك الوصتتول إليهتتا متتن استتمها )و قتتد يشتتمل استم التدليل(. كنظتترة‬ ‫تقريبية، قد تنظر إلى محتويات اللف كأنه سلسلة من الحرف، مما يعن أنه يمكنك التعامل مع هذا الحتوى، أو أي جتتزء منتته،‬ ‫بمساعدة دالت تتعامل مع سلسل الحرف .‬
‫14‬

‫اسم الملف - الدليل الحاليء‬ ‫لتبسيط التفسيات الت تلي، سوف نقوم بتوضيح فقط السماء البسيطة للملفات الت ستتوف تعامتتل معهتتا. إذا كنتتت تفعتتل هتتذا‬ ‫في تمارينك، اللفات سوف يتم صنعها و\أو يتم البحث عنها من قبل بيلثون فتتي التتدليل الحتتالي. عتتادة متتا يكتتون هتتذا التتدليل فتتي‬ ‫نفس مكان السكريبت، إل إذا كنت تشغل السكريبت من خلل نافتذة ال ‪ ،IDLE‬فتي هتذه الحالتة، يتتم تعييتت التدليل الحتتالي عنتد‬ ‫تشغيل ال ‪) IDLE‬في ويندوز، تعريف هذا الدليل هو جزء من خصائص أيقونة التشغيل(.‬ ‫إذا كنت تعمل مع ‪ ، IDLE‬فإنك بالتأكيد تريد إجبار بيلثون تغيي الدليل الحالي، بحيث يكون ملثلمتتا تريتتده. وللقيتتام بتتذلك، يجتتب‬ ‫عليك كتابة الوامر التالية عند بداية الحصة. نحن نفتض أن التدليل التذي تريتتده هتتو /‪ .home/jules/exercices‬حتتت لتتو‬ ‫كنت تعمل في نظام ويندوز ) وهذه ليست قاعدة(، يمكنك استخدام نفس التعليمة ) ولكن يجب عليك استخدام \ بدل من / : لن‬ ‫الولى تعمل فقتط علتتى أنظمتتة ‪ .(UNIX‬بيلثتون ستيقوم بتتالتحويلت اللزمتتة، هتذا إذا كنتتت تعمتتل علتتى ‪ Mac OS‬أو ‪ Linux‬أو‬ ‫‪. Windows‬‬
‫24‬

‫‪>>> from os import chdir‬‬ ‫)"‪>>> chdir("/home/jules/exercices‬‬

‫14‬ ‫بعب ارة أد ق, يب عليك أن تأخذ بعي العةتب ار أن مةتوى اللف هو تسلسل من الب ايةت ات. معظم الب ايةت ات ماثلة بواسيطة رموز,‬ ‫والعكس غي صحيح : سوف نةتعلم ف ن اية اليط اف الةتومييز الواضح بي سلسل الب ايةت ات والسلسل النصية .‬ ‫24 ف ح الة اسةتخدامك لنظ ام ترشغيل ويندوز, يكنك تضومي ف هذا الس ار الرس الة الت تعي جه از الةتخزين حيث يوجد اللف. على‬ ‫سبيل الاث ال: ‪.D:/home/jules/exercices‬‬

‫711‬

‫اسم الملف - الدليل الحالي‬

‫المر الول يستدعي الدالة ‪ ()chdir‬من وحدة ‪ .os‬تحتوي وحدة ‪ os‬عل جميع الدالت الت تتعامل متتع أنظمتتة التشتتغيل )‬ ‫‪ ،(os = operating system‬أي نظام تشغيل( بغض النظر عن نوعه.‬ ‫المر اللثاني يتسبب في تغيي الدليل ) ‪.(chdir =change directory‬‬ ‫‪ ‬يمكنك أيضا إدراج هذه الوامر )التعليمات( في بداية البرنامــج النصـي، أو تحديــد اسـم المســار الكامــل للملـف‬ ‫‪ ‬اختر أسماء ملفات قصيرة. تجنب قدر المكان الحرف المعلمة والمسافات والعلمات المطبعية الخاصة. في‬ ‫بيئات عمل اليونكس )ماك، لينكس، ‪ ،(... BSD‬ينصح في أغلب الحيان باستخدام الحرف الصغيرة فقط .‬ ‫الذي تريد معالجته، ولكن هذا قد يكون خطر على ثقل الكتابة في برامجك.‬

‫شكلي الستدعاء‬ ‫أسطر التعليمات الت سوف نستخدمها هي فرصة لشح آليات ملثية للهتمام. أنتت تعتترف أنته بالضتتافة إلتتى التدالت الدمجتتة‬ ‫في الوحدات الساسية، بيلثون يوفر لك كمية هائلة من الدالت الخاصة، والت تم تجميعها في وحدات. من الوحدات الت عرفتها‬ ‫الوحدة ‪ math‬والوحدة ‪.tkinter‬‬ ‫لستخدام الدالت من وحدة، يجب عليك استدعائها. لكن هتتذا يتتم بطريقتتي مختلفتتتي، كمتتا ستنى بالستفل، كتتل واحتدة لتديها‬ ‫ممياتها وعيوبها.‬ ‫هذا ملثال على الطريقة الولى :‬
‫‪>>> import os‬‬ ‫)(‪>>> rep_cour = os.getcwd‬‬ ‫‪>>> print rep_cour‬‬ ‫‪C:\Python22\essais‬‬

‫في السطر الول من هذا اللثال نحتن نستتتدعي الوحتدة ‪،os‬ت التت تحتتتوي علتى وظتائف كتلثية متلثية للهتمتام التت تستمح لنتا‬ ‫بالوصتتول إلتتى نظتتام التشتتغيل. أمتتا الستتطر اللثتتاني فهتتو يستتتخدم الدالتتة ‪ ()getcwd‬متتن وحتتدة ‪ . os‬كمتتا تتترون، الدالتتة‬ ‫‪ ()getcwd‬تقوم بإرجاع اسم الدليل الحالي ) ‪ .(getcwd = get current working directory‬للمقارنة، هذا‬ ‫ملثال على الطريقة اللثانية :‬
‫‪>>> from os import getcwd‬‬ ‫)(‪>>> rep_cour = getcwd‬‬
‫34‬

‫34 النقيطة الف اصلة تعب هن ا عن علقة النةتوم اء. وهذا ماث ال على الس اء الؤهلة الت سيةتم اسةتخدامه ا على نيط ا ق واسع ف م ا‬ ‫تبقى من هذه الدورة. ربط الس اء بس اعدة النق اط هي وسيلة ل بأس ب ا للعن اصر الت ترشكل جزءا من الجوموع ات, والت هي‬ ‫رب ا قد تكون من موموعة أكب, وإل. على سبيل الاث ال, تسومية ‪ systeme.machin.truc‬ترشي إل عنصر ‪ ,truc‬والذي هو جزء‬ ‫من الجوموعة ‪ ,machin‬والذي هو جزء من الجوموعة ‪ .systeme‬سوف نرى العديد من الماثلة عن هذه الةتقنية, وخصوص ا عندم ا‬ ‫ندرس أصن اف الك ائن ات .‬

‫التعامل مع الملفات‬
‫)‪>>> print(rep_cour‬‬ ‫‪C:\Python31\essais‬‬

‫811‬

‫في هذا هذا اللثال الجديد، قمنا باستدعاء الدالة ‪ getcwd‬فقط من الوحدة ‪ .os‬بالستدعاء بهذه الطريقة، سيتم دمج الدالتتة‬ ‫مع كود كما لو أننا كتبناه بأنفسنا. في السطر الت نستعملها، ليس من الضوري ذكر جزء الوحدة ‪.os‬‬ ‫و يمكننا استدعاء العديد من الدالت من نفس الوحدة بنفس الطريقة :‬
‫‪>>> from math import sqrt, pi, sin, cos‬‬ ‫)‪>>> print(pi‬‬ ‫95356295141.3‬ ‫))5(‪>>> print(sqrt‬‬ ‫الجذر التريبيعي لـ 5 #‬ ‫5779760632.2‬ ‫))6/‪>>> print(sin(pi‬‬ ‫جيب الزاوية 03 درجة #‬ ‫5.0‬

‫و يمكننا استدعاء كل الدالت من وحدة ، كما في :‬
‫* ‪from tkinter import‬‬

‫لهذه الطريقة مية سهولة كتابة التعليمات البمجية للدالت الت تم إستدعائها. ولديها أيضا عيتتب )خاصتتة فتتي الشتتكل الخيتت،‬ ‫عند استدعاء جميع دالت الوحدة( تشتتوش مستتاحة الستم الحتالي. قتد تكتتون بعتتض التدالت التت استتدعيتها لتديها نفتتس استم‬ ‫التغي الذي عرفته أنت، أو نفس اسم دالة تم إستدعائها من وحدة أخرى. فإذا حدث هذا، واحد من السمي التضتتاربي لتتن يتتتم‬ ‫الوصول إليه بشكل جيد.‬ ‫في البامج الت لديها بعض الهمية، والت تستدعي عددا كتبيا متن وحتدات متن مختلتف الصتتادر، ستيكون متن الفضتتل لهتا أن‬ ‫تستخدم الطريقة الولى، وهذا معناه استخدام أسماء ملؤهلة بشكل كامل.‬ ‫عموما، يوجد استلثناءات لهذه القاعدة في حالة معينة من الوحدة ‪ ،tkinter‬لنه يحتوي على دالت مطلوبة بشدة )عندما تقتترر‬ ‫استخدام هذه الوحدة(.‬ ‫كتابة متسلسلة في ملف‬ ‫في بيلثون، يتم توفي الوصول إلى اللفات عن طريق كائن الواجهة خاصة، الت تسمى كائن اللف. نحن نقوم بصنع هتتذا اللتتف‬ ‫باستخدام الدالة الدمجة ‪ . ()open‬الت تقوم بإرجاع الكائن متتع أستاليب محتتددة، والتتت تستتمح لتتك بقتتراءة وكتابتتة فتتي هتتذا‬
‫44‬

‫اللف.‬

‫44هذه الدالة, هي قيومة رجوه لك ائن معي, وغ الب ا م ا تسومى مصنع الدالة‬

‫911‬

‫كتايبة متسلسلة في ملف‬

‫اللثال الت يوضح كيفية فتح ملف ، ثم كتابة سلسلتي نصيتي فيه، ثتتم إغلقتته. لحتتظ أن إذا كتتان اللتتف غيتت موجتتود فستتوف‬ ‫ستم إنشاءه تلقائيا. ومن جهة أخرى، وإذا كان اللف موجود بالفعل وبه بعض البيانات، الحتتروف التتت ستتوف تستتجلها ستتتكون‬ ‫بعد الوجودة. يمكنك أن تقوم بهذا التمرين مباشة على سطر الوامر :‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫)'‪obFichier = open('Monfichier','a‬‬ ‫)'! ‪obFichier.write('Bonjour, fichier‬‬ ‫)"! ‪obFichier.write("Quel beau temps, aujourd'hui‬‬ ‫)(‪obFichier.close‬‬

‫ملحظات‬ ‫•السطر الول يقوم بإنشاء ملف الكائن ‪ ،obFichier‬و التتت ستشتتي )مرجتتع( إلتتى اللتتف الحقيقتتي)علتتى القتترص أو علتتى‬ ‫القرص الرن( وهتتو ستيكون استمه ‪ .Monfichier‬تنتبيه : ل تخلتط بيت استم اللتف متع استم كتائن اللتف التذي يتيتح‬ ‫الوصول إليه ! بعد هذا التمرين، يمكنك التحقق من أن هذا اللف تم إنشاؤه في نظامك )في الدليل الحالي( استم اللتتف هتتو‬ ‫‪) Monfichier‬و الذي تستطيع عرض محتواه مع أي محرر( .‬ ‫•الدالة ‪ ()open‬تنتظر برامتين ، و الذين يجب أن يكونا سلسلتي نصيتي. البامت الول سيكون اسم اللف الذي يجتتب‬
‫54‬

‫)‪ ،(append‬وهتتذا يعنتت أن البيانتتات‬

‫فتحه، واللثاني هو اسم وضع الفتح. '‪ 'a‬يشي إلى فتح اللتتف بوضتتع إضتتافة‬

‫الت سيتم حفظها سيتم إضافتها إلى نهاية اللف، إضافة إلى الت هي موجودة بالفعل. نستطيع أيضتتا استتتخدام الوضتتع '‬ ‫‪) 'w‬للكتابة - ‪ ،( write‬لكن عند استخدام هذا الوضع، سيقوم بيلثون بصنع ملف جديد )فارغ(، ويكتب فيه البيانات، بدايتتة‬ ‫• السلوب ‪ ()write‬يكتب فعليا. ويجب أن تكون البيانات الت يجب كتابتها كبامت. هذه البيانات يتم حفظها فتتي اللتف‬ ‫واح دا بعد الخر ) نحن نتحدث هنا عن الوصول التسلسل للملف(. عند كل استدعاء للدالة ‪ ()write‬تستتتمر الكتابتة فتتي‬ ‫ً‬ ‫اللف )مع الوجود بالفعل(.‬ ‫•السلوب ‪ ()close‬تغلق اللف. وهي متاحة لجميع الستعمالت .‬ ‫قراءةء متسلسلة من الملف‬ ‫سوف نقوم الن بإعادة فتح اللف، لكن هذه الرة، من أجل قراءة العلومات الت سجلناها في الخطوة السابقة :‬
‫)'‪>>> ofi = open('Monfichier', 'r‬‬ ‫)(‪>>> t = ofi.read‬‬ ‫)‪>>> print(t‬‬ ‫! ‪Bonjour, fichier !Quel beau temps, aujourd'hui‬‬ ‫)(‪>>> ofi.close‬‬

‫من بداية اللف. فإذا وجد ملفا بنفس السم، يتم مسحه وصنع ملف جديد.‬ ‫ً‬

‫يكن إض افة برامةتر ث الث للش ارة إل الةترميز الةتسةتخدم )انظر إل صفحة 341(.‬

‫54‬

‫التعامل مع الملفات‬

‫021‬

‫كما كان متوقعا، السلوب ‪ ()read‬يقرأ البيانات في اللف ويحوله إلى متغي من نوع سلسلة نصية) ‪ .(string‬فإذا استخدمنا‬ ‫هذا السلوب بدون برامتات، يتم نقل كامل محتويات اللف .‬ ‫ملحظات‬ ‫•اللف الذي نريد استدعائه لقرائته يدعى ‪ .Monfichier‬يجب علينا أن نكتب تعليمة فتح اللف ليشي إلى اللف. فإذا‬ ‫كان اللف غي موجود سوف تحصل على رسالة خطأ. على سبيل اللثال :‬
‫)'‪>>> ofi = open('Monficier','r‬‬ ‫'‪IOError: [Errno 2] No such file or directory: 'Monficier‬‬

‫•من جهة أخرى، نحن غي ملزمي باختيار اسم محدد لكائن اللف. نستطيع اختيتار استم أي متغيت. وبالتتالي فتتي تعليمتنتا‬ ‫الولى نحن قمنا بصنع كائن ملف وسميناه ‪ ،ofi‬والذي ستيكون إعشتارة للملتف الصتتلي ‪ ،Monfichier‬والتذي ستوف‬ ‫يتم فتحه للقراءة منه )البامت ’‪.(’r‬‬ ‫• السلسلتان النصيتان اللتان وضعناهما قي اللف تم دمجهما في سطر واحد. هذا طبيعي، لننا لم نستتتخدم أي رمتتز ختتاص‬ ‫عندما قمنا بحفظه. سوف نتعرف لحقا على طريقة حفظ أسطر منفصلة‬ ‫• السلوب ‪ ()read‬يمكننا استخدامه مع برامتت. وستوف يشتي إلتى عتدد الحتروف التت يجتتب أن تقترأ. بدايتة متن الوقتتع‬ ‫الوجود بالفعل في اللف :‬
‫)'‪>>> ofi = open('Monfichier', 'r‬‬ ‫)7(‪>>> t = ofi.read‬‬ ‫)‪>>> print(t‬‬ ‫‪Bonjour‬‬ ‫)51(‪>>> t = ofi.read‬‬ ‫)‪>>> print(t‬‬ ‫‪, fichier !Quel‬‬

‫فإذا لم يكن ما يكفي من الحروف في اللف، تتوقف القراءة في نهاية اللف :‬

‫•‬

‫)0001(‪>>> t = ofi.read‬‬ ‫)‪>>> print(t‬‬ ‫! ‪beau temps, aujourd'hui‬‬

‫فإذا تم الوصول بالفعل إلى نهاية اللف، فإن ‪ ()read‬تقوم بإرجاع سلسلة فارغة :‬
‫)(‪>>> t = ofi.read‬‬ ‫)‪>>> print(t‬‬

‫)(‪>>> ofi.close‬‬

‫•ل تنس إغلق اللف بعد استعماله‬ ‫َ‬

‫121‬

‫قراءة متسلسلة من الملف‬ ‫في كل ما سبق، لقد افترضنا دون شرح أن السلسل النصية يتم تبادلها بين مفسر بيثون والملف. وهــذا فــي‬

‫الواقع غير صحيح، لن السلسل النصية يتم تحويلها إلى سلسل بايتات ليتم تخزينها في ملفــات. وبالضــافة‬ ‫معيــار الــترميز الــذي يجــب اســتخدامه فــي ملفاتــك : ســنرى كيــف يمكننــا فعــل هــذا فــي الفصــل القــادم. فــي‬

‫إلــى ذلــك، هنالــك للســف معــايير مختلفــة لهــذا الغــرض. بــالمعنى الــدقيق، فــي بيثــون ينبغــي أن يكــون واضــحا‬

‫غضون ذلك، يمكنك العتماد على بيثون لن بيثون يستخدم المعيار الفتراضي لنظامك، وهـذا سـوف يجنبـك‬

‫المشاكل في التمارين الولى. ومـع ذلـك، إذا كـانت بعـض المعلمـات تظهـر بشـكل غريـب، يرجـى تجاهـل هـذا‬

‫مؤقتا .‬

‫العبارة ‪ break‬للخرلوج من الحلقة‬ ‫ليس علينا القول أننا بحاجة إلى حلقات في البنامج عندما نتعامل مع ملف ل نعرف محتوياته. والفكرة هي قراءة اللف جزءا‬ ‫ً‬ ‫جزءا حت نصل إلى نهاية اللف.‬ ‫ً‬ ‫الدالة الت بالسفل تشح هذه الفكرة. فهي تقوم بنسخ ملف بأكمله )بغض النظر عن حجمتته( متتن خلل نقتتل 05 حتترف فتتي كتتل‬ ‫مرة :‬
‫:)‪def copieFichier(source, destination‬‬ ‫"‪"copie intégrale d'un fichier‬‬ ‫)'‪fs = open(source, 'r‬‬ ‫)'‪fd = open(destination, 'w‬‬ ‫:1 ‪while‬‬ ‫)05(‪txt = fs.read‬‬ ‫:""== ‪if txt‬‬ ‫‪break‬‬ ‫)‪fd.write(txt‬‬ ‫)(‪fs.close‬‬ ‫)(‪fd.close‬‬ ‫‪return‬‬

‫فإذا أردت اختبار هذه الدالة، يجب عليك توفي دالتي : الول اسم اللتتف الصتتلي، واللثانيتتة استتم اللتتف التتذي تريتتد الستنستتاخ‬ ‫إليه. على سبيل اللثال :‬
‫)'‪copieFichier('Monfichier','Tonfichier‬‬

‫ستلحظ أننا عندما قمنا ببناء الحلقة، استخدمنا طريقة مختلفة عن الت عرفناها سابقا. كمتتا تعلتتم أن العبتتارة ‪ while‬يجتتب‬ ‫دائما أن تلحقها الش ط لتقييمه ، ويتم تنفيذ الكتلة الت تليه في الحلقة، مادامت هذه الدالة صحيحة. ولكننا هنا قمنا باستتتبدال‬ ‫الش ط التحقق برقم بسيط، وأنت تعرف أن مفس بيلثون يعتب أي قيمة غي الصفر قيمة صحيحة.‬
‫64‬

‫حلقة ‪ while‬بالعلى سوف تعمل لجل غي مسمى، لن الش ط يبقى دائما صحيحا. ومع ذلك، يمكننا أن نقطع هذه الحلقة‬ ‫باستخدام عبارة ‪ ،break‬وربما يجب علينا أن نضع عدة عبارات توقف في عدة أماكن :‬
‫64انظر إل صفحة 65 : تعبي حقيقي\مزيف‬

‫التعامل مع الملفات‬
‫: >1 ‪while 2 ‪if 3 ‪if >>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫)"‪f = open("Fichiertexte", "w‬‬ ‫)"‪f.write("Ceci est la ligne un\nVoici la ligne deux\n‬‬ ‫)"‪f.write("Voici la ligne trois\nVoici la ligne quatre\n‬‬ ‫)(‪f.close‬‬

‫لحظ أن في نهاية السطر \‪ n‬حيث يتم إدراجها في السلسل النصية، حت نفصل بي أسطر النص السابق عندما نقوم بحفظه.‬ ‫من دون هذه العلمة، سوف يتم حفظ الحروف واحدا بعد الخر، كما في الملثلة السابقة.‬ ‫عند قراءة اللف، أسطر اللف يمكن أن يتم استاجاعها بشكل منفصل عن بعضتهم. عتن طريتق الستلوب ‪،()readline‬ت علتى‬ ‫سبيل اللثال، لن يقرأ هنا سوى سطر واحد في كل مرة )بما في ذلك علمة نهاية السطر( .‬
‫74‬ ‫ب العن الدقيق, وكوم ا تن اولن ا ملف يةتوي على "ب ايةت ات ق ابلة لليطب اعة" الت قيومه ا يكنه ا أن متاثل رموز طب اعية ف ترميز مدد‬ ‫جدا. سوف نن اقش هذا بةتفصيل أكاثر ف الفصل الق ادم. تديدا, هو بيةت ات ذات قيومة رقومية م ا بي 23 و 552. والب ايةت ات للقيومة‬ ‫أقل من 23 هي رموز قدية للةتحكم وعوموم ا ل يكن متاثيله ا بواسيطة أحرف .‬ ‫84 اعةتوم ادا على نظ ام الةترشغيل السةتخدم, الةترميز الوافق لنه اية السيطر قد يكون مةتلف ا. وعلى سبيل الاث ال, ف نظ ام ترشغيل ويندوز‬ ‫هن الك تسلسل إثني من الب ايةت ات )رمز الرج اع وقفز السيطر(, ف حي أن أنظومة الةترشغيل من نوع يونكس )ماثل لينكس( يكفي أن تضع‬ ‫القفز السيطر, أم ا ف "م اك" فهو يسةتخدم رمز الرجوع. من حيث البدأ, ل يوجد م ا يدعو للقلق حول هذه الخةتلف ات. من خلل‬ ‫عوملي ات الكةت ابة, يسةتخدم بياثون اتف اقية موجودة ف نظ امك. للقراءة, يقوم بياثون بةتصحيحه ا حسب التف اقية )م ا يع ادل ا( .‬

‫321‬
‫)'‪>>> f = open('Fichiertexte','r‬‬ ‫)(‪>>> t = f.readline‬‬ ‫)‪>>> print(t‬‬ ‫‪Ceci est la ligne un‬‬ ‫))(‪>>> print(f.readline‬‬ ‫‪Voici la ligne deux‬‬

‫ملفات نصية‬ ‫ّ‬

‫السلوب ‪ ()readlines‬ينقل جميع السطر التبقية في سلسلة نصية . :‬
‫)(‪>>> t = f.readlines‬‬ ‫)‪>>> print(t‬‬ ‫]'‪['Voici la ligne trois\n', 'Voici la ligne quatre\n‬‬ ‫)(‪>>> f.close‬‬

‫ملحظات‬ ‫• في القائمة أعله تظهر في عشكلها الخام، مع علمة اقتباس واحدة للسلسل، وحروف خاصة في عشكلها التقليدي. ويمكنتتك‬ ‫بالطبع استعراض هذه القائمة )بمساعدة الحلقة ‪ ،while‬على سبيل اللثال( لستخراج السلسل الفردية .‬ ‫•السلوب ‪ ()readlines‬يجعل من المكن قراءة ملف كامل بتعليمة واحد فقط. هذا ليس دائما ممكنتتا، فملثل لتو لتم يكتن‬ ‫اللف كبيا يمكن وضعه فتتي متغيت، وهتذا معنتاه فتتي ذاكترة الوصتتول العشتتوائي للحاستوب، لتذا فمتن الضتوري أن يكتون‬ ‫الحجم كافيا. فإذا كنت في حاجة لعالجتتة ملفتتات ضتتخمة، وتريتتد أستتخدام الستتلوب ‪ ()readline‬فتتي حلقتتة، كمتتا فتتي‬

‫اللثال التالي.‬

‫•لحظ أن ‪ ()readline‬هو أسلوب يرجع سلسلة نصية، في حي أن ‪ ()readlines‬ترجع قائمة. فتتي نهايتتة اللتتف،‬ ‫‪ ()readline‬تقوم بإرجاع قناة فارغة، في حي أن ‪ ()readlines‬تقوم بإرجاع سلسلة فارغة.‬ ‫السكريبت التالي يوضح كيفية إنشاء دالة للتعامل مع اللفات النصتية. فتتي هتذه الحالتة، ستوف يقتوم باستنستتاخ اللتف النصتت‬ ‫وسيحذف جميع السطر الت تبدأ برمز ’#’ :‬
‫:)‪def filtre(source,destination‬‬ ‫"‪"recopier un fichier en éliminant les lignes de remarques‬‬ ‫)'‪fs = open(source, 'r‬‬ ‫)'‪fd = open(destination, 'w‬‬ ‫:1 ‪while‬‬ ‫)(‪txt = fs.readline‬‬ ‫:''== ‪if txt‬‬ ‫‪break‬‬ ‫:'#' =! ]0[‪if txt‬‬ ‫)‪fd.write(txt‬‬ ‫)(‪fs.close‬‬ ‫)(‪fd.close‬‬ ‫‪return‬‬

‫لستدعاء هذه الدالة، يجب عليك استخدام برامتين : اسم اللف الصلي، اسم اللف الذي سيتلقى النسخة الت تمت تصتتفيتها.‬ ‫على سبيل اللثال :‬

‫التعامل مع الملفات‬
‫)'‪filtre('test.txt', 'test_f.txt‬‬

‫421‬

‫تسجيل لوعرض مختلف المتغيرات‬ ‫البامت الستخدم مع السلوب ‪ ()write‬في اللف النص يجب أن يكون سلسلة نصية. مع التتذي تعلمنتتاه حتتت الن، نحتتن ل‬ ‫نستطيع حفظه مع أنواع أخرى من البيانات لذا لنسطيع حفظها في ملف يجب علينا أن نحولهتتا إلتتى سلستتلة نصتتية ) ‪.(string‬‬ ‫يمكننا أن نفعل ذلك بمساعدة الدالة الدمجة ‪: ()str‬‬
‫25 = ‪>>> x‬‬ ‫))‪>>> f.write(str(x‬‬

‫سوف نرى لحقا أنه يوجد طرق أخرى لتحويل قيم رقمية إلى سلسل نصية )انظر : تنستتيق السلستل النصتية، صتتفحة 941(.‬ ‫لكن السلؤال ليس هنا. إذا قمنا بحفظ قيم رقمية بتحويلها أول إلى سلسل نصية، سوف نستطيع إذن أن نعيد تحويلها إلى قيتتم‬ ‫رقمية عندما نقوم بقراءة اللف. على سبيل اللثال :‬
‫5 = ‪>>> a‬‬ ‫38.2 = ‪>>> b‬‬ ‫76 = ‪>>> c‬‬ ‫)'‪>>> f = open('Monfichier', 'w‬‬ ‫))‪>>> f.write(str(a‬‬ ‫))‪>>> f.write(str(b‬‬ ‫))‪>>> f.write(str(c‬‬ ‫)(‪>>> f.close‬‬ ‫)'‪>>> f = open('Monfichier', 'r‬‬ ‫))(‪>>> print(f.read‬‬ ‫7638.25‬ ‫)(‪>>> f.close‬‬

‫لقد قمنا بحفتظ ثلثتة قيتم رقميتتة. لكتن كيتف يمكننتتا التميتت بيت السلستل النصتية الناتجتتة، عنتدما نقتوم بتشتغيل اللتف ؟ هتذا‬ ‫مستحيل ! ل شء يشي إلى أنه يوجد 3 قيم بدل من واحدة أو 2 أو 4 ....إلخ‬ ‫هنالتتك عتتدة حلتتول لهتتذه الشتتكلة. أفضتتلها هتتو استتتدعاء وحتتدة بيلثتتون متخصصتتة : الوحتتدة ‪ . pickle‬وهتتذا شتتح لكيفيتتة‬
‫94‬

‫استخدامها :‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫‪import pickle‬‬ ‫]"‪a, b, c = 27, 12.96, [5, 4.83, "René‬‬ ‫)'‪f =open('donnees_test', 'wb‬‬ ‫)‪pickle.dump(a, f‬‬ ‫)‪pickle.dump(b, f‬‬ ‫)‪pickle.dump(c, f‬‬ ‫)(‪f.close‬‬ ‫)'‪f = open('donnes_test', 'rb‬‬ ‫)‪j = pickle.load(f‬‬ ‫)‪k = pickle.load(f‬‬

‫94ف اللغة النكليزية, الصيطلح ‪ pickle‬معن اه "ح افظ". ولقد أطلق هذا السم على هذه الوحدة لن ا تسةتخدم لةتخزين البي ان ات‬ ‫مع الف اظ على نوعه ا .‬

‫521‬
‫)‪>>> l = pickle.load(f‬‬ ‫))‪>>> print(j, type(j‬‬ ‫>'‪27 >> nom = 'Cédric‬‬ ‫)]5[‪>>> print(nom[1], nom[3], nom‬‬ ‫‪é r c‬‬

‫المزيد من هياكل البيانات‬

‫031‬

‫غالبا يكون تحديد مكان حرف في نهاية السلسلة مفيدا. للقيام بذلك، يجب استخدام ملؤشتتات ستتالبة. ملثل 1- للحتترف الخيتت و‬ ‫2- للحرف قبل الخي ...إلخ :‬
‫)]6-[‪>>> print (nom[-1], nom[-2], nom[-4], nom‬‬ ‫‪cid‬‬ ‫>>>‬

‫فإذا أردت تحديد عدد أحرف في السلسلة، نستخدم الدالة الدمجة ‪: ()len‬‬
‫))‪>>> print(len(nom‬‬ ‫6‬

‫الستخراج أجزاء لسلسلة‬ ‫في الكلثي من الحيان، عندما تعمل مع السلسل، قد ترغب بإسستخراج سلستتلة صتتغية متتن سلستتلة طويلتتة. بيلثتتون يتتوفر لتتك‬ ‫تقنية بسيطة تسمى التقطيع )"التشتيح"(. وتتكتون هتذه التقنيتة متن قوستي )نصتف مربتع : ][( وفتي داخلهتا ملؤشتتات بدايتة‬ ‫ونهاية الشيحة الت تريد استخراجها :‬
‫"‪>>> ch = "Juliette‬‬ ‫)]3:0[‪>>> print(ch‬‬ ‫‪Jul‬‬

‫في شيحة ]‪،[n,m‬تت يتم تضمي بداية من ‪ ،n‬ول يتم تضمي ‪ .m‬فإذا أردت تخزيتتن هتتذه الليتتة بستتهولة، يجتتب أن تملثتتل أدلتتة‬ ‫تشي للمواقع في ما بي الحروف، كما في الرسم بالسفل :‬

‫و نظرا لهذا النموذج، فإنه ليس صعبا أن تعرف أن استخراج 7:3[‪ [ch‬تساوي "‪"iett‬‬ ‫ملؤشات الشيحة لديها قيم افتاضية : يعتب أن أول ملؤش غي معرف ملثل الصفر، في حي أن اللؤشتت اللثتتاني يعتتتب أن طتتول‬ ‫السلسلة الكاملة :‬
‫)]3:[‪>>> print(ch‬‬ ‫‪Jul‬‬ ‫)]:3[‪>>> print(ch‬‬ ‫‪iette‬‬ ‫أول ثلثة أظحرف #‬ ‫كل ما يبعد 3 أظحرف #‬

‫و ينبغي على الحروف العلمة أن ل تواجه مشاكل :‬
‫'‪>>> ch = 'Adélaïde‬‬ ‫)]8:4[‪>>> print(ch[:3], ch‬‬ ‫‪Adé aïde‬‬

‫131‬

‫النقطة على سلسل النصية‬ ‫التسلسل، التكرار‬ ‫و يمكن للسلسل أن ترتبط بواسطة العامل + وأن تتكرر بواسطة العامل * :‬

‫'‪>>> n = 'abc' + 'def‬‬ ‫جمع سلسلة #‬ ‫4 * ' ! ‪>>> m = 'zut‬‬ ‫تكرار #‬ ‫)‪>>> print(n, m‬‬ ‫! ‪abcdef zut ! zut ! zut ! zut‬‬

‫نلحظ أن العاملي + و* يستطيعان أيضا أن يستخدموا للجمع وضب عند تطبيقهتتا علتتى برامتتتات رقميتتة. الحقيقتتة أن نفتتس‬ ‫العوامل يمكن أن تعمل بشكل مختلف تبعا للسياق الذي تعمل فيه وهي تستخدم الية ملثية جدا تسمى حمولة الزائتتدة للمشتتغل.‬ ‫في لغات البمجة الخرى، الحمولة الزائدة للعوامل ليست ممكنة دائما : ويجب علينا استخدام رموز مختلفة للضتتافة والتكتترار،‬ ‫على سبيل اللثال .‬ ‫01.1 أعرف بنفسك ماذا يحدث، عند تقطيع السلسلة، عندما يكون واحد أو أكث من اللؤشات الشيحة خاطئة، وصف ذلك‬ ‫بأفضل طريقة ممكنة. )إذا كان اللؤش اللثاني هو الصغر من اللؤش الول، على سبيل اللثال' أو إذا كان اللؤشتت اللثتتاني‬ ‫أكب من حجم السلسلة( .‬ ‫01.2 إقطع أجزاء سلسلة كبية على أجزاء كل واحدة بها 5 أحرف. ثم قم بجمع القطع في ترتيب عكس. السلسلة يجب أن‬ ‫تحتوي على الحرف العلمة .‬ ‫01.3 حاول كتابة دالة صغي اسمها ‪ ()trouve‬الت تفعل بالضبط عكس الذي يفعلته عامتل اللؤشتت )هتذا معنتاه متا بيت‬ ‫قوسي ] [(. بدل من البدء بملؤش ليجع لك الحرف الطلوب، هذه الدالة تقوم بإرجاع ملؤش الكلمة الت تم إدخالها.‬ ‫و بعبارة أخرى، اكتب دالة تأخذ برامتتتين : الولتتى استتم السلستتلة التتت يجتتب معالجتهتتا واللثانيتتة الحتترف التتذي يجتتب‬ ‫إيجاده. يجب على الدالة أن تقوم بإرجاع أول ملؤش للحرف في السلسلة. ‪ Ainsi par‬على سبيل اللثال :‬
‫))"&" ,"‪print(trouve("Juliette & Roméo‬‬

‫تمارين‬

‫يجب أن يطبع : 9‬ ‫انتبه : يجب أن تفكر في جميع الحالت الحتملة. وهذا يشمل أن تقوم الدالة بإرجاع قيمة معينة)على سبيل اللثال -1(‬ ‫إذا كان الحرف الذي يبحث عنه غي موجود في السلسلة. ويجب على السلسلة أن تقبل الحرف العلمة .‬ ‫01.4 حسن الدالة في التمرين السابق بإضافة برامت ثالث : وهو ملؤش من أين يبدأ البحث في السلسلة. على سبيل اللثال:‬
‫))5 ,"‪print(trouve ("César & Cléopâtre", "r‬‬

‫يجب أن تطبع : 51 )وليس 4 !(.‬ ‫01.5 اكتب الدالة ‪ ()compteCar‬الت تحسب عدد مرات تكرار الحرف في السلسلة في السلسلة :‬

‫المزيد من هياكل البيانات‬
‫))"‪print(compteCar("ananas au jus","a‬‬

‫231‬

‫يجب أن تطبع : 4‬
‫))"‪print(compteCar("Gédéon est déjà là","é‬‬

‫يجب أن تطبع : 3‬ ‫دورة من التسلسل : العبارة ‪... for ... in‬‬ ‫كلثيا ما يحدث أنه يجب علينا أن نتعامل متتع السلستتلة النصتتية بأكملهتتا بحتترف، متتن الحتترف الول إلتتى الحتترف الخيتت، للقيتتام‬ ‫بداية من أي واحدة أي معامل. ندعو هذه العملية بت "دورة". سنقتص فقط علتتى أدوات بيلثتتون التتت نعرفهتتا، نحتتن نستتتطيع أن‬ ‫نقوم بتمي هذه الدورة بمساعدة الحلقة، تتمحور حول العبارة ‪: while‬‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫...‬ ‫...‬ ‫...‬ ‫* ‪J‬‬ ‫"‪nom ="Joséphine‬‬ ‫0= ‪index‬‬ ‫:)‪while index < len(nom‬‬ ‫)' '= ‪print(nom[iindex] + ' *', end‬‬ ‫1+ ‪index = index‬‬ ‫* ‪o * s * é * p * h * i * n * e‬‬

‫هذه الحلقة تقطع السلسلة ‪ nom‬لتستخرج كل حروفها واحدة واحدة، ثتم تطبتع معهتا علمتة نجمتة. انظتر جيتدا إلتى الشت ط‬ ‫الستخدم مع العبارة ‪ while‬وهو ‪ ،(index < len(nom‬وهذا معناه أن الحلقة ستتوقف عندما تصتتل للملؤشتت 9 )السلستتلة‬ ‫تتكون من 01 حروف(. وفي هذه الحالة سوف نتعامل مع كل حرف في السلسلة، لن الفهرسة تبدأ من 0 وتنتهي بت 9.‬ ‫دورة التسلستتل هتتي عمليتتة متكتتررة جتدا فتتي البمجتتة. لستهولة الكتابتتة، بيلثتتون تتتوفر لتتك هيكتتل حلقتتة أكتتث ملئمتتة متن الحلقتتة‬ ‫‪ ،while‬وهو السلوب ‪: ... for ... in‬‬ ‫مع هذه التعليمات، يصبح البنامج في العلى هكذا :‬
‫"‪>>> nom ="Cléopâtre‬‬ ‫:‪>>> for car in nom‬‬ ‫...‬ ‫)' '= ‪print(car + ' *', end‬‬ ‫...‬ ‫* ‪C * l * é * o * p * â * t * r * e‬‬

‫كما ترون، هيكل الحلقة هو الكث ملئمة. فهو يريحكم من تعريف وزيادة متغي معي )عداد( لدارة ملؤش الحرف الذي تريتتدون‬

‫معالجته فتتي كتل تكترار )بيلثتون هتتو التذي يفعتتل ذلتك( الهيكتل ‪ ... for ... in‬ل يظهتتر ستتوى الضتوري، أي أن التغيتت ‪car‬‬
‫سيحتوي على كل الحروف على التوالي، من البداية إلى النهاية.‬

‫331‬

‫النقطة على سلسل النصية‬

‫العبارة ‪ for‬تتيح كتابة الحلقات، في تكرار يعالج فيه على التوالي كل عناص لسلسلة القدمة. في اللثال أعله. كان التسلسل‬ ‫هو سلستتلة نصتية. اللثتال التتالي يوضتح أنته يمكتن لنتتا أن نطبتتق نفتتس العمليتتة علتتى القتتوائم )و ستيكون نفتتس الشتء متتع ال‬ ‫‪ tuples‬في وقت لحق( :‬
‫]'‪liste = ['chien', 'chat', 'crocodile', 'éléphant‬‬ ‫:‪for animal in liste‬‬ ‫))‪print('longueur de la chaîne', animal, '=', len(animal‬‬

‫عند تشغيل هذا السكريبت يظهر لنا :‬
‫‪longueur‬‬ ‫‪longueur‬‬ ‫‪longueur‬‬ ‫‪longueur‬‬ ‫‪de‬‬ ‫‪de‬‬ ‫‪de‬‬ ‫‪de‬‬ ‫‪la‬‬ ‫‪la‬‬ ‫‪la‬‬ ‫‪la‬‬ ‫‪chaîne‬‬ ‫‪chaîne‬‬ ‫‪chaîne‬‬ ‫‪chaîne‬‬ ‫5 = ‪chien‬‬ ‫4 = ‪chat‬‬ ‫9 = ‪crocodile‬‬ ‫8 = ‪éléphant‬‬

‫العبارة ‪ : ... for ... in‬هو ملثال آخر من العبارة الجمعة. ل تن س النقطتي في نهاية السطر، ومسافة البادئتة للكتلتتة التتت‬ ‫َ‬ ‫تليها.‬ ‫السم بعد الكلمة الحجوزة ‪ in‬هو الذي تجتتب معتالجته. الستم بعتد الكلمتتة الحجتتوزة ‪ for‬هتتو استم التتذي اختتتته لتغيتت التذي‬ ‫سيحتوي على جميع عناص التسلسل على التوالي. هذا التغيتت ستيتم تعريتف تلقائيتا )هتذا معنتتاه أنته ليتس متن الضتوري أن‬ ‫تحدده سلفا، وسوف يتكيف تلقائيا لعنص التسلسل الت تتم معتتالجته )تتتذكر أنتته فتتي حالتتة وجتتود قائمتتة، ليتتس بالضتتورة أن‬ ‫تكون جميع عناصه من نفس النوع( على سبيل اللثال :‬
‫]]'‪divers = ['lézard', 3, 17.25, [5, 'Jean‬‬ ‫:‪for e in divers‬‬ ‫))‪print(e, type(e‬‬

‫عند تشغيل هذا السكريبت فسوف يعطينا :‬
‫>'‪lézard >>‬ ‫>>>‬ ‫>>>‬ ‫71‬ ‫>>>‬ ‫"‪chaine = "Amélie et Eugène\n‬‬ ‫)"‪of =open("test.txt", "w‬‬ ‫)‪of.write(chaine‬‬ ‫)(‪of.close‬‬

‫مع هذه السطر القليلة، لقد قمنا بحفظ سلسلة نصية في هيئة أسطر نصية في ملتتف، بالطريقتتة العتتتادة. دعونتتا نقتتوم بقتتراءة‬ ‫هذا اللف، لكن سوف نقوم بفتحه في الوضع البيناري )اللثنائي(، وسوف نقوم بتمرير البامت "‪ "rb‬إلى الدالة ‪ .()open‬فتتي‬ ‫هذا الوضع، يتم نقل البايتات بوضع خام، دون تحويل من أي نوع. والقراءة عن طريق الدالة ‪ ()read‬الت ستتعطينا سلستتلة‬ ‫نصية كما في الفصل السابق، لكن في سلسلة من البايتات، والتغي الذي يتلقى تلقائيا نوع التغي كنوع بايت :‬
‫)‪ (b‬يبيناري )‪ (r‬وضع القراءة >= "‪# "rb‬‬

‫)"‪>>> of =open("test.txt", "rb‬‬ ‫)(‪>>> octets =of.read‬‬ ‫)(‪>>> of.close‬‬ ‫)‪>>> type(octets‬‬ ‫>'‪>> ch_lue =of.read‬‬ ‫)(‪>>> of.close‬‬ ‫‪>>> ch_lue‬‬ ‫'‪'Amélie et Eugène\n‬‬

‫في السكريبتات التقدمة، من الحتمل دائما تحديد التتمي الفتتض للملفتات معتتالجته، حتت لتو كتتان الطلتتب متن الستتتخدم هتذه‬ ‫العلومات، أو فكر في تجارب متقدمة كلثيا أو قليل لتحديد تلقائيا نوع التمي .‬ ‫حالة لسكريبتات بيثون‬ ‫سكريبتات بيلثون هي في حد ذاتها ملفات نصية، بالطبع. بناء على تكوين برنامج التحرير الخاص بك، أو على نظتتام التشتتغيل‬ ‫ً‬ ‫الخاص بك، يمكن لهذه النصوص أن يتم ترميهتا بمعتتاير مختلفتتة. بحيتث يمكتن لتبيلثون تفستيه بشتتكل صتتحيح، وينصتح لتك‬ ‫دائما أن تشمل عشبه التعليق هذا )يجب أن يكون في السطر الول أو اللثاني( :‬
‫-*- 1-‪# -*- coding:Latin‬‬

‫أو :‬
‫-*- 8-‪# -*- coding:Utf‬‬

‫… ... هذا يدل على التمي الستخدم فعليا، بطبيعة الحال !‬ ‫و بالتالي مفس بيلثون يعرف كيف يفك السلسل النصية الت استتتخدمتها فتتي الستتكريبت. لحتتظ أنتته يمكنتتك حتتذف هتتذا الشتتبه‬ ‫تعليق إذا كنت متأكدا أنه يتم ترمي النصوص الخاص بك بتمي 8-‪ ،UTF‬لنه هو الن العيار الفتاض لنصوص بيلثون .‬
‫85‬

‫75‬ ‫ف العلوم اتية, نسومي ‪) codec‬ترميز\فك ترميز( أي تويل شكل. سوف ترى على سبيل الاث ال العديد من ‪) codecs‬ترميزات(‬ ‫ف ع ال العلوم اتية )ترميز الصوت, الفيديو(. وبياثون لديه العديد من برامج تويل السلسل النصية لةتحويل السلسل وفق ا لع ايي‬ ‫مةتلفة.‬ ‫85‬ ‫ف الصدارات الس ابقة لبياثون, الةترميز الفةتراضي هو ‪. ASCII‬‬

‫541‬

‫النقطة على سلسل النصية‬ ‫الوصول إلى حروف أخرى غير الموجودة على لوحة المفاتيح‬

‫دعونا نرى أي جزء يمكنك أن تستخرجه فتتي الحقيقتتة جميتتع الحتتروف لتتديها معتترف رقمتتي عتتالي يونيكتتود. للوصتتول إلتتى هتتذه‬ ‫العرفات، يوفر لك بيلثون عددا من الدالت العرفة مسبقا.‬
‫الدالة ‪ (ord(ch‬تقبل أي حرف كبامت. وترجع القيمة الرقمية للحرف. ملثل ‪ ("ord("A‬تقوم بإرجتاع العتتدد 56، و "(‪ord‬‬

‫‪ ("Ĩ‬تقوم بإرجاع العدد 692.‬

‫الدالة ‪ (chr(num‬تقوم بالعكس تماما، تعطيها الحرف الطبعي وهتتي تقتتوم بإرجتتاع معتترف اليونيكتتود التتذي يستتاوي الرقتتم.‬ ‫ولتعمل هذه، يتطلب هذا استيفاء شطي :‬ ‫•قيمة ‪ num‬يجب أن تكون لحرف موجود مستبقا )معرفتتات اليونيكتتود ليستت مستتمرة : بعتض الرمتوز ل تتطتابق متع أي‬ ‫حرف(‬ ‫• يجتتب علتى حاستوبك أن يعتترف الوصتف الرستومي للحتترف، أو، بطريقتة أخترى، يعترف رستم هتذا الحترف، وهتذا يستمى "‬ ‫‪" - " glyphe‬حرف رسومي". أنظمة التشغيل الحديلثة تحتوى على مكتبات كبية للحروف الرسومية، والت ينبغي لها أن‬ ‫تعرض اللف على الشاعشة .‬ ‫على سبيل اللثال 56(‪ (chr‬تقوم بإرجاع الحرف ‪ ،A‬و 6401(‪ (chr‬يرجع الحرف السييلي ‪.Ж‬‬ ‫يمكنك استخدام هذه الدالت العرفة مسبقا للهو باستكشاف لعبة إظهار الحرف على عشاعشة الحاسوب. يمكنك على سبيل اللثال‬ ‫أن تقوم بإرجاع الحروف الصغية للبجدية اليونانية، مع العلم أن الرموز الخصصة لهتا تتتاوح متا بيت 549 إلتى 969. انظتر‬ ‫للسكربت بالسفل :‬
‫"" = ‪s‬‬ ‫سلسلة فارغة #‬ ‫549 = ‪i‬‬ ‫أول كود #‬ ‫:969 =< ‪while i‬‬ ‫آخر كود #‬ ‫)‪s += chr(i‬‬ ‫1 + ‪i = i‬‬ ‫)‪print("Alphabet grec (minuscule) : ", s‬‬

‫يجب عليه أن يظهر النتيجة التالية :‬
‫‪Alphabet grec (minuscule) : αβγδεζηθικλμνξοπρςστυφχψω‬‬

‫تمارين‬
‫01.41 اكتب سكريبت صغي يجب عليه أن يظهر جدول رمتوز ‪ .ASCII‬يجتتب علتى البنامتج أن يقتوم بإظهتار جميتع الحتروف‬ ‫والرموز. بداية من هذا حدد العلقة الرقمية البسيطة بي كل حرف كبي وبي كل حرف صغي يقابله .‬

‫المزيد من هياكل البيانات‬

‫641‬

‫01.51 عدل السكريبت السابق لستكشاف الرموز ما بي 821 و 652، حيث ستجد حروف معلمتتة )متن بيتت أمتور كتلثية(. هتتل‬ ‫العلقة العددية الت وجدتها في التمرين السابق ستبقى نفسها للحروف العلمة الفرنسية ؟‬ ‫01.61 بداية من هذه العلقة، اكتب دالة تحول جميتتع الحتتروف الصتغية إلتى حتروف كتبية، والعكتتس بتتالعكس )مقدمتة فتتي‬ ‫الجملة كبامت(.‬ ‫01.71 اكتب سكريبت يقوم بنسخ ملف نص باستبدال جميع الفراغات )الساحات الفارغة( بهذه الجموعة من الرموز -*-. اللف‬ ‫الذي ستنسخه يجب أن يكون ترميه بمعيار 1-‪ ،Latin‬واللف الهدف سيكون ترميه 8-‪ .Utf‬استتم اللفيتت ستيتم طلبهتتم‬ ‫في بداية السكريبت .‬ ‫01.81 اكتب الدالة ‪ ،(voyelle(car‬الت تقوم بإرجاع "صحيح" إذا كان الحرف في البامت فوايال .‬ ‫01.91 اكتب الدالة ‪ ،(compteVoyelles(phrase‬الت تقوم بإرجاع عدد الحروف الفوايال في الجملة القدمة .‬ ‫01.02 اكتشف نطاق )مدى( حروف اليونيكود الوجودة في حاسوبك، بمساعدة حلقة برمجية مشابهة للت قمنتتا باستتتخدامها‬ ‫لظهار البجدية اليونانية. واعث على الرموز القابلة للحروف السييلية، واكتب سكريبت يظهرها بالكبي والصغي.‬ ‫السللسل هي كائنات‬ ‫في الفصول السابقة، لقد تعرفت إلى العديد من الكائنات. وأنت تعرف أنه يمكننا أن نعمل علتتى كتتائن بمستتاعدة الستتاليب )هتتذا‬ ‫معناه الدالت الرتبطة بهذا الكائن(.‬ ‫في بيلثون، السلسل النصية هي كائنات. لذلك يمكننا القيام بمعالجة السلسل النصتتية باستتتخدام الستتاليب اللئمتتة. وفتتي متتا‬ ‫يلي بعضها، لقد إختنا الكث استخداما :‬
‫95‬

‫•‪ : ()split‬تحويل سلسلة إلى قائمة. يمكننا اختيار الحرف التتذي يفصتتلها )يتتتم وضتتعه كبامتتت(، فتتإذا لتتم نضتتع ستتيكون‬ ‫الفراغ)مساحة فراغة( هي الفتاضية :‬
‫"‪>>> c2 ="Votez pour moi‬‬ ‫)(‪>>> a = c2.split‬‬ ‫)‪>>> print(a‬‬ ‫]'‪['Votez', 'pour', 'moi‬‬ ‫"‪>>> c4 ="Cet exemple, parmi d'autres, peut encore servir‬‬ ‫)","(‪>>> c4.split‬‬ ‫]'‪['Cet exemple', " parmi d'autres", ' peut encore servir‬‬

‫95 هذه م ا هي إل أماثلة قليلة. وأغلب هذه الس اليب يكن أن يةتم اسةتخدمه ا مع برامةترات مةتلفة ل ندد جيعه ا هن ا )على سبيل‬ ‫الاث ال, بعض البامةترات ل تسومح بع الة سوى جزء من السلسلة(. يكنك الصول على ق ائومة ك املة من جيع الس اليب الرتبيطة‬ ‫بك ائن لسةتخدام الدالة الدمة ‪ .()dir‬يرجى الرجوع إل أي كةت اب مرجعي )أو وث ائق على النةترنت لبياثون( إذا كنت تريد أن‬ ‫تعرف أكاثر من ذلك .‬

147

‫النقطة على سلسل النصية‬

‫( : جمع قائمة نصية إلى واحدة )هذا السلوب يعمل عكس السلوب السابق (. تنبيه : السلسلة الت نطبق‬join(liste• : ‫عليها هذا السلوب ستكون بملثابة فاصلة )واحدة أو أكث( ; البامت المرر سيكون قائمة نصية الت نريد جمعها‬
>>> b =["Bête", "à", "manger", "du", "foin"] > >> print(" ".join(b)) Bête à manger du foin >>> print("---".join(b)) Bête---à---manger---du---foin

:‫ البحث عن مكان كلمة‬sch ‫( : في سلسلة‬find(sch•
>>> ch1 = "Cette leçon vaut bien un fromage, sans doute ?" >>> ch2 = "fromage" >>> print(ch1.find(ch2)) 25

: ‫ عدد تكرار الكلمة‬sch ‫( : في سلسلة‬count(sch•
>>> ch1 = "Le héron au long bec emmanché d'un long cou" >>> ch2 = 'long' >>> print(ch1.count(ch2)) 2

: ‫)( : تحويل سلسلة إلى حروف صغية‬lower•
>>> ch = "CÉLIMÈNE est un prénom ancien" >>> print(ch.lower()) célimène est un prénom ancien

: ‫)( : تحويل سلسلة إلى حروف كبية‬upper•
>>> ch = "Maître Jean-Noël Hébèrt" >>> print(ch.upper()) MAÎTRE JEAN-NOËL HÉBÈRT

:(‫)( : تحويل أول حرف في كل كلمة إلى حرف كبي )ملثل العناوين النكليية‬title•
>>> ch ="albert rené élise véronique" >>> print(ch.title()) Albert René Élise Véronique

: ‫)( : بديل السلوب السابق. يحول فقط أول حرف في السلسلة إلى حرف كبي‬capitalize•
>>> b3 = "quel beau temps, aujourd’hui !" >>> print(b3.capitalize()) "Quel beau temps, aujourd’hui !"

: ‫)( : يحول جميع الحروف الكبية إلى صغية والعكس بالعكس‬swapcase•
>>> ch = "Le Lièvre Et La Tortue" >>> print(ch.swapcase()) lE lIÈVRE eT lA tORTUE

: ‫)( : حذف الفراغات في بداية ونهاية السلسلة‬strip•
>>> ch = " Monty Python >>> ch.strip() 'Monty Python' "

‫المزيد من هياكل البيانات‬

‫841‬ ‫•2‪ : (replace(c1, c‬استبدال جميع الحروف 1‪ c‬بحروف 2‪ c‬في السلسلة:‬

‫"‪>>> ch8 = "Si ce n'est toi c'est donc ton frère‬‬ ‫))"*"," "(‪>>> print(ch8.replace‬‬ ‫‪Si*ce*n'est*toi*c'est*donc*ton*frère‬‬

‫•‪ : (index(car‬إيجاد ملؤش أول ظهور للحرف ‪ car‬في السلسلة:‬
‫"‪>>> ch9 ="Portez ce vieux whisky au juge blond qui fume‬‬ ‫))"‪>>> print(ch9.index("w‬‬ ‫61‬

‫في معظم هذه الساليب، يكون من المكن تحديد جتزء متا يجتتب معتالجته، وهتذا يكتتون بإضتتافة برامتتات إضتافية. علتى ستبيل‬ ‫اللثال :‬
‫))"‪>>> print (ch9.index("e‬‬ ‫4‬ ‫))5,"‪>>> print (ch9.index("e‬‬ ‫8‬ ‫))51,"‪>>> print (ch9.index("e‬‬ ‫92‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬

‫البحث من البداية السلسلة‬ ‫'‪ 'e‬والعثور على أول ظحرف‬ ‫إيبدأ فقط من المؤشر 5‬ ‫الثانية '‪ 'e‬وجد‬ ‫ِ‬ ‫إيبدأ البحث يبداية من المؤشر 51‬ ‫'‪ 'e‬وجد رايبع‬ ‫ِ‬

‫إلخ.‬ ‫أرجو منك أن تفهم أنه ل يمكن وصف كل الساليب التاحة، والبامتات الخاصة بها، في إطار هذه الدورة. فإذا أردت الزيد من‬ ‫العلومات، فيجب عليك قراءة وثائق بيلثون ) ‪ ،(Library reference‬أو مراجع جيدة .‬ ‫داالت مدمجة‬ ‫لجميع الغراض العملية، تذكر أيضا أنه يمكننا أيضا أن نطبق على السلسل عددا كبيا من الدالت الدمجة في اللغة :‬ ‫•‪ (len(ch‬إرجاع طول السلسلة ‪ ،ch‬أو بعبارة أخرى، عدد أحرفها .‬ ‫•‪ (float(ch‬تحويل السلسلة ‪ ch‬إلى رقم حقيقي ) ‪) (float‬و بطبيعة الحتال فتإن هتذا ل يعمتتل إل إذا كتانت السلستتلة‬ ‫رقما، حقيقي أو صحيح(‬ ‫انتبه : ليس الفاصلة العشية‬ ‫•‪ (int(ch‬يحول السلسلة ‪ ch‬إلى عدد صحيح )مع نفس القيود( :‬
‫)"481"(‪>>> a = int‬‬ ‫02 + ‪>>> print a‬‬ ‫402‬

‫)"63.21"(‪>>> a = float‬‬ ‫5 + ‪>>> print a‬‬ ‫63.71‬

‫#‬

‫•‪ (str(obj‬يحول أو )يملثل( كائن ‪ obj‬إلى سلسلة نصية. ‪ obj‬يمكن أن يكون معطيات من أي نوع :‬

‫941‬

‫النقطة على سلسل النصية‬

‫]56.7 ,"‪>>>> a, b = 17, ["Émile‬‬ ‫".‪>>> ch =str(a) +" est un entier et " +str(b) +" est une liste‬‬ ‫)‪>>> print(ch‬‬ ‫.‪17 est un entier et ['Émile', 7.65] est une liste‬‬

‫تنسيق السللسل النصية‬ ‫لكمال هذه النظرة العامة على الميات لرتبطة بالسلسل النصية، يبدو من الحكمة أن أقدم لك تقنية معالجة أكث قوة، تستتمى‬ ‫"تنسيق السلسل". هذا مفيد جدا في جميع الحالت الت تحتاج بناء سلسلة معقدة من عدة قطع، ملثل قيم التغيات الختلفة.‬ ‫على سبيل اللثال، اكتب برنامج الذي يعالج لون ودرجة حرارة محلول مائي، في الكيمياء، يتم تخزين اللتتون فتتي سلستتلة نصتتية‬ ‫تدعى ‪ ،coul‬ودرجة الحرارة في متغي من نوع حقيقي يدعى ‪ .temp‬ويجب على برنامجك أن يقوم ببنتتاء سلستتلة نصتتية‬ ‫من هذه البيانات، على سبيل اللثال، جملة ملثل هذه : "الحلول سيكون أحمر ودرجة الحرارته 7.21 درجة مئوية ".‬ ‫يمكنك بنتاء هتذه السلستلة بجمتتع القطتع متع بعضتها البعتض بمستاعدة العامتتل التسلستتل )الرمتز +(، ولكتن يجتتب عليتتك أيضتا‬ ‫استخدام الدالة الدمجة ‪ ()str‬لتحويل سلسلة نصية والقيمة الرقمية موجودة داخل متغي من نوع ‪) float‬قم بالتمارين( .‬ ‫يوفر لك بيلثون إمكانيات أخرى. يمكنك صنع سلسلة )"‪ - "patron‬الزعيم( الت تحتوي على أغلب النص التذي لتم يتغيتت، متتع‬ ‫علمات الواقع الحددة )حقول( حيث تظهر عندما تريد محتويات التغيات. قم الن بتطبيق السلوب ‪،()format‬تت على هتتذه‬ ‫السلسلة، وسوف توفرها على عشكل برامتات والكائنات الختلفة تحول إلى حروف ويتم إضافتها بدل العلمات. ملثال أفضل متتن‬ ‫كل هذا :‬
‫"‪>>> coul ="verte‬‬ ‫9.51 + 743.1= ‪>>> temp‬‬ ‫"‪>>> ch ="La couleur est {} et la température vaut {} °C‬‬ ‫))‪>>> print(ch.format(coul, temp‬‬ ‫‪La couleur est verte et la température vaut 17.247 °C‬‬

‫تستخدم العلمات التكونة من القواس، الت تحتوي أو قد ل تحتوي على معلومات التنسيق :‬ ‫•إذا كانت العلمات فارغة )في أبسط الحالت(، سوف يتحصل السلوب ‪ ()format‬على برامتات التتت ستتتكون بملثابتتة‬ ‫العلمات في السلسلة. وسوف يقوم بيلثون إذا بتطبيق الدالة ‪ ()str‬على كل من هتتذه البامتتتات، وستتوف يضتتفها إذا فتتي‬ ‫السلسلة في مكان العلمات، في نفس التتيب. البامتات يمكن أن تكون أي كائن أو تعبي بيلثون :‬
‫6141.3= ‪>>> pi‬‬ ‫7.4= ‪>>> r‬‬ ‫".}{ ‪>>> ch ="L’aire d’un disque de rayon {} est égale à‬‬ ‫))2**‪>>> print(ch.format(r, pi * r‬‬ ‫.449793.96 ‪L’aire d’un disque de rayon 4.7 est égale à‬‬

‫المزيد من هياكل البيانات‬

‫051‬

‫• يمكتتن للعلمتتات أن تحتتتوي علتتى أرقتتام متسلستتلة )العتتد يبتتدأ متتن الرقتتم 0( لوصتتف بدقتتة البامتتتات التتت ستتتمرر لتتت‬ ‫‪ ()format‬لتحتتل مكانهتتا. هتتذه التقنيتتة هتتي قيمتتة خاصتتة إذا كتتانت نفتتس البامتتت يجتتب عليتته استتتبدال مجموعتتة متتن‬ ‫العلمات الحددة:‬
‫".}1{‪>>> phrase ="Le{0} chien{0} aboie{1} et le{0} chat{0} miaule‬‬ ‫))"" ,""(‪>>> print(phrase.format‬‬ ‫.‪Le chien aboie et le chat miaule‬‬ ‫))"‪>>> print(phrase.format("s", "nt‬‬ ‫.‪Les chiens aboient et les chats miaulent‬‬

‫•‪ L‬يمكن للعلمات أن تحتوي على معلومات تنستتيق )بالعشتتتا،ك أو ليتتس متتع تسلستتل الرقتتام(. علتتى ستتبيل اللثتال، يمكنتتك‬ ‫تحديد بدقة النتيجة النهائية أو إجبار استخدام الرموز العلمية أو تحديد عدد الحرف، ... إلخ :‬
‫‪>>> ch ="L'aire d'un disque‬‬ ‫* ‪>>> print(ch.format(r, pi‬‬ ‫‪L'aire d'un disque de rayon‬‬ ‫‪>>> ch ="L'aire d'un disque‬‬ ‫* ‪>>> print(ch.format(r, pi‬‬ ‫‪L'aire d'un disque de rayon‬‬ ‫".}‪de rayon {} est égale à {:8.2f‬‬ ‫))2**‪r‬‬ ‫‪4.7 est égale à‬‬ ‫.04.96‬ ‫".}‪de rayon {0} est égale à {1:6.2e‬‬ ‫))2**‪r‬‬ ‫.10+‪4.7 est égale à 6.94e‬‬

‫في الختبار الول، النتيجة تم تنسيقها بطريق لتحمل 8 أحرف، رقمي منهم بعد الفاصل. فتتي التجربتتة اللثانيتتة، تتم عتترض‬ ‫النتيجة في عشكل علمي )10+‪ e‬معناها 1001 ‪ .(x‬ملحظة : يتم تنفيذ التقريبات الحتملة بشكل صحيح .‬ ‫الوصف الكامل لجميع إمكانيات التنسيق يجب أن تكون في العديد من الصفحات، وهذا أكب من حجم نطتتاق الكتتتاب. فتتإذا كنتتت‬ ‫في حاجة لعرفة الزيد حول التنسيق، فيجب عليك الطلع على وثائق لغة بيلثون، أو الكتب الكث تخصصا. ملحظة بستتيطة‬ ‫: هذا التنسيق يسمح بإظهار بسهولة النتيجة الرقمية بالتقيم اللثنائي )بيناري( أو اللثماني أو الست العشي :‬
‫987= ‪>>> n‬‬ ‫".‪>>> txt ="Le nombre {0:d} (décimal) vaut {0:x} en hexadécimal et {0:b} en binaire‬‬ ‫))‪>>> print(txt.format(n‬‬ ‫.‪Le nombre 789 (décimal) vaut 315 en hexadécimal et 1100010101 en binaire‬‬

‫لسللسل التنسيق " القديمة "‬ ‫إصتدارات بيلثتون قبتل الصتدار 3 كتانت تستتخدم تقنيتات تنستتيق مختلفتتة قليل وأقتل تطتورا، لكتن ل تتزال صتالحة للستتخدام.‬ ‫وأنصحك بأن تعتمد الطريقة الت ذكرناها في الفقرات السابقة. وسوف نشح هنا باختصار الطريقة القديمة، لنك قتتد تواجههتتا‬ ‫في سكريبتات الكلثي من البمجي )و حت في بعض أملثلتنا !(. وتتكون في تنسيق السلسلة بجمع عنصتتين بمستتاعدة العامتتل‬ ‫%. على يسار هذا العامل، السلسلة "الرئيسة" الت تحتوي على علمات تبدأ دائما بت %، وفي اليمي )بي قوسي( أيتتن يضتتع‬ ‫بيلثون الكائن في السلسلة، بدل من العلمات .‬

‫مثال:‬

‫151‬

‫النقطة على سلسل النصية‬

‫"‪>>> coul ="verte‬‬ ‫9.51 + 743.1 = ‪>>> temp‬‬ ‫))‪>>> print ("La couleur est %s et la température vaut %s °C" % (coul, temp‬‬ ‫‪La couleur est verte et la température vaut 17.247 °C‬‬

‫العلمة %‪ s‬تلعب نفس دور }{ في الطريقة الجديدة. وتقبل أي كائن )سلسلة، عدد صحيح، عدد حقيقتتي، قائمتتة ...(. ويمكنتتك‬ ‫استخدام علمات أخرى أكث تقدما، ملثل %‪ 8.2f‬أو %‪ 6.2e‬الت هي ملثل }:‪ {8.2f‬و}:‪ {6.2e‬في الطريقة الجديدة. وهذا في‬ ‫أبسط الحالت، لكن اقتنع أن إمكانيات الصيغة الجديدة هي واسعة .‬

‫تمارين‬
‫01.12 اكتب سكريبت الذي يقوم بنسخ ملف نص تم ترميه بت 1-‪ Latin‬إلى 8-‪ ،Utf‬ويجب أن تكتتون كتتل كلمتتة تبتتدأ بحتترف‬ ‫كبي. سوف يقوم البنامج بطلب أسماء اللفات من الستخدم. العتاملت القتراءة والكتابتة للملفتات فتتي وضتع الوضتتع‬ ‫اللف النص العادي .‬ ‫01.22 بديل التمرين السابق : ف ّعل عمليتتات قتراءة وكتابتتة اللفتات فتتي وضتع اللثنتائي، والعمليتتات ترميتت\فتتك ترميتت سلستل‬ ‫البايتات. بالضافة، يجب عليك التعامل مع السطر بطريقة لستبدال جميع الفراغات بمجموعة من 3 رموز -*-.‬ ‫01.32 اكتب سكريبت الذي يقوم بحساب عدد الكلمات الوجودة في ملف نص .‬ ‫01.42 اكتب سكريبت الذي يقوم بنسخ ملف نص مع دمج )مع السابقة( السطر الت ل تبدأ بحرف كبي .‬ ‫01.52 لديك ملف يحتوي على قيم رقمية. إعتب أن هذه القيم هي أقطتار متن سلستلة متن الكترات. اكتتب ستكريبت يقتوم باستتخدام‬ ‫معطيات هذا اللف لصنع ملف آخر، منظمة فتي أستطر متن النصتوص بوضتوح الخصتائص الخترى لهتذه الكترات )مستاحة‬ ‫الجزء ومساحة الخارجية والحجم(، في جمل ملثل هذه :‬
‫45.5076 .‪Diam. 46.20 cm Section 1676.39 cm² Surf‬‬ ‫39.83254 .‪Diam. 120.00 cm Section 11309.73 cm² Surf‬‬ ‫.‪Diam‬‬ ‫‪0.03 cm Section‬‬ ‫.‪0.00 cm² Surf‬‬ ‫00.0‬ ‫‪Diam. 13.90 cm Section‬‬ ‫.‪151.75 cm² Surf‬‬ ‫99.606‬ ‫48.27742 .‪Diam. 88.80 cm Section 6193.21 cm² Surf‬‬ ‫²‪cm‬‬ ‫²‪cm‬‬ ‫²‪cm‬‬ ‫²‪cm‬‬ ‫²‪cm‬‬ ‫³‪Vol. 51632.67 cm‬‬ ‫³‪Vol. 904778.68 cm‬‬ ‫.‪Vol‬‬ ‫³‪0.00 cm‬‬ ‫.‪Vol‬‬ ‫³‪1406.19 cm‬‬ ‫³‪Vol. 366638.04 cm‬‬

‫.إلخ‬ ‫01.62 لديك تحت تصفك ملف نص يحتوي على أسطر تملثل قيما رقمية من نوع حقيقتتي، دون أن تعتترض )و يتتتم ترميهتتا‬ ‫كسلسل نصية(. اكتب سكريبت يقوم بنسخ هذه القيم في ملف آخر، وتقريبهم بحيث ل تحتوي بعد الفاصل أكتتث متتن‬ ‫رقم واحد، هذا الرقم ل يمكن أن بكون سوى 0 أو 5 )التقريب يجب أن يكون صحيحا( .‬ ‫النقطة في القوائم‬ ‫لقد التقينا القتتوائم بالفعتتل عتتدة متترات، منتتذ تقتتديمه باختصتتار فتتي الفصتتل 5. القتتوائم هتتي مجموعتتات مرتبتتة متتن الكائنتتات. ملثتتل‬ ‫السلسل النصية، القوائم هتتي مجموعتتة متن جتزء متن نتوع عتام التذي ستتميه فتتي بيلثتتون التسلستتل. ملثتتل الحتتروف فتتي السلستتلة،‬ ‫الكائنات تم وضعها في القائمة من خلل الفهرس )رقم الذي يشي إلى مكان الكائن في التسلسل(.‬

‫المزيد من هياكل البيانات‬

‫251‬ ‫تعريف قائمة - الوصول إلى عناصرها‬ ‫أنت تعرف بالفعل أنه يتم تحديد القائمة بمساعدة القواس العقوفة )نصف مربع( :‬

‫]52 ,01 ,83 ,5[ = ‪>>> nombres‬‬ ‫]"‪>>> mots = ["jambon", "fromage", "confiture", "chocolat‬‬ ‫]]7491 ,"‪>>> stuff = [5000, "Brigitte", 3.1416, ["Albert", "René‬‬

‫في اللثال الخي أعله، قمنا بتجميع عدد صحيح وسلسلة وعدد حقيقي وحت قائمة، لتذكيكم بأنه يمكتتن وضتتع معطيتتات متتن‬ ‫أي نوع في القائمة، بما في ذلك القوائم والقواميس و ‪) tuples‬سوف نناقشها في وقت لحق(.‬ ‫للوصول إلى عناص قائمة، سوف نستخدم نفس الطرق )رقم اللؤش والتقطيع إلى قطع( للوصول إلى الحرف في سلسلة :‬
‫)]2[‪>>> print(nombres‬‬ ‫01‬ ‫)]3:1[‪>>> print(nombres‬‬ ‫]01 ,83[‬ ‫)]3:2[‪>>> print(nombres‬‬ ‫]01[‬ ‫)]:2[‪>>> print(nombres‬‬ ‫]52 ,01[‬ ‫)]2:[‪>>> print(nombres‬‬ ‫]83 ,5[‬ ‫)]1-[‪>>> print(nombres‬‬ ‫52‬ ‫)]2-[‪>>> print(nombres‬‬ ‫01‬

‫و ينبغي أن تلفت الملثلة الذكورة أعله انتباهكم إلى أن قطعة )شيحة( متتن القائمتتة هتتي دائمتتا قائمتتة )حتتت لتتو كتتانت القطعتتة‬ ‫)الشيحة( تحتوي على عنص واحد، كمتتا فتتي اللثتتال اللثتالث( إ ذا يمكتن للعنصتت الواحتد أن يحتتتوي علتتى معطيتتات متن أي نتوع.‬ ‫ً‬ ‫وسوف نقوم باستكشاف هذه المية طوال هذه الملثلة القادمة .‬ ‫القوائم يمكن تغييرها‬ ‫على عكس السلسل النصية، القوائم هي تسلسل قابل للتغيي. وهذا سيسمح لنا لحقا ببناء قوائم كبية الحجم، قطعة قطعتتة،‬ ‫ً‬
‫71 = ]0[‪>>> nombres‬‬ ‫‪>>> nombres‬‬ ‫]52 ,01 ,83 ,71[‬

‫بطريقة ديناميكية )و هذا معناه بمساعدة أي خوارزمية(. على سبيل اللثال :‬

‫في اللثال أعله، قمنا باستبدال العنص الول من القائمة ‪ ،nombres‬باستخدام العامل ] [ )على يسار علمة الساوات.‬ ‫فإذا كنت تريد الوصول إلى عنص في قائمة داخل قائمة أخرى. يكفي أن تشي ببساطة إلى ملؤش بي قوسي )نصف مربع( :‬
‫"‪>>> stuff[3][1] = "Isabelle‬‬ ‫‪>>> stuff‬‬ ‫]]7491 ,'‪[5000, 'Brigitte', 3.1415999999999999, ['Albert', 'Isabelle‬‬

‫351‬

‫النقطة في القوائم‬

‫كما هو الحال بالنسبة لجميع التسلسلت، يجب علينا أن ل ننستت أن التتقيم يبتدأ متن الصتفر. وبالتتالي، فتي اللثتال أعله قمنتا‬ ‫باستبدال العنص رقم 1 في قائمة، والذي هو العنص 3 في قائمة أخرى : سلسلة ‪.stuff‬‬ ‫القوائم هي كائنات‬ ‫في بيلثون، القوائم هي كائنات في حد ذاتها، ويمكنك إ ذا تطبيق عدد من الساليب الفعالة عليها بشكل خاص. وهذه بعضها :‬ ‫ً‬
‫]27 ,52 ,01 ,83 ,71[ = ‪>>> nombres‬‬ ‫)(‪>>> nombres.sort‬‬ ‫‪>>> nombres‬‬ ‫]27 ,83 ,52 ,71 ,01[‬ ‫)21(‪>>> nombres.append‬‬ ‫‪>>> nombres‬‬ ‫]21 ,27 ,83 ,52 ,71 ,01[‬ ‫)(‪>>> nombres.reverse‬‬ ‫‪>>> nombres‬‬ ‫]01 ,71 ,52 ,83 ,27 ,21[‬ ‫)71(‪>>> nombres.index‬‬ ‫4‬ ‫)83(‪>>> nombres.remove‬‬ ‫‪>>> nombres‬‬ ‫]01 ,71 ,52 ,27 ,21[‬ ‫قم يبفرز القائمة #‬

‫أضف عنصر إلى النهاية #‬

‫اعكس ترتيب العناصر #‬

‫جد مؤشر عنصر #‬ ‫إظحذف عنصر #‬

‫و بالضافة إلى هذه الساليب، يوجد أيضا التعليمة الدمجة ‪،del‬تت الذي تسمح لك بحذف عنص أو أكث من خلل ملؤشتته )أو‬ ‫ملؤشاتهم( :‬
‫]2[‪>>> del nombres‬‬ ‫‪>>> nombres‬‬ ‫]01 ,71 ,27 ,21[‬ ‫]3:1[‪>>> del nombres‬‬ ‫‪>>> nombres‬‬ ‫]01 ,21[‬

‫لحتتظ الفتترق بيتت الستتلوب ‪ ()remove‬والتعليمتتة ‪ del : del‬تعمتتل متتع ملؤشتت أو شتتيحة اللؤشتت، فتتي حيتت أن‬ ‫‪ ()remove‬تبحث عن القيمة )فإذا كان يوجد العديد من العناص بنفس القيمة يتم مسح الولى فقط( .‬

‫تمارين‬
‫01.72 اكتب سكريبت يقوم بإنشاء قائمة من الربعات والكعبات عددها 02 إلى 04 .‬ ‫01.82 اكتب السكريبت يقوم تلقائيا بصنع قائمة من النحنيات ذات زوايا من 0° إلى 09°، في خطوات من 5°. تنبيه : الدالة‬ ‫‪ ()sin‬لوحدة ‪ math‬تعتب أن الزوايا بالراديان )063° = 2 ‪ π‬راديان( .‬

‫المزيد من هياكل البيانات‬

‫451‬

‫01.92 اكتب سكريبت يسمح بعرض أول 51 نتيجة لجدول الضب على 2، 3، 4، 5، 7، 31، 71، 91 )هذه القام سوف يتم‬ ‫وضعها في بداية القائمة( في عشكل جدول مشابه للجدول التالي :‬
‫2‬ ‫3‬ ‫5‬ ‫4‬ ‫6‬ ‫01‬ ‫6‬ ‫9‬ ‫51‬ ‫8‬ ‫21‬ ‫02‬ ‫01‬ ‫51‬ ‫52‬ ‫21‬ ‫81‬ ‫03‬ ‫41‬ ‫12‬ ‫53‬ ‫61‬ ‫42‬ ‫04‬ ‫81‬ ‫72‬ ‫54‬ ‫02‬ ‫03‬ ‫05‬ ‫22‬ ‫33‬ ‫55‬ ‫42‬ ‫63‬ ‫06‬ ‫62‬ ‫93‬ ‫56‬ ‫82‬ ‫24‬ ‫07‬ ‫03‬ ‫54‬ ‫57‬

‫.إلخ‬
‫,’‪Jean-Michel‬‬ ‫,’‪’Marc‬‬ ‫,’‪’Vanessa‬‬ ‫,’‪’Anne‬‬ ‫01.03 انظتتتتتر للقائمتتتتتة التاليتتتتتة : ]’,’‪’Maximilien‬‬

‫‪[’’Alexandre-Benoît’, ’Louise‬‬ ‫اكتب سكريبت يقوم بعرض اسم من هذه السماء مع عدد الحروف الت يتكون منها .‬ ‫01.13 لديك قائمة من أي العداد صحيحة، بعضتها مكترر فتتي أمتاكن مختلفتتة فتتي القائمتتة. اكتتتب ستكريبت يقتوم بنستتخ هتتذه‬ ‫القائمة في قائمة أخرى مع حذف التكرار )سيتم فرز القائمة النهائية( .‬ ‫01.23 اكتب سكريبت يبحث عن الكلمة الطول في الجملة القدمة )يجب على الستخدم أن يدخل الجملة حسب اختياره(‬ ‫01.33 اكتب سكريبت يقوم بعتترض قائمتتة بكتتل أيتام الستتنة متن مخيلتتتك، والتت تبتدأ بيتوم الخميتتس. الستتكريبت الختاص بتتك‬ ‫يستخدم 3 قوائم : قائمة بأيام السبوع، قائمة بأسماء العشهر، وقائمة بعدد اليام لكل عشتتهر)تجاهتتل الستتنة الكبيستتة(.‬ ‫على سبيل اللثال :‬
‫‪jeudi 1 janvier‬‬ ‫‪vendredi 2 janvier‬‬ ‫‪samedi 3 janvier‬‬ ‫‪dimanche 4 janvier‬‬

‫و هكذا إلى يوم 13 ديسمب )كانون الول(‬ ‫01.43 لديك ملف نص يحتوي على أسماء التلميذ. اكتب سكريبت يقوم بنسخة مرتبة من هذا اللف .‬ ‫01.53 اكتب دالة تقوم بفرز قائمة. هذه الدالة ل يجب عليها أن تستخدم السلوب الدمج ‪ ()sort‬الخاص ببيلثون : لذا يجتتب‬ ‫عليك أن تقوم بنفسك بكتابة خوارزمية الفرز .‬ ‫تقنيات تقطيع متقدم للتعديل على قائمة‬ ‫كما لحظنا للتو، يمكنك إضافة أو حذف عناص في قائمة باستخدام التعليمة )‪ (del‬والسلوب )‪ (()append‬الدمج. فتتإذا‬ ‫كان ليزال لديك فهم أساس "للتقطيع إلى شائح"، يمكنك إذا الحصول على نفس النتائج بمساعدة معامل واحد ] [. استخدام‬ ‫هذا العامل هو أكث عرضة للتلف من التعليمات أو الساليب الخصصة، لكنه يسمح بمزيد من الرونة :‬ ‫إدخال عنصر أو أكثر في أي مكان في القائمة‬
‫]'‪>>> mots = ['jambon', 'fromage', 'confiture', 'chocolat‬‬ ‫]"‪>>> mots[2:2] =["miel‬‬ ‫‪>>> mots‬‬ ‫]'‪['jambon', 'fromage', 'miel', 'confiture', 'chocolat‬‬ ‫]'‪>>> mots[5:5] =['saucisson', 'ketchup‬‬

‫551‬

‫النقطة في القوائم‬

‫‪>>> mots‬‬ ‫]'‪['jambon', 'fromage', 'miel', 'confiture', 'chocolat', 'saucisson', 'ketchup‬‬

‫لستخدام هذه التقنية، يجب عليك أن تعرف هذه الميات :‬ ‫•إذا استخدمت العامل ] [ على يسار علمة الساواة لدراج أو حذف عنص أو عناص في قائمة، يجب عليتتك أن تشتتي إلتتى‬ ‫"الشيحة" في القائمة الستهدفة )و هذا معناه ملؤشين الذين جمعتهمتتا باستتخدام الرمتتز :(، وليتس عنصتت واحتد فتتي هتذه‬ ‫القائمة .‬ ‫• يجب على العنص الذي على يمي علمة الساوات أن يكون قائمة. فإذا لم تدرج سوى عنص واحد، يجب عليك إذا تقديمه‬ ‫بيتت معقتتوفي لتحويتتل أول إلتتى سلستتلة بعنصتت واحتتد. لحتتط أن العنصتت 1[‪ [mots‬ليتتس قائمتتة ) هتتو سلستتلة "‬ ‫‪ ،("fromage‬إذا العنص 3:1[‪ [mots‬في واحدة.‬ ‫سوف تفهم بشكل أفضل من خلل تحليل ما يلي :‬ ‫إزالة \ الستبدال عناصر‬
‫][ = ]5:2[‪>>> mots‬‬ ‫يدل على قائمة فارغة ][ #‬ ‫‪>>> mots‬‬ ‫]'‪['jambon','fromage','saucisson', 'ketchup‬‬ ‫]'‪>>> mots[1:3] = ['salade‬‬ ‫‪>>> mots‬‬ ‫]'‪['jambon', 'salade', 'ketchup‬‬ ‫]'‪>>> mots[1:] = ['mayonnaise', 'poulet', 'tomate‬‬ ‫‪>>> mots‬‬ ‫]'‪['jambon', 'mayonnaise', 'poulet', 'tomate‬‬

‫•في السطر الول من ملثالنا، قمنا باستبدال الشيحة ]5:2[ بقائمة فارغة، والذي يتوافق مع الذي حذفناه.‬ ‫• في السطر الرابع، قمنا باستبدال شيحة بعنص واحد. لحظ مرة أخرى أن هذا العنص هو فتتي حتتد ذاتتته "يعتترض" علتتى‬ ‫عشكل قائمة.‬ ‫• في السطر السابع، قمنا باستبدال الشيحة بها عنصان بأخرى بها‬

‫المزيد من هياكل البيانات‬

‫651‬ ‫إنشاء قائمة من الرقام بمساعدة الدالة )(‪range‬‬

‫إذا كان يجب عليك التعامل مع سلسل من الرقام، يمكنك إنشاؤها بستتهولة بمستتاعدة هتتذه الدالتتة الدمجتتة. فهتتي تقتوم بإرجتاع‬ ‫سلسلة من العداد الصحيحة الت يمكنك استخدامها مباشة، أو تحويلها إلى سلسلة عن طريق الدالة ‪ ،()list‬أو تحويلها إلى‬
‫06‬

‫‪ tuple‬بمساعدة الدالة ‪) ()tuple‬سوف نقوم بشح ال ‪ tuples‬في وقت لحق( :‬
‫))01(‪>>> list(range‬‬ ‫]9 ,8 ,7 ,6 ,5 ,4 ,3 ,2 ,1 ,0[‬

‫الدالة ‪ ()range‬تقوم افتاضتتيا بتوليتد سلستلة متن العتداد الصتحيحة بشتتكل متايتد، ومختلفتتة بعتدد واحتد. فتإذا استتدعيت‬ ‫‪ ()range‬مع برامت واحد، القائمة ستحتوي على عدد الرقام القيم الساوية للبامت القدم، لكنها تبدأ من الرقم صفر )و هتتذا‬ ‫معناه أن ‪ (range(n‬سوف تقوم بتوليد الرقام من 0 إلى )1-‪ .(n‬لحظ أن البامت القدم لن يكون في السلسلة.‬ ‫يمكننا استخدام ‪ ()range‬مع برامتين أو 4 برامتات مفصولة بفواصل، لتوليد متواليات من أعداد أكث تحديدا :‬
‫>>>‬ ‫,5[‬ ‫>>>‬ ‫,3[‬ ‫))31,5(‪list(range‬‬ ‫]21 ,11 ,01 ,9 ,8 ,7 ,6‬ ‫))3,61,3(‪list(range‬‬ ‫]51 ,21 ,9 ,6‬

‫فإذا كان لديك صعوبة في استيعاب اللثال أعله، افتض أن ‪ ()range‬تنتظر منك دائما 3 برامتات، والت يمكن أن نستتميها‬ ‫الخطوة للقفز من قيمة لخرى. فإذا لم نضعها فإن البامتين ‪ FROM‬و ‪ STEP‬ستكون قيمتهم افتاضية هي 0 و 1.‬

‫‪ FROM‬و ‪ TO‬و ‪ .STEP‬و ‪ FROM‬هي القيمة الولى لتوليدها، ‪ TO‬هي الخية )أو بالحرى الخية مع واحتتد(، و ‪ STEP‬هتتي‬ ‫و يسمح بالبامتات السلبية :‬
‫))3- ,01- ,01(‪>>> list(range‬‬ ‫]8- ,5- ,2- ,1 ,4 ,7 ,01[‬

‫تكرار القائمة بمساعدة ‪ for‬و)(‪ range‬و)(‪len‬‬ ‫العبارة ‪ for‬هي العبارة اللثالية لتكرار قائمة:‬
‫]'‪>>> prov = ['La','raison','du','plus','fort','est','toujours','la','meilleure‬‬ ‫:‪>>> for mot in prov‬‬ ‫...‬ ‫)' '= ‪print(mot, end‬‬ ‫...‬ ‫‪La raison du plus fort est toujours la meilleure‬‬

‫فإذا كنت تريد تكرار مجموعة من العداد الصحيحة، الدالة ‪ ()range‬ستكون مناسبة:‬
‫06‬ ‫إن ‪ ()range‬تعيطي ف الواقع الوصول إل الكرر )ك ائن بياثون مولد لةتسلسلت(, ولكن شرحه ا خ ارج إط ار الذي وضعن اه لذه‬ ‫الكةت اب. يرجى الرجوع إل ق ائومة مراجع, صفحة31, أو وث ائق بياثون على النةترنت إذا كنت تريد الةتوضيح .‬

‫751‬
‫:)3 ,81 ,01(‪>>> for n in range‬‬ ‫...‬ ‫)3**‪print(n, n**2, n‬‬ ‫...‬ ‫0001 001 01‬ ‫7912 961 31‬ ‫6904 652 61‬

‫النقطة في القوائم‬

‫من الريح الجمع بي الدالت ‪ ()range‬و ‪ ()len‬للحصول تلقائيا على كافة ملؤشات لتسلسل )قائمة أو سلسلة(. على سبيل‬ ‫اللثال :‬
‫]'‪fable = ['Maître','Corbeau','sur','un','arbre','perché‬‬ ‫:))‪for index in range(len(fable‬‬ ‫)]‪print(index, fable[index‬‬

‫تشغيل هذا البنامج سيظهر لنا :‬
‫0‬ ‫1‬ ‫2‬ ‫3‬ ‫4‬ ‫5‬ ‫‪Maître‬‬ ‫‪Corbeau‬‬ ‫‪sur‬‬ ‫‪un‬‬ ‫‪arbre‬‬ ‫‪perché‬‬

‫نتيجة هامة من الطباعة الديناميكية‬ ‫كما لحظنا سابقا )في الصفحة 331(، نوع التغي الستخدم مع العبارة ‪ for‬سيتم إعادة تعريفه بإستمرار في الدورات : حتتت‬ ‫لو كانت عناص القائمة بأنواع مختلفة، يمكننا تكرار هذه القائمة بمساعدة ‪ for‬بدون أي خطأ، لن نتتوع التغيتت فتتي التتدورات‬ ‫)الحلقات( سوف يتم تعديله تلقائيا إلى نوع العنص الذي يتم قراءته. على سبيل اللثال :‬
‫]'‪>>> divers = [3, 17.25, [5, 'Jean'], 'Linux is not Windoze‬‬ ‫:‪>>> for item in divers‬‬ ‫...‬ ‫))‪print(item, type(item‬‬ ‫...‬ ‫>'‪3 > fruits = ['orange','citron‬‬ ‫]'‪>>> legumes = ['poireau','oignon','tomate‬‬ ‫‪>>> fruits + legumes‬‬ ‫]'‪['orange', 'citron', 'poireau', 'oignon', 'tomate‬‬

‫المزيد من هياكل البيانات‬
‫3 * ‪>>> fruits‬‬ ‫]'‪['orange', 'citron', 'orange', 'citron', 'orange', 'citron‬‬

‫851‬

‫العامل * مفيد جدا لنشاء قائمة من ‪ n‬عناص متطابقة :‬
‫7*]0[ = ‪>>> sept_zeros‬‬ ‫‪>>> sept_zeros‬‬ ‫]0 ,0 ,0 ,0 ,0 ,0 ,0[‬

‫على سبيل اللثال، أنت تريد صنع قائمة ‪ B‬الذي تحتوي على نفس العدد من العناص في قائمتتة ‪ .A‬يمكنتتك إنجتتاز هتتذا بطتترق‬ ‫مختلفة، ولكن أبسطها هي : ‪.(B = [0]*len(A‬‬ ‫اختبار العضوية‬ ‫يمكنك بسهولة تحديتتد متتا إذا كتتان العنصتت هتتو جتتزء متن قائمتتة أو ل بمستتاعدة العبتتارة ‪) in‬هتتذه العبتتارة يمكتتن استتتخدامها متتع‬ ‫التسلسلت( :‬
‫'‪>>> v = 'tomate‬‬ ‫:‪>>> if v in legumes‬‬ ‫...‬ ‫)'‪print('OK‬‬ ‫...‬ ‫‪OK‬‬

‫نسخ الئحة‬ ‫نفتض أن لديك قائمة تريد نسخها في متغي جديد يسمى ‪ .phrase‬فإن أول فكتترة تتبتادر إلتتى ذهنتتك هتتي أن تكتتتب مهمتتة‬ ‫بسيطة ملثل :‬
‫‪>>> phrase = fable‬‬

‫متن خلل القيتتام بتذلك، اعلتم أنتك لتم تقتم بصتتنع نستتخة أصتتلية. بعتتد هتذه التعليمتتة، ل توجتتد ستوى قائمتتة واحتدة فتتي ذاكترة‬ ‫الحاسوب. أنت لم تقم سوى بصنع مرجع بسيط لهذه القائمة. حاول على سبيل اللثال :‬
‫]'‪>>> fable = ['Je','plie','mais','ne','romps','point‬‬ ‫‪>>> phrase = fable‬‬ ‫'‪>>> fable[4] ='casse‬‬ ‫‪>>> phrase‬‬ ‫]'‪['Je', 'plie', 'mais', 'ne', 'casse', 'point‬‬

‫إذا كان التغي ‪ phrase‬يحتوي علتتى نستتخة أصتتلية متتن القائمتتة، ستتوف تكتتون هتتذه النستتخة مستتتقلة عتتن النتتص الصتتلي،‬ ‫وينبغي أل يتم تعديلها بتعليمة ملثل الت بالسطر اللثالث، الت تطبق على التغي ‪ .fable‬يمكنك تجربة الزيتتد متتن التغييتتات‬ ‫الخرى، سواء على محتويات ‪،fable‬ت أو علتى محتويتتات ‪ .phrase‬فتتي جميتتع الحتتوال، ستوف تجتد أن التعتديلت عتدلت‬ ‫أيضا على الخرى، والعكس بالعكس .‬

‫951‬

‫النقطة في القوائم‬

‫في الواقع، ‪ fable‬و ‪ phrase‬تم تعيي كلهما في كائن واحد في الذاكرة. لوصف هذه الحالتتة، يقتتول علمتتاء الحاستتوب أن‬ ‫‪ phrase‬هو اسم مستعار لت ‪.fable‬‬ ‫سوف نرى لحقا، استخدام السم الستعار. أما الن، سوف نتعلم تقنية عمل نسخة أصلية )فعلية( لقائمة. مع الفاهيم الذكورة‬ ‫أعله، يجب أن تكون قادرا على إيجاد واحدة بنفسك .‬ ‫ملحظة بسيطة حول تركيب الجملة‬ ‫بيلثون يسمح لك "بتوسيع" تعليمة طويلة على عدة أسطر، فإذا استمررت بتمي شء ما محدد بواسطة زوج متن القتتواس، أو‬ ‫العقوفي، أو قوسي )نصف مربع(. يمكنك معالجة العبارات بي قوسي، أو تعريف قوائم طويلة، أو ‪ tuples‬كبية أو قواميس‬ ‫كبية)انظر أدناه(. مستوى مسافة البادئة غي مهم : الفس يكشف عن نهاية العبارة حيث يتم إغلق زوج الركب.‬ ‫هذه الية تسمح لك بتحسي إمكانية قراءة برامجك. على سبيل اللثال :‬
‫,'‪couleurs = ['noir', 'brun', 'rouge‬‬ ‫,'‪'orange', 'jaune', 'vert‬‬ ‫]'‪'bleu', 'violet', 'gris', 'blanc‬‬

‫تمارين‬
‫01.63 انظر في القوائم التالية :‬
‫]13,03,13,03,13,13,03,13,03,13,82,13[ = 1‪t‬‬ ‫,'‪t2 = ['Janvier','Février','Mars','Avril','Mai','Juin‬‬ ‫]'‪'Juillet','Août','Septembre','Octobre','Novembre','Décembre‬‬

‫اكتب برنامجا صغيا يقوم بإدراج جميع عناص القائمة الولى في القائمة اللثانية ، بحيث يتم فرز كل استتم عشتتهر متتع‬ ‫عدد أيامه :‬
‫.].‪['Janvier',31,'Février',28,'Mars',31, etc‬‬

‫المزيد من هياكل البيانات‬

‫061‬

‫01.73 اصنع قائمة ‪ A‬تحتوي على بضعة عناص. قم بعمل نسخة منها في متغي جديد ‪ .B‬اقتاح : قم أول بصنع القائمة‬ ‫‪ B‬بنفس طول القائمة ‪ A‬لكنها ل تحتوي سوى على أصفار. ثم قم باستبدال كل الصفار بعناص من القائمة ‪.A‬‬ ‫01.83 نفس السلؤال، لكن اقتاح آخر : قم أول بصنع القائمة ‪ B‬فارغة. ثم قم بملئها بالعناص القائمة ‪ A‬واحدة تلو الخرى.‬

‫01.93 نفس السلؤال، لكن اقتاح آخر : لصنع القائمة ‪ ،B‬قم بقص شيحة من القائمة ‪A une tranche incluant tous‬‬
‫تحتوي على كل العناص )بمساعدة العامل ]:[(.‬ ‫01.04 الرقم الولي هو الرقم الذي يقبل القسمة على نفسه وعلى واحد. اكتب برنامجا يقوم بعرض جميتتع الرقتتام الوليتتة متتا‬ ‫بي 1 و 0001، باستخدام أسلوب غربال إراتونسلثي :‬ ‫•أصنع قائمة من 0001 عنص، قم بتهيئة كل عنص على القيمة 1.‬ ‫• إستعرض هذه القائمة بداية من العنص اللثتتاني : إذا كتتان العنصتت حلتتل لتتديه القيمتتة 1، ضتتع 0 لجميتتع العناصتت الباقيتتة،‬ ‫والت هي ملؤشات مضعفات العدد الصحيح للملؤش الذي حصلت عليه .‬ ‫•عندما تستعرض جميع القائمة، ملؤشات العناص الت بقية 1 ستيكونون الرقتتام الوليتتة التت نبحتتث عنهتتا. فتتي الحقيقتتة :‬ ‫بداية من اللؤش 2، ستلغي جميع العناص الزوجية : 4، 6، 8، 01 ...إلخ. مع اللؤش 3، سوف تقوم بإلغاء جميع العناص‬ ‫اللؤش 6، 9، 21، 51 ...إلخ، وهكذ. والعناص الت بقيت 1 هي أرقام أولية .‬ ‫الرقام العشوائية - المدرج الحصائي‬ ‫معظم البامج تقوم بعمل الشء نفسه في كل مرة تقوم بتشغيلها. وتسمي هذه البامج بالحتمية )الحددة(. الحتمية هتتي شتتء‬ ‫جيد : بالطبع نحن نريد نفتس السلستتلة متن العمليتتات الحستتابية تطبتق علتتى نفتتس العطيتتات تتتلؤدي دائمتا إلتى نفتتس النتيجتتة.‬ ‫لبعض التطبيقات، إن الحاسوب صعب تكهنه. على سبيل اللثال اللعاب هي ملثال واضح، هنالك العديد من الخرين.‬ ‫على عكس الظاهر، فإنه ليس من السهل كتابة خوارزمية هتتي حقتتا غيتت حتميتتة )و هتتذا معنتتاه أن تنتتتج نتيجتتة ل يمكتتن التنبتتلؤ‬ ‫بها(. ومع ذلك، هنالك تقنيات رياضية لحاكات أكث أو أقل نتيجة الصدفة. لقد كتبت كتب بالكامل لشح كيفية إنتاج عشوائي‬ ‫"بنوعية جيدة". ونحن بالطبع لن نضع سلؤال كهذا.‬ ‫في وحدة ‪ ،random‬يقدم لك بيلثون مجموعة متنوع من الدالت لتوليد أرقام عشوائية تتبع توزيعات رياضية مختلفة. نحن‬ ‫لن نجرب هنا سوى بعضها. اطلع على وثائق بيلثون على الشبكة لعرفة الزيد. يمكنك استدعاء جميع الدالت في الوحدة بت :‬
‫* ‪>>> from random import‬‬

‫الدالة ‪ random‬لوحدة ‪ random‬تسمح لك بإنشاء أعداد حقيقية عشتتوائية ذات قيمتتة متابي 0 و 1. البامتتت هتتو حجتتم القائمتتة‬ ‫الطلوبة :‬

‫161‬
‫:)‪>>> def list_aleat(n‬‬ ‫...‬ ‫‪s = [0]*n‬‬ ‫...‬ ‫:)‪for i in range(n‬‬ ‫...‬ ‫)(‪s[i] =random‬‬ ‫...‬ ‫‪return s‬‬ ‫...‬ ‫)3(‪>>> list_aleat‬‬ ‫]421830733465417.0 ,66887491505795430.0 ,76787226011848573.0[‬ ‫)3(‪>>> list_aleat‬‬ ‫]2561706558237028.0 ,9864364486682773.0 ,1394620975201518.0[‬

‫النقطة في القوائم‬

‫يمكنك أن ترى أننا أول أخذنا جزءا ببناء قائمة من الصفار بطول ‪ ، n‬ثم قمنا باستبدال الصفار بأرقام عشوائية .‬

‫تمارين‬
‫01.14 أعد كتابة الدالة ‪ ()list_aleat‬في العلى، باستخدام السلوب ‪ ()append‬لصنع قائمة جزءا جتزءا بدايتتة متتن‬ ‫قائمة فارغة )بدل من استبدال الصفار من قائمة موجودة سابقا كما فعلنا قبل قليل(.‬ ‫01.24 اكتب الدالة ‪ ()imprime_liste‬الت تسمح بإظهار جميع العناص الوجودة في قائمة بتتأي حجتتم ستتطرا ستتطرا.‬ ‫اسم القائمة سيكون في البامت ، استخدم هذه الدالة لطباعتة قائمتة متن الرقتتام العشتوائية التت تتم صتنعها بواستطة‬ ‫الدالتتة ‪ .()list_aleat‬علتتى ستتبيل اللثتتال التعليمتتة 8(‪ ((imprime_liste(liste_aleat‬ستتوف تقتتوم بعتترض‬ ‫عمود من 8 أرقام حقيقية عشلؤائية .‬ ‫هل الرقام الت تم تولدها هي فعل عشتتوائية ؟ هتذا الشتء صتتعب قتوله. نحتن لتم نفعتل ستوى لعتدد قليتتل متن القيتم، ل يمكننتا‬ ‫التحقق من هذا. ومن جانب آخر، إذا استخدمنا الدالة ‪،()random‬ت مترات عديتتدة، نتوقتتع أن يكتتون نصتتف القيتم النتجتتة هتتي‬ ‫أكب من 5.0 )و النصف الخر أقل(.‬ ‫نركز على هذا النطق. القيتم التت يتتم الحصتول عليهتا هتي دائمتا فتتي نطتاق 0 - 1. مشتاركة هتذا الفاصتتل الزمنتت فتتي 4 أجتزاء‬ ‫متستتاوية : متتن 0 إلتتى 52.0 و متتن 52.0 إلتتى 5.0 ومتتن 5.0 إلتتى 57.0 ومتتن 57.0 إلتتى 1 فتتإذا وضتتعنا عتتددا كتتبيا متتن القيتتم‬ ‫العشوائية، نحن نتوقع أنه سيكون هنالك الكلثي من النخفتتاض فتتي الكستتور الربعتتة. ويمكننتتا تعميتتم هتتذا النطتتق إلتتى رقتم أي‬ ‫كس، طالا أنهم متساوون .‬ ‫01.34 اكتب برنامجا يتحقق من عمل مولد الرقام العشوائية في بيلثون باستخدام النظريتتة التذكورة أعله . البنامتج ستيقوم‬ ‫بالتالي :‬ ‫• أطلب من الستخدم عدد القيم العشوائية الت سيتم إنشاؤها بمساعدة الدالتة ‪ .()random‬وستيكون متن التلثي للهتمتام‬ ‫أن يوفر البنامج عددا افتاضيا )0001 على سبيل اللثال( .‬

‫تمرين‬

‫المزيد من هياكل البيانات‬

‫261‬

‫• اطلب من الستخدم كم يريد لمشاركة في مجموعة قيم الكسور المكنة )و هذا معناه ما بي 0-1(. هنا أيضا، يجب أن تقتتدم‬ ‫عدد الكسور الفتاض )5 على سبيل اللثال(. يمكنك أن تحدد للمستخدم ما بي 2 و 1\01 عدد القيم العشوائية.‬ ‫•قم ببناء قائمة من ‪ N‬عدادات )‪ N‬ستكون عدد من الكسور الطلوبة(. وسيتم تهيئة كل واحدة منهم إلى الصفر.‬ ‫•إسحب عشوائيا جميع القيم الطلوبة، بمساعدة الدالة ‪ ، ()random‬وقم بتخزين هذه القيم داخل قائمة .‬ ‫• قم بتدوير قائمة القيم الت تم سحبها عشوائيا )حلقة(، وقم بإجراء اختبتار لكتل واحتد منهتا لتحديتد متا هتي جتزء متن فتتة‬ ‫الفاصلة 0-1 هي عليها. يزداد العداد واحد واحد .‬ ‫•عند النتهاء، اعرض حالة كل عداد .‬ ‫مثال على نتائج الت يتم عرضها من برنامج من هذا النوع :‬
‫: )0001 = ‪Nombre de valeurs à tirer au hasard (défaut‬‬ ‫‪Nombre de fractions dans l'intervalle 0-1 (entre 2 et‬‬ ‫... ‪Tirage au sort des 100 valeurs‬‬ ‫... ‪Comptage des valeurs dans chacune des 5 fractions‬‬ ‫02 41 52 03 11‬ ‫: )0001 = ‪Nombre de valeurs à tirer au hasard (défaut‬‬ ‫‪Nombre de fractions dans l'intervalle 0-1 (entre 2 et‬‬ ‫... ‪Tirage au sort des 10000 valeurs‬‬ ‫... ‪Comptage des valeurs dans chacune des 5 fractions‬‬ ‫2602 5391 1602 2791 0791‬ ‫001‬ ‫5 : )5= ‪10, défaut‬‬

‫00001‬ ‫5 : )5= ‪1000, défaut‬‬

‫أسلوب جي د لهذه الشكلة من خلل تصور دالت بسيطة لكتابتها لحل جزء أو آخر من الشكلة، ثم استخدامها لعشياء أكب.‬ ‫علتتى ستتبيل اللثتتال، تستتتطيع أول أن تحتتاول تعريتتف الدالتتة ‪ ()numeroFraction‬التتت تحتتدد أي جتتزء متتا بيتت 0-1‬ ‫)قيمةالستمدة(. هذه الدالة تأخذ برامتين )القيمة الستمدة، عدد الكسور الت يتتتم اختيارهتتا متتن قبتتل الستتتخدم( ويقتتوم بإرجتتاع‬ ‫ملؤش العداد لزيادته )هذا معناه رقم الكس(. قد يكون هنالك منطق رياض بستتيط التذي يستتمح لتتك بتحديتتد اللؤشتت الكستت متن‬ ‫هذين البامتتان. بمتتا فتتي ذلتك الدالتتة الدمجتتة ‪،()int‬ت التتت تستتمح لتك بتحويتتل عتتدد حقيقتتي إلتى عتدد صتتحيح بإزالتتة الجتتزء‬ ‫فإذا لم تجدها، فكرة أخرى ملثي للهتمام، إبدأ ببناء قائمة تحتوي على القيم "الحاور" الت تحدد الكستتور الحتتددة )علتتى ستتبيل‬ ‫اللثال 0 – 52,0 – 5,0 – 57,0 - 1 في حالة 4 كسور(. معرفة هذه القيم قد يسهل كتابة الدالة ‪()numeroFraction‬‬ ‫الت نريد أن نطورها.‬ ‫إذا كان لديك الزيد من الوقت، يمكنك أيضا صتنع نستتخة رستومية متن البنامتج، والتت ستوف تعترض لتك النتائتج علتى رستم‬ ‫بياني )الرسم البياني "بالعصا"(‬ ‫العشي.‬

‫361‬

‫النقطة في القوائم‬ ‫لسحب العداد الصحيحة عشوائيا‬ ‫ً‬

‫‪ L‬عندما تطور مشاريعك الشخصية، سوف تحتاج إلى الكلثي من الحيان إلى دالة تسمح لك عشوائيا بستتحب عتدد صتحيح فتي‬ ‫حدود معينة. على سبيل اللثال، فإذا أردت كتابة برنامج للعبة أوراق اللعب الت يتم سحبها عشوائيا )اللعبة العادية 25 ورقة(،‬ ‫سوف تستخدم بكل تأكيد دالة يمكنها سحب عدد صحيح عشوائيا ما بي 1 و 25 .‬ ‫يمكنك القيام بهذا عن طريق الدالة ‪ ()randrange‬للوحدة ‪ .random‬هذه الدالة تستخدم مع 1 أو 2 أو 3 برامتات.‬ ‫باستخدام برامت واحد، تقوم بإرجاع عدد صحيح ما بي 0 والقيمة البامت ناقص 1. على سبيل اللثتتال، 6(‪(randrange‬‬ ‫سوف تقوم بإرجاع عدد ما بي 0 و 5.‬ ‫باستتتخدام برامتتتين، العتتدد التتذي ستتيتم إرجتتاعه ستتيكون متتا بيتت البامتتت الول والبامتتت اللثتتاني نتتاقص واحتتد. علتتى ستتبيل اللثتتال،‬ ‫8 ,2(‪ (randrange‬تقوم بإرجاع عدد ما بي 2 و 7.‬ ‫و إذا أضتتفنا برامتتت ثتالث، فتتإنه يشتتي إلتتى أن العتتدد التتذي يجتتب ستتحبه يجتتب أن يكتتون متتن مجموعتتة متتن العتداد محتددة متتن العتداد‬ ‫الصحيحية، ويتم فصلها عن بعض بفاصل معي، الذ تم تعريفه بالبامت اللثالث. على سبيل اللثال، 3 ,31 ,3(‪(randrange‬‬ ‫سوف تقوم بإرجاع عدد من 3، 6، 9، 21 :‬
‫‪>>> from random import randrange‬‬ ‫:)51(‪>>> for i in range‬‬ ‫...‬ ‫)' '= ‪print(randrange(3, 13, 3), end‬‬ ‫...‬ ‫21 3 9 3 9 3 9 21 21 21 3 3 21 6 21‬

‫01.44 اكتتتب ستتكريبت يقتتوم بستتحب عشتتوائيا أوراق اللعتتب. استتم الورقتتة التتت يتتتم ستتحبها يجتتب أن يكتتون قتتد عتترض بشتتكل‬
‫>‪Frappez ‪Frappez ‪Frappez ‪Frappez >> print(liste‬‬ ‫]'‪['jambon', 'salade', 'confiture', 'chocolat‬‬ ‫'‪>>> chaine ='Roméo préfère Juliette‬‬ ‫'‪>>> chaine[14:] ='Brigitte‬‬ ‫‪***** ==> Erreur: object doesn't support slice assignment‬‬ ‫*****‬

‫للتعديل، على سبيل اللثال :‬

‫لقد حاولنا تغيي نهاية السلسلة النصية، لكننتتا لتم ننجتتح. الستتبيل الوحيتتد لتحقيتتق أهتتدافنا هتتو بصتتنع سلستتلة جديتدة، ونقتتوم‬
‫'‪>>> chaine = chaine[:14] +'Brigitte‬‬ ‫)‪>>> print(chaine‬‬ ‫‪Roméo préfère Brigitte‬‬

‫بنسخ ما نريد تغييه :‬

‫توفر لك بيلثون نوعا من البيانات يدعى الصتفوفة الغلقتتة ‪ ، tuple‬وهتتو يشتتبه كتلثيا القتتوائم، لكنتته ملثتتل السلستل، ل يمكتن‬
‫16‬

‫تعديله.‬ ‫من النظور اللغوي، الصفوفة الغلقة )‪ (tuple‬هي مجموعة من العناص مفصولة بفواصل :‬
‫'‪>>> tup = 'a', 'b', 'c', 'd', 'e‬‬ ‫)‪>>> print(tup‬‬ ‫)'‪('a', 'b', 'c', 'd', 'e‬‬

‫على الرغم من أنه غي ضوري، لكن من الستحسن تحديد الصفوفة الغلقة )‪ (tuple‬بزوج من القتتواس، ملثتتل الدالتتة ‪()print‬‬ ‫في بيلثون. هذا ببساطة لزيادة إمكانية قراءة الكود، لكن هذا مهم .‬
‫)'‪>>> tup = ('a', 'b', 'c', 'd', 'e‬‬

‫العمليات على المصفوفات المغلقة )‪(tuples‬‬ ‫ل يمكن أن تعمل العمليات على الصتفوفة الغلقتتة )‪ (tuple‬بنتاء جملتتة الصتفوفات الغلقتتة )‪ (tuples‬ليتتس مماثتتل للقتتوائم، لن‬ ‫الصفوفات الغلقة )‪ (tuples‬غي قابلة للتغيي :‬
‫)]4:2[‪>>> print(tup‬‬ ‫)'‪('c', 'd‬‬ ‫)'‪>>> tup[1:3] = ('x', 'y‬‬ ‫***** !خطأ ***** >==‬ ‫:)‪Traceback (most recent call last‬‬ ‫>‪File "", line 1, in >> tup = ('André',) + tup‬‬

‫16هذا الصيطلح ليس كلومة إنكليزية ع ادية : هو لفظ ح اسوب جديد .‬

‫561‬
‫)‪>>> print(tup‬‬ ‫)'‪('André', 'b', 'c', 'd', 'e‬‬

‫المصفوفات المغلقة )‪(tuples‬‬

‫لحظ أنه يجب عليك دائما على القل فاصلة واحدة لتعريف الصفوفة الغلقة )‪) (tuple‬اللثال الخي فتتوق يستتتخدم مصتتفوفة‬ ‫مغلقة )‪(tule‬يحتوي على عنص واحد: '‪.('André‬‬ ‫يمكنك تحديد طول الصفوفة الغلقة )‪ (tuple‬بمساعدة ‪ ،()len‬التدوير بمساعدة الحلقة ‪ ،for‬استخدم التعليمة ‪ in‬لعرفة ما‬ ‫إذا كتان العنصتت القتدم هتتو جتتزء، إلتخ ...، تمامتتا ملثلمتتا كنتتت تفعتتل متع القائمتتة. عمليتتات الجمتتع والضتتب تعمتتل إذا ؟ لكتن لن‬ ‫الصفوفات الغلقتتة )‪ (tuples‬غيتت قابلتتة للتغييتت )التحريتر(، ل يمكتتن استتخدام التعليمتتة ‪ del‬ول الستلوب ‪()remove‬متع‬ ‫الصفوفات الغلقة )‪: (tuples‬‬
‫)"‪>>> tu1, tu2 = ("a","b"), ("c","d","e‬‬ ‫2‪>>> tu3 = tu1*4 + tu‬‬ ‫3‪>>> tu‬‬ ‫)'‪('a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'c', 'd', 'e‬‬ ‫:3‪>>> for e in tu‬‬ ‫...‬ ‫)":"=‪print(e, end‬‬ ‫...‬ ‫:‪a:b:a:b:a:b:a:b:c:d:e‬‬ ‫]2[3‪>>> del tu‬‬ ‫:)‪Traceback (most recent call last‬‬ ‫>‪File "", line 1, in >> print(dico['mouse‬‬ ‫‪souris‬‬

‫يرجى ملحظة أن ترتيب أي عنص ل يطابق الذي قدمناه سابقا. وهذه ليست لها أي أهمية : وهذا معناه أننا لن نستخرج قيمة‬ ‫أحد عناص القاموس بمساعدة رقم ترتيبه، بدل من ذلك نستخدم الفاتيح :‬ ‫نلحظة أيضا، على عكس القوائم، فإنه ليس من الضوري استدعاء أسلوب معي )ملثتتل ‪ (()append‬لضتتافة عنصتت جديتتد‬ ‫إلى القاموس : فقط قم بصنع زوج جديد من مفتاح-قيمة .‬ ‫العمليات على القواميس‬ ‫آخر، في هذه الرة يحتوي على مخزون من الفاكهتتة اللؤشتتات )أو الفاتيتح( ستيكونون أستماء فواكهتة، والقيتم ستتكون كتتل هتذه‬
‫}731 : '‪>>> invent = {'pommes': 430, 'bananes': 312, 'oranges' : 274, 'poires‬‬ ‫)‪>>> print(invent‬‬ ‫}731 :'‪{'oranges': 274, 'pommes': 430, 'bananes': 312, 'poires‬‬

‫أنت تعرف كيفية إضافة عنص إلى قاموس. لزالة عنص، نستخدم التعليمة الدمجتتة ‪ .del‬اصتتنع علتتى ستتبيل اللثتتال قاموستتا‬ ‫الفواكهة الدرجة في الخزون )القيم ستكون هذه الرة قيم رقمية( .‬

‫فإذا أراد سيد،ك تصفية جميع التفاح ول بيعها، يمكننا إزالة من القاموس :‬
‫]'‪>>> del invent['pommes‬‬ ‫)‪>>> print(invent‬‬ ‫}731 :'‪{'oranges': 274, 'bananes': 312, 'poires‬‬

‫761‬

‫القواميس‬ ‫الدالة الدمجة ‪ ()len‬متكاملة مع القواميس : تقوم بإرجاع عدد العناص:‬

‫))‪>>> print(len(invent‬‬ ‫3‬

‫اختبار االنتماء‬ ‫ملثل متتا يحتدث للسلستل والقتوائم والصتفوفات الغلقتتة )‪ ،(tuples‬التعليمتتة ‪ in‬تعمتتل متع القتتواميس. فهتتي تستتمح لتم إذا كتان‬
‫36‬

‫القاموس يحتوي على مفتاح محدد :‬

‫:‪>>> if "pommes" in invent‬‬ ‫...‬ ‫)"‪print("Nous avons des pommes‬‬ ‫:‪... else‬‬ ‫...‬ ‫)"‪print("Pas de pommes. Sorry‬‬ ‫...‬ ‫‪Pas de pommes. Sorry‬‬

‫القواميس هي كائنات‬ ‫يمكننا أن نطبق على القوائم العديد من الساليب الخاصة :‬ ‫السلوب ‪ ()keys‬يقتوم بإرجتاع تسلستل الفاتيتح الستتخدمة فتتي القتاموس. هتذا التسلستل يمكتن استتخدامه فتي العبتارات أو‬ ‫تحويلها إلى قائمة أو إلى مصفوفات مغلقة إذا لزم المر، عن طريق دالت الدمجة ملثل ‪ ()list‬أو ‪: ()tuple‬‬

‫))(‪>>> print(dico.keys‬‬ ‫)]'‪dict_keys(['computer', 'mouse', 'keyboard‬‬ ‫:)(‪>>> for k in dico.keys‬‬ ‫...‬ ‫)]‪print("clé :", k, " --- valeur :", dico[k‬‬ ‫...‬ ‫‪clé : computer --- valeur : ordinateur‬‬ ‫‪clé : mouse --- valeur : souris‬‬ ‫‪clé : keyboard --- valeur : clavier‬‬ ‫))(‪>>> list(dico.keys‬‬ ‫]'‪['computer', 'mouse', 'keyboard‬‬ ‫))(‪>>> tuple(dico.keys‬‬ ‫)'‪('computer', 'mouse', 'keyboard‬‬

‫و بشكل مماثل، فإن السلوب ‪ ()values‬يقوم بإرجاع سلسلة من القيم الخزنة في القواميس :‬
‫))(‪>>> print(invent.values‬‬ ‫)]731 ,213 ,472[(‪dict_values‬‬

‫أمتتا بالنستتبة للستتلوب ‪،()items‬تت فهتتو يقتتوم باستتتخراج متتن القتتاموس سلستتلة معادلتتة للمصتتفوفات الغلقتتة )‪ .(tuples‬وهتتذا‬ ‫السلوب سيكون مفيدا جدا فيما بعد، عندما نريد تكرار قاموس بمساعدة حلقة :‬
‫)(‪>>> invent.items‬‬ ‫)])472 ,'‪dict_items([('poires', 137), ('bananes', 312), ('oranges‬‬

‫ف الصدارات الس ابقة لبياثون, ك ان من الضروري اسةتدع اء أسلوب معي )السلوب ‪ (()has_key‬لداء هذا الخةتب ار.‬

‫36‬

‫المزيد من هياكل البيانات‬
‫))(‪>>> tuple(invent.items‬‬ ‫))472 ,'‪(('poires', 137), ('bananes', 312), ('oranges‬‬

‫861‬

‫السلوب ‪ ()copy‬يسمح لك بصنع نسخة طبق الصل من قاموس. يجب أن تعرف إذا قدمت متغيا جديدا وربطه بالقاموس‬ ‫سيكون هذا فقط مرجعا للكائن نفسه، وليتتس كائنتتا جديتتدا. ستبق وأن تحتتدثنا علتتى هتتذا المتتر فتتي القتتوائم )انظتتر إلتتى الصتفحة‬
‫‪>>> stock = invent‬‬ ‫‪>>> stock‬‬ ‫}731 :'‪{'oranges': 274, 'bananes': 312, 'poires‬‬

‫‪ .(Error: Reference source not found‬على سبيل اللثال، العبارة بالسفل ل تعرف قاموسا جديدا )عكس الظاهر( :‬

‫فإذا قمنا بتغيي ‪،invent‬ت سيتم تغيي ‪ stock‬أيضا، والعكس بالعكس )هذان السمان يشيان إلتى نفتس كتائن القتاموس‬
‫]'‪>>> del invent['bananes‬‬ ‫‪>>> stock‬‬ ‫}731 :'‪{'oranges': 274, 'poires‬‬

‫في ذاكرة الحاسوب( :‬

‫لصنع نسخة حقيقية )مستقلة( لقاموس موجود مسبقا، يجب عليك استخدام السلوب ‪: ()copy‬‬
‫)(‪>>> magasin = stock.copy‬‬ ‫165 = ]'‪>>> magasin['prunes‬‬ ‫‪>>> magasin‬‬ ‫}731 :'‪{'oranges': 274, 'prunes': 561, 'poires‬‬ ‫‪>>> stock‬‬ ‫}731 :'‪{'oranges': 274, 'poires‬‬ ‫‪>>> invent‬‬ ‫}731 :'‪{'oranges': 274, 'poires‬‬

‫تدوير قاموس‬ ‫يمكنك استخدام حلقة التكرار ‪ for‬لعالجة جميع عناص في قاموس، لكن انتبه :‬ ‫• خلل التكرار، الفاتيح الستخدمة في القاموس هي الت سيتم تعيينها تبعا لتغي العمل، وليس القيم.‬ ‫• التتيب الذي سيتم استخراج العناص به ل يمكن التنبلؤ به )لن القاموس ليس متسلسل( .‬ ‫ملثال:‬
‫}213:"‪>>> invent ={"oranges":274, "poires":137, "bananes‬‬ ‫:‪>>> for clef in invent‬‬ ‫...‬ ‫)‪print(clef‬‬ ‫...‬ ‫‪poires‬‬ ‫‪bananes‬‬ ‫‪oranges‬‬

‫إذا كنت ترغب في أن تقوم بمعالجة على القيم، يكفي أن تقوم باستداد كل واحد من الفاتيح الطابقة :‬
‫:‪>>> for clef in invent‬‬ ‫...‬ ‫)]‪print(clef, invent[clef‬‬

‫961‬
‫...‬ ‫731 ‪poires‬‬ ‫213 ‪bananes‬‬ ‫472 ‪oranges‬‬

‫القواميس‬

‫هذا النهج ليس ملثاليا، سواء من حيث الداء أو حت متتن وجهتتة نظتتر الوضتتوح. فمتتن الستحستتن بتدل متن ذلتتك استتتخدام طريقتتة‬ ‫‪ ()items‬الذي تم وصفه في القسم السابق :‬
‫:)(‪for clef, valeur in invent.items‬‬ ‫)‪print(clef, valeur‬‬ ‫...‬ ‫731 ‪poires‬‬ ‫213 ‪bananes‬‬ ‫472 ‪oranges‬‬

‫في هذا اللثال، السلوب ‪ ()items‬يتم تطبيقه على قاموس ‪ invent‬الذي يقتتوم بإرجتتاع سلستتلة متتن الصتتفوفات الغلقتتة )‬ ‫‪) ( tuples‬الفتاح، القيمة(. يتم تنفيذ هذه الدورة علتتى هتذه القائمتة بمستتاعدة حلقتة التت تقتوم بفحتص كتل عنصتت متن عناصتت‬ ‫الصفوفة الغلقة )‪. (tuples‬‬ ‫عناصر المصفوفة المغلقة )‪. (tuples‬‬ ‫حت الن وصفنا أن مفاتيتتح القتتواميس هتتي متتن نتتوع سلستتلة ) ‪ .(string‬فتتي‬ ‫الحقيقتتة يمكننتتا استتتخدام كمفتتتاح متتن أي نتتوع متتن البيانتتات الغيتت قابلتتة‬ ‫للتغيي : أعداد صتتحيحة، أعتتداد حقيقيتتة، سلستتل نصتتية، وحتتت الصتتفوفات‬ ‫الغلقة )‪.(tuples‬‬ ‫على سبيل اللثال، نريد أن نتعرف على العشجار اللحوظة الت توجد في حقل‬ ‫مستطيل كتبي. لهتذا يمكننتتا استتتخدام قتتاموس، ومفتتاتيحه ستتتكون مصتفوفات‬ ‫مغلقة )‪ (tuples‬الت تشي إلى إحداثيات ‪ x,y‬لكل عشجرة:‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫}{ = ‪arb‬‬ ‫])2,1([‪arb‬‬ ‫])4,3([‪arb‬‬ ‫= ]5,6[‪arb‬‬ ‫= ]1,5[‪arb‬‬ ‫= ]3,7[‪arb‬‬ ‫'‪= 'Peuplier‬‬ ‫'‪= 'Platane‬‬ ‫'‪'Palmier‬‬ ‫'‪'Cycas‬‬ ‫'‪'Sapin‬‬

‫)‪>>> print(arb‬‬ ‫,'‪{(3, 4): 'Platane', (6, 5): 'Palmier', (5, 1): 'Cycas', (1, 2): 'Peuplier‬‬ ‫}'‪(7, 3): 'Sapin‬‬ ‫)])5,6([‪>>> print(arb‬‬ ‫‪palmier‬‬

‫المزيد من هياكل البيانات‬

‫071‬

‫قتتد تلحتتظ أننتتا قللنتتا متتن الكتابتتة بدايتتة متتن الستتطر اللثتتالث, بالستتتفادة متتن أقتتواس الصتتفوفات الغلقتتة )‪ (tuples‬الختياريتتة‬ ‫)استخدمها بحذر !(‬ ‫في هذا النوع من البناء، نأخذ في اعتبارنا أن القاموس يحتوي فقط علتتى بعتتض العناصتت متتن أزواج الحتتداثيات. وعلوة علتتى‬ ‫ذلك، ل يوجد شء. وبالتالي، إن كنا نريد الستعلم فتتي القتتاموس لعرفتتة مكتتان غيتت موجتتود، علتتى ستبيل اللثتتال الحتتداثيات )‬ ‫1,2(، فإننا نحصل على خطأ :‬
‫)]2,1[‪>>> print(arb‬‬ ‫‪Peuplier‬‬ ‫)]1,2[‪>>> print(arb‬‬ ‫)1 ,2( :‪***** Erreur : KeyError‬‬ ‫*****‬

‫لحل هذا الشكلة الصغية، يمكننا استخدام السلوب ‪: ()get‬‬
‫)'‪>>> arb.get((1,2), 'néant‬‬ ‫‪Peuplier‬‬ ‫)'‪>>> arb.get((2,1), 'néant‬‬ ‫‪néant‬‬

‫البامت الول الذي يتم تمريره هو لهذا السلوب هو مفتاح البحث، أما البامت اللثاني فهي القيمة التتت نريتتد الحصتتول عليهتتا إذا‬ ‫كان الفتاح غي موجود في القاموس .‬ ‫القواميس ليست متسلسلة‬ ‫كما رأيتم أعله، ل يتم ترتيب عناص القتتاموس فتتي أي ترتيتتب معيتت. العمليتتات ملثتتل التسلستتل والستتخراج )متتن مجموعتتة متن‬ ‫العناص التصلة( ل يمكن تطبيقها هنا ببساطة. فإذا حاولت في أي حال من الحوال، سيقوم بيلثون بطباعتتة خطتتأ عنتتد تشتتغيل‬ ‫كود :‬
‫)]3:1[‪>>> print(arb‬‬ ‫***** ‪***** Erreur : TypeError: unhashable type‬‬

‫و رأيتم أيضا أنه يكفي لتعيي ملؤش جديد )مفتاح جديد( لضافة مدخلت إلى القاموس. وهذه ل تعمل مع القوائم :‬
‫46‬

‫789 = ]'‪>>> invent['cerises‬‬ ‫)‪>>> print(invent‬‬ ‫}731 :'‪{'oranges': 274, 'cerises': 987, 'poires‬‬ ‫]'‪>>> liste =['jambon', 'salade', 'confiture', 'chocolat‬‬ ‫'‪>>> liste[4] ='salami‬‬ ‫‪***** IndexError: list assignment index out of range‬‬ ‫*****‬

‫46تذكي : الس اليب الت تسومح بإض افة عن اصر إل الق ائومة ت شرحه ا ف صفحة 451.‬

‫171‬

‫القواميس‬

‫هي ليست من التسلسلت، ثبت أن القواميس إذا قيم خاصة تم صنعها يتجميع معطيات والت يتعي على الرء الضافة عليهتتا‬ ‫أو الحذف منها، في أي ترتيب كانت. وهي تحل محل القوائم عندما يتعلق المر بالتعامل متتع مجموعتتات متن العطيتات الرقميتتة،‬ ‫والت هم غي متسلسلي.‬ ‫ملثال :‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫}{ = ‪client‬‬ ‫"‪client[4317] = "Dupond‬‬ ‫"‪client[256] = "Durand‬‬ ‫"‪client[782] = "Schmidt‬‬

‫إلخ.‬

‫تمارين‬
‫01.54 اكتب سكريبت يقوم بصنع نظام قاعدة بيانات صغي يعمل بمساعدة القاموس، هذا النظام يقوم بحفظ أسماء عدد من‬ ‫أصتتدقائك وأعمتتارهم وطتتولهم. الستتكريبت الختتاص بتتك يجتتب عليتته أن يحتتتوي علتتى دالتتتي : الولتتى للتتء القتتاموس،‬ ‫واللثانية للطلع. في دالة اللء، استخدم حلقة لقبول العطيات من الستخدم.‬ ‫في القاموس، اسم الطالب سيكون مفتاح الوصول، والقيم ستكون أنفاق )‪) (tuples‬العمر، الطول(، حيتتث يتتتم التعميتت‬ ‫علتتى العمتتر بالستتنوات )عتتدد صتتحيح(، والطتتول بالمتتتار )عتتدد حقيقتتي (. دالتتة الستشتتارة تشتتمل أيضتتا حلقتتة، حيتتث‬ ‫يستطيع الستخدم إدخال أي استم ليتتم إرجتاع لتته زوجيت )العمتتر، الطتول( القابتل. وستتكون نتيجتتة الستتعلم ستطر‬ ‫منسق جيدا، على سبيل اللثال )السم: جي دوت - العمر: 51 سنة - الطول: 47.1 مت(. لتحقيق ذلك، استخدم تنسيق‬ ‫السلسل النصية الت شحناها في الصفحة 941.‬ ‫01.64 اكتتتب دالتتة تبتتدل مفاتيتتح بقيتتم القتتاموس )تستتمح لتتك علتتى ستتبيل اللثتتال بتحويتتل قتتاموس إنكليتتي\فرنستت بقتتاموس‬ ‫فرنس\إنكليي(. نفتض أن القاموس ل يحتوي على قيم متطابقة عديدة .‬ ‫القواميس هي أداة لنشاء مدرج بياني أنيق .‬ ‫على سبيل اللثال، لنفتض أننا نريد إنشاء رسم بياني يملثل تكرار كل حرف من البجدية في نتتص القتتدم. خوارزميتتة التتت تقتتوم‬ ‫بهذا العمل هي بسيطة للغاية إذا كنت تريد بنائها بالعتماد على قاموس :‬
‫"‪>>> texte ="les saucisses et saucissons secs sont dans le saloir‬‬ ‫}{= ‪>>> lettres‬‬ ‫:‪>>> for c in texte‬‬ ‫...‬ ‫1 + )0 ,‪lettres[c] =lettres.get(c‬‬ ‫...‬ ‫)‪>>> print(lettres‬‬ ‫:'‪{'t': 2, 'u': 2, 'r': 1, 's': 14, 'n': 3, 'o': 3, 'l': 3, 'i': 3, 'd': 1, 'e': 5, 'c‬‬ ‫}4 :'‪3, ' ': 8, 'a‬‬

‫المزيد من هياكل البيانات‬

‫271‬

‫نبدأ من خلل إنشاء قاموس فارغ: ‪ .lettres‬ثم سنستخدم للء هذا القاموس البجدية كمفتاح. القيم الت نريد تخزينهتتا لتتك‬ ‫مفاتيح ستكون تكرار الحرف في النص القابل. لحساب هذا، سوف نقوم بتدوير سلستلة النصتية ‪ .texte‬لكتل حترف، ستوف‬ ‫نطلب من القاموس بمساعدة السلوب ‪،()get‬تت باستخدام الحرف كمفتاح لقراءة التكرار الوجتتود لهتتذا الحتترف. إذا كتتانت القيمتتة‬ ‫غي موجودة سوف يعيد لنا السلوب ‪ ()get‬قيمتتة فارغتتة. فتتي جميتتع الحتتالت، ستنقوم بزيتادة القيمتتة الوجتتود، ونخزنهتتا فتتي‬ ‫القاموس، في الكان الذي يتوافق مع الفتاح )هذا معناه إلى الحرف الذي تتم معالجته(.‬ ‫لتحسي عملنا، نستطيع أن نعرض الرسم البياني في ترتيتب أبجتدي. للقيتام بتذلك، ستوف نفكتر علتتى الفتور باستتخدام أستلوب‬ ‫الفرز ‪،()sort‬ت لكن هذا ل يمكن تطبيقه إل على القوائم. هذا ل يهتم! لقتد رأينتا فتي العلتتى كيتف يمكننتا تحويتل القتاموس إلتى‬ ‫قائمة مصفوفات مغلقة )‪:(tuples‬‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫'([‬ ‫,)3‬ ‫))(‪lettres_triees = list(lettres.items‬‬ ‫)(‪lettres_triees.sort‬‬ ‫)‪print(lettres_triees‬‬ ‫,'‪', 8), ('a', 4), ('c', 3), ('d', 1), ('e', 5), ('i', 3), ('l', 3), ('n', 3), ('o‬‬ ‫])2 ,'‪('r', 1), ('s', 14), ('t', 2), ('u‬‬

‫تمارين‬
‫01.74 لديك تحت تصفك أي ملف نص )ليس كبي جدا(. اكتب سكريبت يحسب تكرار كل حرف من البجدية في هذا النص‬ ‫)لتسهيل الشكلة تجاهل الحروف العلمة( .‬ ‫01.84 قم بتعديل السكريبت بالعلى بحيث ينش جدول تواجد كل كلمة في النص. نصيحة : في أي نص، ل تفصتتل الكلمتتات‬ ‫فقط بالسافات، لكن حت بأدوات التنقيط الختلفة. لتبسيط الشكلة، يمكنك البدء باستتتبدال جميتتع الرمتتوز بمستتافات،‬ ‫تحويل السلسلة الناتجة في قائمة من الكلمات بمساعدة السلوب ‪.()split‬‬ ‫01.94 لديك تحت تصفك أي ملف نص )ليس كبيا جدا(. اكتب سكريبت يحلل هذا النص، ويقوم تخزين في قتتاموس الكتتان‬ ‫الدقيق لكل كلمة )قم بعد عد لبأحرف في البدايتتة(. إذا كتتانت كلمتتة موجتتودة فتتي أمتتاكن مختلفتتة، جميتتع المتتاكن يجتتب‬ ‫تخزينها : كل قيمة في قاموس يجب أن تكون قائمة الماكن .‬ ‫التحكم في تدفق التنفيذ بالستخدام قاموس‬ ‫كلثيا ما يحدث أننا نقوم بتنفيتذ البامتج فتتي اتجاهتتات مختلفتتة، اعتمتتادا علتتى قيمتتة التغيتت. يمكنتتك بتالطبع التعامتتل متع هتذه‬ ‫الشكلة باستخدام سلسلة من العبارات ‪ ،if - elif - else‬لكنها يمكن أن تصبح مرهقة جدا وغي أنيقة إذا كنت تتعامل مع‬ ‫عدد كبي من الحتمالت، على سبيل اللثال:‬
‫)" : ‪materiau = input("Choisissez le matériau‬‬ ‫:'‪if materiau == 'fer‬‬ ‫)(‪fonctionA‬‬

‫371‬
‫:'‪elif materiau == 'bois‬‬ ‫)(‪fonctionC‬‬ ‫:'‪elif materiau == 'cuivre‬‬ ‫)(‪fonctionB‬‬ ‫:'‪elif materiau == 'pierre‬‬ ‫)(‪fonctionD‬‬ ‫‪elif‬‬ ‫... ‪... etc‬‬

‫القواميس‬

‫لغات البمجة توفر لك عبارات محتددة للتعامتتل متع هتذه الشتتكلة، ملثتل العبتارات ‪ switch‬أو ‪ case‬فتتي الستت أو فتتي باستكال.‬ ‫بيلثتتون ل تتتوفر لتتك أي واحتتد، لكتتن يمكنتتك الحصتتول عليهتتا بمستتاعدة قائمتتة )لقتتد أعطينتتا شتتح مفصتتل فتتي الصتتفحة :‪Error‬‬ ‫‪ ،(Reference source not found‬أو أفضل من ذلك عن طريق قاموس. على سبيل اللثال :‬
‫)" : ‪materiau = input("Choisissez le matériau‬‬ ‫,‪dico = {'fer':fonctionA‬‬ ‫,‪'bois':fonctionC‬‬ ‫,‪'cuivre':fonctionB‬‬ ‫,‪'pierre':fonctionD‬‬ ‫}... ‪... etc‬‬ ‫)(]‪dico[materiau‬‬

‫التعليمتان في العلى يمكن جمعها في تعليمة واحد فقط، لكننا جعلناها منفصلة لتفصيل اللية :‬ ‫•العبارة الولى تعرف قاموس ‪ dico‬حيث أن الفاتيح هي الحتمالت الختلفة للمتغي ‪ ،materiau‬والقيم هي أسماء‬ ‫الدالت الت يجب استدعاؤها. لحظ أنها سوى أسماء الدالت، ومن الهم أن ل تضع القوسي فتتي هتتذه الحالتتة )و إل ستتوف‬ ‫يقوم بيلثون بتنفيذ جميع الدالت في وقت صنع القاموس( .‬ ‫• العبارة اللثانية تقوم باستدعاء الدالة القابلة للختيتار بمستاعدة الدالتة ‪ .materiau‬استم الدالتتة ستيتم استتخراجه متن‬ ‫القاموس بمساعدة الفتاح، ثم يتم ربط بزوج من القواس. بيلثون ستعرف إذا أنهتتا استتتدعاء دالتتة بشتتكل تقليتتدي، ثتتم يتتتم‬ ‫تشغيله .‬ ‫يمكنك تعزيز التقنية في العلى باستبدال هذه التعليمة مع ملثيلها في السفل، الذي يقوم باستدعاء الستتلوب ‪ ()get‬حالتتة إذا‬ ‫كان الفتاح الطلوب غي موجود في القاموس)و بهذه الطريقة يمكنك الحصول على ما يعادل تعليمة ‪ else‬في نهاية السلسلة‬ ‫الطويلة من ‪: (elif‬‬
‫)()‪dico.get(materiau, fonctAutre‬‬

‫عندما تكون قيمة التغي ‪ materiau‬ل تتطابق مع أي مفتاح في القاموس، يتم استدعاء الدالة )( ‪. ()fonctAutre‬‬ ‫01.05 أكمل التمرين 64.01 )نظام قاعدة بيانتتات صتتغي( بإضتتافة دالتتي : واحتدة لحفتظ القتاموس الناتتج فتتي ملتتف نصت،‬ ‫واللثانية لعادة بناء هذا القاموس من خلل هذا اللف النص.‬

‫تمارين‬

‫المزيد من هياكل البيانات‬

‫471‬

‫كل سطر من اللف النص يتوافق مع عنص من القاموس. سيتم تنسيق ذلك بطريقة مفصول جيدا :‬ ‫الفتاح والقيمة )هذا معناه اسم الشخص جزء، ومجموعة : العمر + الطول، في جزء آخر(.‬ ‫في مجموعة "العمر + الطول"، هذان الثنان معطيات رقمية. لتذا يجتتب عليتتك استتتخدام رمتز للفصتتل، علتتى ستبيل اللثتال "@"‬ ‫للفصل بي الفتاح والقيمة، و"#" للفصل بي معطيات هذه القيمة :‬
‫76.1#81@‪Juliette‬‬ ‫87.1#71@‪Jean-Pierre‬‬ ‫17.1#91@‪Delphine‬‬ ‫.‪Anne-Marie@17#1.63 etc‬‬

‫01.15 ح ّسن سكريبت التمرين السابق، باستخدام قاموس بتوجيه تدفق تنفيذ البنامج في مستوى القائمة الرئيسية. ستتوف‬ ‫يعرض البنامج على سبيل اللثال :‬
‫: ‪Choisissez‬‬ ‫‪(R)écupérer un dictionnaire préexistant sauvegardé dans un fichier‬‬ ‫‪(A)jouter des données au dictionnaire courant‬‬ ‫‪(C)onsulter le dictionnaire courant‬‬ ‫‪(S)auvegarder le dictionnaire courant dans un fichier‬‬ ‫: ‪(T)erminer‬‬

‫اعتمادا على اختيار الستخدم، يتم إ ذا استدعاء الدالة القابلة عن طريق اختيار في قاموس الدالت .‬ ‫ً‬

‫11‬
‫11الأصناف، الكائنات، الصفات‬
‫في الفصول السابقة، لقد التقيت بالفعل عدة مرات مع مفهوم الكائن. وأنت تعتترف أن الكتتائن هتتو وحتتدة تتتم إنشتتاؤها متتن صتتنف‬ ‫ملثيل )و هذا معناه هتتو نتوع متن "فئتتة" أو "نتوع" كتائن(. علتتى ستبيل اللثتال، يمكننتا أن نجتد فتتي مكتبتة ‪ ،Tkinter‬صتنف )(‬ ‫‪ Button‬من خللها يمكننا صنع أي عدد من الزرار في النافذة.‬ ‫سوف ندرس الن كيف يمكنك تعريف أصناف جديدة من الكائنات. هذا الوضوع صعب نسبيا، ولكننا ستتوف نقتتتب تتدريجيا،‬ ‫بداية من تعريف أصناف كائنات بسيطة جدا، الت سوف نصقلها.‬ ‫ملثل كائنات الحياة اليومية )الحقيقية(، الكائنتتات الحاستتوبية يمكتتن أن تكتتون بستتيطة جتتدا أو معقتتدة جتدا. قتتد تكتتون مكونتتة متتن‬ ‫أجزاء مختلفة، والت هي في حد ذاتها كائنات، وهذه جعلت بدورها كائنات أخرى أكث بساطة، إلخ ...‬

‫فائدة الصناف‬ ‫الصناف هي الدوات الرئيسية للبمجة الشيئية ) ‪ Object Oriented Programming‬أو ‪ .(OOP‬هتتذا النتتوع متتن البمجتتة‬ ‫يسمح لك بهيكلة البامج العقدة عن طريق تنظيمها على أنها مجموعات من كائنات تتفاعل مع بعضها ومع العالم الخارجي.‬ ‫الفائدة الولى من هذا النهج من البمجة يكمن في بناء كائنات مختلفة تستخدم بشكل مستقل عن بعضتها البعتض )علتى ستبيل‬ ‫اللثال من قبل مبمجي مختلفي( بدون خطر تداخلها. هذه النتيجة تحقق من خلل مفهتتوم التغليتتف : الوظيفتتة الداخليتتة للكتتائن‬ ‫والتغيات الت تستخدم للقيام بعملها، نوعا ما بشكل مغلق في الكائن. ل يمكن للكائنتتات الختترى أو العتتالم الختتارجي الوصتتول‬ ‫إليها إل من خلل إجراءات محددة جيدا : واجهة الكائن.‬ ‫إن استخدام الصناف في برامجك يسمح لك - من بي الفوائد الخرى - بتجنب اسنخدام الحتتد القصتت متتن التغيتتات العاليتتة.‬ ‫يجب أن تعرف أن استخدام التغيات العالية أمر خطي جدا، حت أنه أكث أهميتتة متتن البامتتج كتتبية الحجتتم، لنتته متتن المكتتن‬

‫الصناف، الكائنات، الصفات‬

‫671‬

‫دائما تغيي هذه التغيات، أو حت إعادة تعريفها، في أي جزء من البنامج )هذا الخطر يزداد سوءا إذا كتان هنالتتك العديتد متن‬ ‫ً‬ ‫البمجي يعملون على نفس البنامج(.‬ ‫الفائدة اللثانية الناتجة عن استخدام الصناف هي إمكانية بناء كائنات جديدة من الكائنات الوجودة، وبالتتتالي إعتتادة استتتخدام‬ ‫الساحات البمجية الكبية الكتوبة بالفعل )بدون لسها !(، لعشتقاق مية جديدة. هذا ستتيكون ممكنتتا بفضتتل مفتتاهيم العشتتتقاق‬ ‫وتعدد العشكال :‬ ‫• العشتقاق هي آلية تسمح لك ببناء صنف جديد "ابن أو طفل" من صتتنف "أم أو الصتتل". الطفتتل ستتيث جميتتع خصتتائص‬ ‫وجميع وظائف الم، ويمكنك إذا إضافة ما تريد عليها.‬ ‫ً‬ ‫• يمكن لتعدد العشكال تعيي سلوكيات مختلفة للكائنات الشتقة من بعضها البعض، أو من نفس الكتتائن أو متن وفتتق لستتياق‬ ‫معي .‬ ‫قبتتل الضتت قتتدما، لحتتظ هنتتا أن البمجتتة الشتتيئية هتتي شتتء اختيتتاري فتتي بيلثتتون. يمكنتتك تطتتوير العديتتد متتن البامتتج بتتدون‬ ‫استخدامها، مع أدوات أكث بساطة من دالت. اعلم أنك إذا بذلت الزيد من الجهد في تعلتم البمجتتة بمستتاعدة الصتتناف، ستوف‬ ‫تتقن مستوى أعلى، مما يسمح لتك التعامتتل متع مشتتاكل أكتث تعقيتدا. وبعبتارة أخترى، ستوف تصتبح مبمجتتا متخصصتا أكتث.‬ ‫ً‬ ‫• في بداية دراستك، بدأت باستخدام تعليمات بسيطة. لقد كنت إلى حد ما "مبمج باليد" )و هذا معناه تقريبا دون أدوات(.‬ ‫• ثم تعرفت على الدالت الت تم تعريفها مسبقا )انظر للفصتتل الستتادس(، وتعلمتتت أن هنتتا،ك مجموعتتات واستتعة متتن الدوات‬ ‫التخصصة الت قدمت من قبل مبمجي أخرين.‬ ‫• تعلمت كتابة دالت خاصة بك )انظر للفصل السابع ومتتا بعتتده(، فأصتتبحت قتتادرأ علتتى صتتنع أدوات جديتتدة خاصتتة بتتك،‬ ‫ً‬ ‫• إذا كنت ستبدأ الن برمجة الصناف، سوف تتعلتتم كيفيتتة بنتتاء آلت لنتتتاج الدوات. وهتتذا متتن الواضتتح أكتتث تعقيتتدا متتن‬ ‫صنع الدوات مباشة، ولكن هذه تفتح لك أبواب أوسع من ذلك بكلثي !‬ ‫فهم هذه الصناف تساعد،ك على السيطرة على مجال واجهات الستخدم الرسومية )‪ (tkinter، wxPython‬وإعداد،ك للتصتتدي‬ ‫بشكل فعال على لغات حديلثة أخرى ملثل س بلس بلس أو الجافا .‬ ‫وهذه يمنحك تحكمأ كبيأ إضافيا.‬ ‫ً‬ ‫ً‬ ‫لقناعك بذلك، تذكر التقدم الذي قمت به خلل هذه الدورة :‬

‫771‬

‫تعريف صنف أولي‬ ‫تعريف صنف ألولي‬

‫لنشاء صنف كائن بيلثون، نستخدم العبارة ‪ .class‬سوف نتعلم استخدام هذه العبارة، بدءا من تعريتف نتوع كتائن أساست،‬ ‫والذي سيكون ببساطة مجرد نوع من البيانات الجديدة. ولقد استخدمنا أنواعا مختلفة متتن البيانتتات حتتت الن، ولكتتن كتتانت كتتل‬ ‫مرة من نوع مدمج في اللغة نفسها. سوف نقوم الن يصنع نوع مركب جديد : النوع ‪.Point‬‬ ‫هذا النوع يتوافق مع مفهوم هندسة مستوى النقطة. في الستوى، يتم تميي النقطة من رقمي )الحتداثيات ‪ x‬و ‪ .(y‬فتي التتدوين‬ ‫الرياض، يتم إذا تعريف النقطة من خلل إحداثيات ‪ x‬و ‪ y‬في زوج من القواس. على ستتبيل اللثتتال النقطتتة )52, 71(. وهنالتتك‬ ‫طريقة طبيعية لتملثيل النقطة في بيلثون ليتم استخدامها لحداثيات قيمتي من نوع حقيقتتي. لكتتن نحتتن نريتتد الجمتتع بيتت هتتاتي‬ ‫القيمتي في كيان واحد، أو في كائن واحد. لتحقيق ذلك سوف نقوم بتعريف الصنف ‪: ()Point‬‬
‫:)‪>>> class Point(object‬‬ ‫...‬ ‫"‪"Définition d'un point géométrique‬‬

‫تعريتتف الصتتناف يمكتتن أن يكتتون فتتي أي مكتتان فتتي البنامتتج، لكتتن يتتتم وضتتعها بشتتكل عتتام فتتي البدايتتة )أو فتتي وحتتدة يتتتم‬ ‫استدعاؤها(. اللثال أعله هو على الرجح البسط الذي يمكن تخيله. سطر واحد يكفي لتعريف نوع كائن جديد ‪.()Point‬‬ ‫نلحظ ما يلي :‬ ‫كتلة التعليمات الت تليها. هذا الجمع يجب أن يحتوي على القل على سطر واحد. في ملثالنا البسط للغاية، هذا الستتطر ل‬ ‫•العبارة ‪ class‬هو ملثال آخر على العبارة الجمعة. ل تن س النقطتي في نهاية السطر فهي إلزاميتتة، ومستتافة البادئتتة فتتي‬ ‫َ‬

‫يحتوى سوى على تعليق بسيط. كما رأينا سابقا في الدالت )انظتتر الصتتفحة 47(، يمكنتتك إضتتافة سلستتلة نصتتية مباشتتة‬ ‫بعد العبارة ‪،class‬تت من أجل وضع تعليق لدراجها تلقائيا إلى الوثائق الداخلية لبيلثون. تعود دائما على وضتتع سلستتلة‬ ‫لوصف الصنف هنا .‬ ‫• تم وضع القواس ليحتوي على مرجع صنف موجود. هذا المر مطلوب للسماح للية الياث. كل الصتتناف الجديتتدة التتت‬ ‫نصنعهايمكن أن ترث من الصنف الصل مجموعة من الميات، الت تضاف إليها تلقائيا. عندما نريد إنشاء صتتنف أساستت‬ ‫)و هذا معناه أنه غي معتمد على أي صنف آخر، كما في ملثالنا الصنف ‪ – ()Point‬جب أن يكون مرجع العشارة حستتب‬ ‫التفاقية هو السم الخاص ‪ ،object‬مما يعن أنه جد جميع الصناف الخرى .‬
‫56‬

‫• التفاقية النتشة بكثة هي أن يتم إعطاء أسماء للصناف تبدأ بحرف كبي. في بقية النص، سوف نحتم هذه التفاقية،‬ ‫والخر الذي يطلب في السد، ويرتبط مه كل اسم صنف زوج من القواس، كما نفعل بالسماء الدالت .‬

‫56 عند تعريف صنف أس اسي، يكنك حذف القواس والرجع إل الصنف ك ائن السلف )الذي قبله(: هذه الؤشرات أصبحت‬ ‫اخةتي ارية ف الب اياثون 3. سنواصل إسةتخدامه ا ف هذا النص، لكن من اليد أن نقوم بةتوضيح أهية مفهوم الوراثة .‬

‫الصناف، الكائنات، الصفات‬

‫871‬

‫نحن نريد إذا تعريف الصنف ‪ .()Point‬يمكننا الن صنع كائنات من هذا الصنف، والت نسميها أيضا ملثيل للصنف. وتستتمى‬ ‫ً‬ ‫هذه العملية بالتملثيل. على سبيل االلثال ننش كائنا جديدا 9‪: p‬‬
‫66‬

‫)(‪>>> p9 = Point‬‬

‫بعد هذه العبارة التغي 9‪ p‬يحتوي على مرجع للكائن الجديد ‪ .()Point‬يمككنتتا أن نقتول أن 9‪ p‬هتتو ملثيتل جديتد للصتنف‬ ‫‪.()Point‬‬ ‫تنبيه‬ ‫مثل الدالت، يجب على الصناف التي يتـم إسـتدعاؤها فــي التعليمـة أن تكـون مصـحوبة بقوســين )حـتى لـو لـم‬ ‫يتم تمرير برامتر(. سوف نرى في الواقع أن الصناف يمكن استدعاؤها مع برامترات .‬ ‫دعونا نرى ما إذا كنا نستطيع أن نفعل عشيئا مع الكائن الجديد 9‪: p‬‬
‫)9‪>>> print(p‬‬ ‫>‪>> print(p9.__doc‬‬ ‫‪Définition d'un point géométrique‬‬

‫كما شحنا الدالت )انظر للصفحة 47(، يتم ربط سلسل توثيق كائنات بيلثون الختلفة مع سمة العرفتتة __‪ .__doc‬وإذا فمتتن‬ ‫المكن دائما العلثور على الوثائق الرتبطة مع أي كائن بيلثون، نت خلل استدعاء هذه السمة.‬ ‫سمات )ألو متغيرات ( المثيل‬ ‫الكتتائن التتذي صتتنعناه هتتو مجتترد صتتد فة فارغتتة. سنضتتيف الن عناصتته، بتعييتت بستتيط، باستتتخدام نظتتام تأهيتتل الستتماء‬ ‫َ ََ‬
‫76‬

‫بالنقا ط :‬

‫‪new‬‬

‫66 ف بياثون, يكنن ا إنرش اء ماثيل ك ائن بس اعدة تعليومة بسييطة خ اصة. ف اللغ ات الخرى تةتيطلب اسةتخدام تعليومة خ اصة, ماثل‬ ‫ليبي أن يقوم بإنرش اء ك ائن جديد من العفن. على سبيل الاث ال: ‪.()p9 = new Point‬‬ ‫76‬ ‫هذا نظ ام الةترقيم مرش ابه للذي اسةتخدمن اه لوصف مةتغي لوحدة, ماثل ‪ math.pi‬أو ‪ .string.ascii_lowercase‬و سوف نعود‬ ‫ف وقت لحق, ولكن نعرف الن أن الوحدات يكنه ا أن تةتوي على دالت, ولكن حت أصن اف ومةتغيات. ح اول على سبيل الاث ال :‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫‪import string‬‬ ‫‪string.capwords‬‬ ‫‪string.ascii_uppercase‬‬ ‫‪string.punctuation‬‬ ‫‪string.hexdigits‬‬

‫971‬
‫0.3 = ‪>>> p9.x‬‬ ‫0.4 = ‪>>> p9.y‬‬

‫سمات )أو متغيرات( المثيل‬

‫التغيان ‪ x‬و ‪ y‬الت قمنا بتعريفهم من خلل الربط الباش مع 9‪ ، p‬هم الن سمات للكائن‬ ‫9‪ .p‬يمكن أيضا استدعاء متغيات اللثيل. في الواقع يتم إدراجها، أو تغليفها في هتتذا اللثيتتل‬ ‫)أو الكائن(. الرسم البياني علتتى اليميتت يظهتتر نتيجتتة هتذه التعيينتتات : التغيتت 9‪ p‬يحتتتوي‬ ‫على مرجع يشي إلى موقع الكتائن الجديتد فتي التذاكرة، والتذي يحتتتوي علتى ستمتي ‪ x‬و ‪.y‬‬ ‫وهذه تتضمن مراجع للقيم 0.3 و 0.4 الخزنة في أماكن أخرى.‬ ‫يمكننا استخدام سمات كائن في أي تعبي، تماما ملثل أي متغي عادي :‬
‫)‪>>> print(p9.x‬‬ ‫0.3‬ ‫)2**‪>>> print(p9.x**2 + p9.y‬‬ ‫0.52‬

‫بسبب التغليف في الكائن، السمات هي متغيات مستقلة عن التغيات الخرى التت قتد تحمتل نفتس الستم. علتتى ستبيل اللثتال،‬ ‫التعليمة ‪ x = p9.x‬معناه : "استخرج من مرجع الكائن في 9‪ p‬قيمة السمة ‪ ،x‬وقم بربط هذه القيمة بالتغي ‪ ."x‬ول يوجد‬ ‫تعارض بي التغي الستقل ‪ .x‬وبي السمة ‪ x‬للكائن 9‪ .p‬الكائن 9‪ p‬يحتوي على مساحة السماء خاصة به، مستتتقلة عتتن‬ ‫مساحة أسماء الرئيسية الت تجد التغي ‪.x‬‬ ‫هام / المثلة الموجودة هنا مؤقتة ،‬ ‫لقد رأينا أنه من السهل جدا إضافة سمة إلى كـائن باسـتخدام تعليمـة بسـيطة مثـل 0.3 = ‪ p9.x‬وهـذا يمكـن‬ ‫، فنحن إذا لن نستخدم هذا النهج سوى للتوضيح، وفقط من أجل تبسيط الشرح لدينا لســمات المثيــل. وســتم‬ ‫تحمله في بيثون )و هذه نتيجة لطبيعة الحيوية لبيثون(، ولكن ل ينصح بذلك حقا، كما سوف تفهــم لحقــا‬ ‫تطوير الطريقة الصحيحة في الفصل القادم .‬

‫تمرير كائن كء برامتر عند استدعاء دالة‬ ‫الدالت يمكنها استخدام الكائنات كبامتات، ويمكن أيضا استخدام الكائن كقيمة للعودة. على سبيل اللثال، يمكنك تعريتتف دالتتة‬ ‫ملثل هذه :‬
‫:)‪>>> def affiche_point(p‬‬ ‫...‬ ‫)‪print("coord. horizontale =", p.x, "coord. verticale =", p.y‬‬

‫البامت ‪ p‬الذي يستخدم من قبل هذه الدالة يجب أن يكون كتائن متن نتوع ‪،()Point‬ت التذي يستتتخدم متغيتات اللثيتل ‪ p.x‬و‬ ‫‪ .p.y‬عندما تستدعى هذه الدالة، يجب عليك إذا توفي كائن من نوع ‪ ()Point‬كبامت. جرب مع الكائن 9‪: p‬‬

‫الصناف، الكائنات، الصفات‬
‫)9‪>>> affiche_point(p‬‬ ‫0.4 = ‪coord. horizontale = 3.0 coord. Verticale‬‬

‫081‬

‫تمرين‬
‫11.1 اكتب دالة ‪ ()distance‬تسمح لك بحساب السافة بي نقطتي. )يجب أن تتذكر نظرية فيلثاغورس !(‬ ‫هذه الدالة تنتظر كائني من نوع ‪ ()Point‬كبامت .‬ ‫التشابه لوالتفرد‬ ‫في اللغة الت نتحدث بها، نفس الكلمة يمكن أن يكون لها معان مختلفة اعتمادا على السياق الذي تستخدم فيه. والنتيجتتة يمكتتن‬ ‫أن نفهم بعض عبارات الت تستخدم فيها هذه الكلمات بمعان مختلفة )مصطلحات غامضة(.‬ ‫على سبيل اللثال كلمة "نفس - ‪ " même‬لديها معان كلثية في الجمل : "عشارلز وأنتا لتدينا نفتس الستيارة" و"عشتارلز وأنتا لتدينا‬ ‫نفس الم". في الجملة الول، ما أعنيه أنن وعشارلز لدينا نفس نموذج السيارة لكنهما سيارتي مختلفتي. وفتتي الجملتتة اللثانيتتة،‬ ‫ما أعنيه أنن وعشارلز لدينا نفس الم )نفس الشخص(.‬ ‫عندما تتعامل متع كائنتات البامتج، يمكتن أن تجتد نفتس الغمتتوض. علتى ستبيل اللثتال، فتتإذا تحتدثنا عتن الستاوات بيت كتائني‬ ‫‪،()Point‬تت هذا معناه هذان الكائنات يحتويان على نفس العطيات )ستتماتهم(، أو يعنتت هتتذا أننتتا نتحتتدث عتتن مرجعيتت لنفتتس‬ ‫الكائن ؟ على سبيل اللثال، التعليمات التالية :‬
‫)(‪>>> p1 = Point‬‬ ‫3 = ‪>>> p1.x‬‬ ‫4 = ‪>>> p1.y‬‬ ‫)(‪>>> p2 = Point‬‬ ‫3 = ‪>>> p2.x‬‬ ‫4 = ‪>>> p2.y‬‬ ‫)2‪>>> print(p1 == p‬‬ ‫‪False‬‬

‫هذه التعليمات تقوم بإنشاء كائني 1‪ p‬و 2‪ p‬يبقون مستقلي، حت لتو كتتانوا ينتمتتون إلتى نفتتس الصتتنف وكتانوا لتديهم نفتس‬ ‫الحتويات. التعليمة الخية تجتترب مستتاواة هتتذين الكتتائني )علمتتة مستتاوات مزدوجتتة(، والنتيجتتة ‪) False‬ستالبة( : إذا ل‬ ‫يتساوون.‬ ‫يمكننا تأكيد هذا بطريقة أخرى :‬
‫)1‪>>> print(p‬‬ ‫>‪>> print(p‬‬ ‫>‪>> p2 = p‬‬ ‫)2‪>>> print(p1 == p‬‬ ‫‪True‬‬

‫بناء على التعليمة 1‪ ، p2 = p‬قمنا بتعيي محتوى 1‪ p‬إلى 2‪ .p‬وهذا معناه متغيين يشيان إلى مرجع الكائن نفسه 1‪ p‬و‬ ‫2‪ p‬هي أسماء مستعارة لبعضها البعض.‬
‫86‬

‫اختبار الساواة هذه الرة أرجع لنا القيمة ‪) ،True‬صحيح(، وهذا معناه أن اختبار القوسي صحيح: 1‪ p‬و 2‪ p‬تم تعيينهم‬ ‫إلى كائن واحد، إذا لم تقتنع حاول:‬
‫7 = ‪>>> p1.x‬‬ ‫)‪>>> print(p2.x‬‬ ‫7‬

‫عندما نغي سمة ‪ x‬لت 1‪ ،p‬نلحظ أن سمة ‪ x‬لت 2‪ p‬تتغي أيضا..‬
‫)1‪>>> print(p‬‬ ‫>‪>> print(p‬‬ ‫>‪>> class Rectangle(object‬‬ ‫"‪"définition d'une classe de rectangles‬‬

‫و سوف تخدمنا الن لنشاء ملثيل :‬
‫86برشأن ظ اهرة الس اء السةتع ارة, انظر أيض ا إل صفحة ‪.Error: Reference source not found‬‬

‫الصناف، الكائنات، الصفات‬
‫)(‪>>> boite = Rectangle‬‬ ‫0.05 = ‪>>> boite.largeur‬‬ ‫0.53 = ‪>>> boite.hauteur‬‬

‫281‬

‫لقتتد صتتنعنا الكتتائن الجديتتد ‪ ()Rectangle‬و أعطينتتاه ستتمتي. لتعريتتف الزاويتتة أعلتتى اليستتار، ستتوف نستتتخدم ملثيتتل جديتتد‬ ‫للصنف ‪ ()Point‬الذي عرفناه سابقا. وبالتالي فإننا أنشأنا كائنا جديدا، داخل كائن آخر!‬
‫)(‪>>> boite.coin = Point‬‬ ‫0.21 = ‪>>> boite.coin.x‬‬ ‫0.72 = ‪>>> boite.coin.y‬‬

‫في أول هذه التعليمات اللثلث، قمنا بصنع سمة جديدة ‪ coin‬للكائن ‪ .boite‬ثم، للوصول لهذا الكائن والذي هو في حد ذاته‬ ‫موجود في كائن آخر، استخدمنا تصنيف السماء الهرمي )بمساعدة النقا ط( والذي تحدثنا عنه عدة مرات سابقا.‬ ‫التعبي ‪ boite.coin.y‬يعن "اذهب إلى مرجع الكائن في التغي ‪ .boite‬وفي هذا الكائن، ثم جد السمة ‪ ،coin‬ثم اذهب‬ ‫إلى مرجع كائن في هذه السمة. فإذا وجد الكائن، قم بتحديد سمته ‪."y‬‬ ‫قد تفهم أفضل إذا كان كل هذا في رسم تخطيطي، ملثل هذا :‬

‫السم ‪ boite‬يوجد في مساحة الماكن الرئيستتة. وهتتو يشتتي إلتتى مستتاحة أختترى للستتماء محجتتوز للكتتائن القابتتل، فتتي هتتذه‬ ‫الستتاحة يتتتم حفتتظ أستتماء ‪ largeur، hauteur‬و ‪ .coin‬وهتتذه تشتتي إلتتى مستتاحات أختترى للستتماء )ملثتتل الستتم‬ ‫» ‪ ،(« coin‬أو إلى قيم تم تعريفها جيدا، والت يتم تخزينها في أماكن أخرى.‬ ‫بيلثون يقوم بحجز مساحات لسماء مختلفة لكل وحدة، كل صنف، كل ملثيل وكل كتتائن. يمكنتتك الستتتفادة متن كتتل هتتذه المتتاكن‬ ‫الجزأة بشكل جيد لتحقيق برامج قوية، وهذا يعن برامج ل يمكن أن تتداخل بسهولة .‬

‫381‬

‫الكائنات مثل القيم رجوع الدالة‬ ‫الكائنات مثل القيمء رجوع الدالة‬

‫لقد رأينا أعله أن الدالت يمكنها استخدام الكائنات كبامتات. ويمكنها أن تمترر ملثيتل كقيمتة رجتوع. علتى ستبيل اللثتال، الدالتة‬ ‫‪ ()trouveCentre‬فتتي الستتفل يمكتتن استتتدعاؤها متتع برامتتت متتن نتتوع ‪ ()Rectangle‬وهتتي ترستتل كائنتتا متتن نتتوع‬ ‫‪ ،()Point‬والت تحتوي على إحداثيات وسط الستطيل .‬
‫:)‪>>> def trouveCentre(box‬‬ ‫...‬ ‫)(‪p = Point‬‬ ‫...‬ ‫0.2/‪p.x = box.coin.x + box.largeur‬‬ ‫...‬ ‫0.2/‪p.y = box.coin.y + box.hauteur‬‬ ‫...‬ ‫‪return p‬‬

‫على سبيل اللثال، يمكنك استدعاء هذه الدالة، باستخدام برامت الكائن ‪ boite‬الذي تم تعريفه بالعلى :‬
‫)‪>>> centre = trouveCentre(boite‬‬ ‫)‪>>> print(centre.x, centre.y‬‬ ‫5.44 0.73‬

‫تعديل الكائنات‬ ‫يمكننا تعديل خصائص كائن عن طريق تعيي قيم جديدة لسماته. على سبيل اللثال، يمكننا تعديل حجم الستطيل )دون تغييتت‬ ‫موقعه(، عن طريق إعادة تعيي سماتيه ‪ hauteur‬و ‪: largeur‬‬
‫02 + ‪>>> boite.hauteur = boite.hauteur‬‬ ‫5 – ‪>>> boite.largeur = boite.largeur‬‬

‫يمكننا فعل هذا في بيلثون، لنه في هذه اللغة خصائص الكائن دائما عامة )على القل حت الصدار الحالي : 1.3(. في اللغات‬ ‫الخر يوجد فرق واضح بي السمات العامة )يمكن الوصول إليها من خارج الكائن( والسمات الخاصة )الذي يمكن الوصول إليها‬ ‫فقط عن طريق الخوارزمية الدرجة في الكائن نفسه(.‬ ‫و لكن كما ذكرنا في العلى )حول تعريف سمات تعيي بسيطة من خارج الكائن(، طريقة تعديل سمات ملثيتتل ليتتس موصتت بتته،‬ ‫لنه ينقص أحد الهداف الساسية للبمجة الشيئية، والذي يهدف إلى إنشاء فصل صتتارم بيتت وظتتائف الكتتائن )حتتت التتت تتتم‬ ‫تعريفها في الخارج( وكيف يتم تنفيذها في الواقع هذه الوظيفة في الكائن )و العالم الخارج ل يعرف(.‬ ‫عمليا، هذا يعن أننا يجب أن نتعلم كيفية عمل تشغيل الكائنات باستخدام أدوات مناسبة، والت نسميها الساليب.‬ ‫و الن، بعد أن نفهم هذه العملية، يمكننا تحديد قاعدة بعدم تغيي سمات الكائن عن طريق العتالم الختتارجي مباشتتة كمتا فعلنتتا‬ ‫الن. وبدل من ذلك نحن نريد استخدام هذا السلوب لعداده خصيصا لهذا الغرض، كما سوف نشحه في الفصتتل القتتادم. جمتتع‬ ‫هذه الساليب يكون لنا ما يسمى بواجهة الكائن .‬

‫21‬
‫21الأصناف والأساليب والميراث‬
‫الصناف التت عرفناهتتا فتتي الفصتتل الستابق يمكتن اعتبارهتتا كمستتاحات لستتماء معينتتة، وفيهتا نحتتن لتن نضتتع حتت الن ستوى‬ ‫التغيات )سمات اللثيل(. ويجب الن إعطاء وظيفة لهذه الصناف .‬ ‫الفكرة الساسية للبمجة الشيئية هي في الواقع جمع الكائنات في نفس الجموعة معا، في كل متترة عتتدد متتن البيانتتات )ستتمات‬ ‫اللثيل(، والخوارزميات تقوم بمختلف العالجات على هذه البيانات )و هي الساليب، أي دالت معينة مغلقة في كائن( .‬

‫الكائن = ] سمات + أساليب [‬
‫و بهذه الطريقة يتم جمع خصائص الكائن والدالت في نفس "الكبسولة" الت تعمل عليها، يتوافتتق متع مصتممي البامتج رغبتة‬ ‫في بناء كيانات حاسوبية ذات سلو،ك مشابه للكائنات في العالم الحقيقي الذي يحيط بنا.‬ ‫على سبيل اللثال الودجة "زر" في تطبيق رسومي. فإنه يبدو من العقول أن تتمن أن الكائن الحاسوبي الذي ندعو ستلوكه التذي‬ ‫يشبه أي زر جهاز في العالم الحقيقي. ونحن نعرف عمل الزر الحقيقي )قادر على غلق أو فتح الدارة الكهربائية( هي مدمجة فتتي‬ ‫الكائن نفسه )و كذلك خصائصه الخرى ملثتتل حجمتته ولتتونه وإلتخ ...( .و بنفتس الطريقتتة، نحتن نأمتتل إذا اختلف خصتتائص زر‬ ‫البنامج )حجمه ، مكانه، لونه، النص الكتوب عليه(، ولكن أيضا تعريف ما يحدث عندما القيام بحركات بالفأرة علتتى هتتذا التتزر،‬ ‫سواء أن يتم جمع داخل كيان محدد جدا في البنامج، حت ل يكون هنالك أي خلط بي الزرار، أو حت أكتتث متتن ذلتتك بيتت زر‬ ‫والكيانات الخرى .‬ ‫تعريف أسلوب‬ ‫لتوضتتيح كلمنتتا، ستتوف نعتترف صتتنفا جديتتدا ‪ ،()Time‬و التتذي ينبغتتي لتته أن يستتمح لنتتا بتتأداء مجموعتتة متتن العمليتتات علتتى‬ ‫اللحظات والدد )جمع مدة(، إلخ :‬

‫الصناف والساليب والميراث‬
‫:)‪>>> class Time(object‬‬ ‫...‬ ‫"‪"définition d'objets temporels‬‬

‫681‬

‫اصنع الن كائنا من نفس النوع، وأضف له متغيات اللثيل لحفظ الساعات والدقائق واللثواني :‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫)(‪instant = Time‬‬ ‫11 = ‪instant.heure‬‬ ‫43 = ‪instant.minute‬‬ ‫52 = ‪instant.seconde‬‬

‫باعتباره تمرينا، اكتب الن بنفسك دالة ‪ ، ()affiche_heure‬والت تستخدم لعرض محتويات كائن من صتتنف ‪()Time‬‬ ‫فتتي الشتتكل التقليتتدي "ستتاعات:دقتتائق:ثتتواني". عنتتد تطتتبيق الكتتائن التتذي قمنتتا بصتتنعه فتتوق، هتتذه الدالتتة يجتتب أن تعتترض‬ ‫52:43:11 :‬
‫)‪>>> affiche_heure(instant‬‬ ‫52:43:11‬

‫دالتك قد يكون عشكلها كهذا :‬
‫:)‪>>> def affiche_heure(t‬‬ ‫...‬ ‫))‪print(str(t.heure) +":" +str(t.minute) +":" +str(t.seconde‬‬

‫أو أفضل من ذلك، ملثل هذا :‬
‫:)‪>>> def affiche_heure(t‬‬ ‫...‬ ‫))‪print("{0}:{1}:{2}".format(t.heure, t.minute, t.seconde‬‬

‫بتطبيق تقنية تنسيق السلسل الت شحناها في الصفحة 941.‬ ‫ربما تكون بحاجة إلى استخدام كائنات الصنف ‪ ،()Time‬هذه الدالة ربما تكون مفيدة لك للعرض.‬ ‫قد يكون من الحكمة تغليف هذه الدالة ‪ ()affiche_heure‬في الصنف ‪- ()Time‬نفسها، بطريقة نجعلهتتا دائمتتا متتتوفرة‬ ‫تلقائيا، كلما أردنا معالجة كائنات من الصنف ‪.()Time‬‬ ‫الدالة الت نريد تغليفها في صنف يسمى بشكل تفضيلي أسلوب ‪.méthode‬‬ ‫و لقد تحدثنا عن الساليب في عدة متترات فتتي الفصتتول الستتابقة متتن هتتذا الكتتتاب، وأنتتت تعتترف بالفعتتل أن الستتاليب هتتي دالت‬ ‫مرتبطة بصنف محدد بكائنات. بقي فقط أن تعلم كيفية صنع هذه الدالة .‬

‫781‬

‫تعريف أسلوب‬ ‫تعريف محدد للسلوب في لسكريبت‬ ‫تعريف أسلوب ملثل تعريف دالة، هذا معناه كتابة كتلة من التعليمات بعد الكلمة الحجوز ‪ ،def‬لكن مع اختلفي:‬

‫• تعريف السلوب يكون مكانه دائما داخل تعريف الصنف، بطريقة حت يظهر بوضوح العلقة بي السلوب والصنف.‬ ‫• تعريف السلوب يجب أن يحتوي دائما على برامت واحد على القل، والت يجب أن تكون مرجع اللثيل، وهذا البامت يجب‬ ‫أن يكون دائما الول .‬ ‫يمكنك مبدئيا استخدام أي اسم متغي للبامت الول، لكن يوص بشدة متابعة التفاقية لذا يكون دائما اسمه: ‪.self‬‬ ‫البامت ‪ self‬ضوري، لنه يجب أن تكون قادرا على تحديد اللثيل الذي سيتم ربطتته، فتتي جتتزء تعليمتتات متتن تعريفتته. ستتوف‬ ‫تفهم هذا بأكث سهولة مع الملثلة القادمة.‬ ‫نلحظ أن تعريف السلوب يحتوي دائما على برامتر واحد : ‪ ،self‬في حين أنه يمكن تعريف الدالة بــدون أن‬

‫تحتوي على أي شيء .‬ ‫انظر كيف يحدث هذا عمليا :‬

‫للتأكد من أن الدالتتة ‪ ()affiche_heure‬ستتكون أستتلوبا للصتتنف ‪،()Time‬تت ستتوف نحتتر،ك ببستتاطة تعريفهتتا إلتتى داختتل‬ ‫الصنف :‬
‫:)‪>>> class Time(object‬‬ ‫...‬ ‫"‪"Nouvelle classe temporelle‬‬ ‫...‬ ‫:)‪def affiche_heure(t‬‬ ‫...‬ ‫))‪print("{0}:{1}:{2}".format(t.heure, t.minute, t.seconde‬‬

‫من الناحية الفنية، فإن هذا يكفي تماما، لن البامتتت ‪ t‬تعيتت اللثيتتل للستتمات الرفقتتة ‪ heure، minute‬و ‪.seconde‬‬ ‫نظرا لدورها، فمن الستحسن تغيي اسمها إلى ‪: self‬‬
‫:)‪>>> class Time(object‬‬ ‫...‬ ‫"‪"Nouvelle classe temporelle‬‬ ‫...‬ ‫:)‪def affiche_heure(self‬‬ ‫...‬ ‫))‪print("{0}:{1}:{2}".format(self.heure, self.minute, self.seconde‬‬

‫تعريف السلوب ‪ ()affiche_heure‬أصبح الن جزءا من كتلة التعليمات البادئة التاليتتة للتعليمتتة الصتتنف )و هتتو أيضتتا‬ ‫جزء من الوثائق " ‪. ("Nouvelle classe temporelle‬‬

‫الصناف والساليب والميراث‬

‫881‬ ‫اختبار اللسلوب، في أي مثيل‬

‫لدينا الن الصنف ‪ ،()Time‬مع السلوب ‪ .()affiche_heure‬من حيث البدأ، نحن الن قادرون على صنع كائنات من‬ ‫هذا الصنف، وتطبيق عليها هذا السلوب. دعونا نرى ما إذا كان يعمل. وللقيام بذلك، نبدأ من تملثيل كائن:‬
‫)(‪>>> maintenant = Time‬‬

‫إذا حاولنا بسعة اختبار السلوب الجديد على هذا الكائن، فإنه ل يعمل :‬
‫)(‪>>> maintenant.affiche_heure‬‬ ‫'‪AttributeError: 'Time' object has no attribute 'heure‬‬

‫هذا أمر طبيعي : لم نصنع بعد سمات اللثيل. يجب أن نقوم على سبيل اللثال :‬
‫31 = ‪>>> maintenant.heure‬‬ ‫43 = ‪>>> maintenant.minute‬‬ ‫12 = ‪>>> maintenant.seconde‬‬

‫... ونحاول مرة أخرى. وهذه الرة إعشتغل :‬
‫)(‪>>> maintenant.affiche_heure‬‬ ‫12:43:31‬

‫في عدة مرات، لقد ذكرنا أنه ليس من الستحسن إنشاء سمات ملثيتتل لربطهتتا مباشتتة متتن ختتارج الكتتائن نفستته. ومتتن الضتتايقات‬ ‫الخرى، فإن هذا يلؤدي إلى أخطاء أخرى ملثل الت ذكرناها سابقا. دعونا نرى الن القيام بعمل أفضل .‬ ‫السلوب المنشئ‬ ‫الخطأ الذي تحدثنا عنه في الفقرة السابقة هل يمكن تجنبه؟‬ ‫هتذا ل يحتدث فعليتا، فتإذا قمنتا بتنظيتم الستلوب ‪ ()affiche_heure‬لجعلته دائمتا يعترض عشتيئا متا، دون أي يكتتون متن‬ ‫الضوري تعديل الكائن النش حديلثا. وبعبارات أخرى، سيكون من الحكمة أن متغيتتات اللثيتتل تكتتون معرفتتا مستتبقا فتتي البدايتتة‬ ‫الصنف، مع قيمة افتاضية.‬ ‫لتحقيق هذا، سوف نقوم باستدعاء أسلوب معي، والذي سوف يعي فيما بعد تحت استتم النشتت. الستتلوب النشتت لتتديه طريقتتة‬ ‫فريدة لكي يتم تشغيله تلقائيا عند تملثيل كائن جديد بداية من الصنف. لذا يمكننا وضتتع كتل متا يبتدو ضتوريا لتهيئتتته تلقائيتا‬ ‫عند إنشاء كائن.‬ ‫و هو معروف عند بيلثون، السلوب النش يدعى ضوري بت __‪) __init‬رمزي "فتتي أستفل الستطر"، وكلمتتة ‪،init‬ت ثتم رمتتزي‬ ‫"في أسفل السطر( .‬

‫981‬

‫السلوب المنشئ‬

‫مثال :‬
‫:)‪>>> class Time(object‬‬ ‫...‬ ‫"‪"Encore une nouvelle classe temporelle‬‬ ‫...‬ ‫:)‪def __init__(self‬‬ ‫...‬ ‫21= ‪self.heure‬‬ ‫...‬ ‫0= ‪self.minute‬‬ ‫...‬ ‫0= ‪self.seconde‬‬ ‫...‬ ‫:)‪def affiche_heure(self‬‬ ‫...‬ ‫))‪print("{0}:{1}:{2}".format(self.heure, self.minute, self.seconde‬‬

‫كما كان سابقا، إنشاء كائن من هذا الصنف وتجربة السلوب ‪: ()affiche_heure‬‬
‫)(‪>>> tstart = Time‬‬ ‫)(‪>>> tstart.affiche_heure‬‬ ‫0:0:21‬

‫لم نحصتتل علتتى أي خطتتأ هتذه الترة. فتتي الواقتتع : عنتتدما يتتم إنشتاء ملثيتل. الكتائن ‪ tstart‬يتتم تعييتت 3 ستتمات ،‪heure‬‬
‫‪ minute‬و ‪ seconde‬بواسطة السلوب النش مع 21 وصفر كقيمة أولية. ولهذا كائن من هذا الصنف موجود، يمكتتن أن‬ ‫نطلب عرض هذه السمات فورا.‬ ‫و الستفادة من هذه التقنية يزداد وضوحا إذا أضفنا عشيئا آخر.‬ ‫ملثل أي أسلوب يجب احتامه، السلوب __‪ ()__init‬تكتتون برامتتتاته جتتاهزة. وفتتي حالتتة هتذا الستتلوب الختاص متن النشت،‬ ‫البامتا يمكن أن تلعب دورا ملثيا للهتمام، لنها سوف تسمح بتهيئة بعض متغيات التملثيل في وقت تملثيل الكائن.‬ ‫يرجى إذا الرجوع إلى التمرين السابق، وغي تعريف السلوب __‪ ()__init‬على النحو التالي ::‬
‫...‬ ‫...‬ ‫...‬ ‫...‬ ‫:)0= ‪def __init__(self, hh =12, mm =0, ss‬‬ ‫‪self.heure =hh‬‬ ‫‪self.minute =mm‬‬ ‫‪self.seconde =ss‬‬

‫أسلوبنا الجديد __‪ ()__init‬لديه الن 3 برامتات، ولكل منها قيمة افتاضية. وبالتالي نحصل على صنف أكث تقدما. عنتتدما‬ ‫كنا نملثل كائن من هذا الصتنف، يمكننتا الن تهيئتتة ستماته الرئيستية بمستتاعدة البامتتات، ضتمن تعليمتتات التملثيتل. وإذا أردنتا‬ ‫حذف كل أو جزء منها، السمات تقوم بتسليم بأي عشكل من العشكال القيم الفتاضية.‬ ‫عندما نكتب تعليمات لتملثيل كائن جديد، وعندما تريد تمرير برامتات لسلوب النشت، يكفتي أن تضتعهم بيتت قوستي تصتتاحب‬ ‫اسم الصنف. لنشع إذا بالضبط ملثل طريقة عندما نريد استدعاء أي دالة.‬ ‫هذا ملثال لصنع وتملثيل كائن جديد ‪ ()Time‬في نفس الوقت :‬

‫الصناف والساليب والميراث‬
‫)81 ,51 ,01(‪>>> recreation = Time‬‬ ‫)(‪>>> recreation.affiche_heure‬‬ ‫81:51:01‬

‫091‬

‫منذ الن متغيات التملثيل لها الن قيم افتاضية، نحن نستطيع أيضا صنع قيتم افتاضتتية للكتائن ‪ ()Time‬بحتذف واحتد أو‬ ‫أكث من برامت :‬
‫)03 ,01(‪>>> rentree = Time‬‬ ‫)(‪>>> rentree.affiche_heure‬‬ ‫0:03:01‬

‫أو أكث :‬
‫)81= ‪>>> rendezVous = Time(hh‬‬ ‫)(‪>>> rendezVous.affiche_heure‬‬ ‫0:0:81‬

‫تمارين‬
‫21.1 عرف الصنف ‪ ()Domino‬الذي يسمح بتملثيل كائنت لحاكات أجزاء للعبة الدومينو. النش فتي هتذا الصتنف يهيت‬ ‫قيم هذه النقا ط على جانب ‪ A‬و ‪ B‬للدومينو )القيم الفتاضية = 0(. وقم بتعريف أسلوبي آخرين :‬ ‫•أسلوب ‪ ()valeur‬الذي يقوم بإرجاع مجموع النقا ط الوجودة على الجانبي ..‬
‫)6,2(‪>>> d1 = Domino‬‬ ‫)3,4(‪>>> d2 = Domino‬‬ ‫)(‪>>> d1.affiche_points‬‬ ‫6 : ‪face A : 2 face B‬‬ ‫)(‪>>> d2.affiche_points‬‬ ‫3 : ‪face A : 4 face B‬‬ ‫))(‪>>> print("total des points :", d1.valeur() + d2.valeur‬‬ ‫51‬ ‫][ = ‪>>> liste_dominos‬‬ ‫:)7(‪>>> for i in range‬‬ ‫...‬ ‫))‪liste_dominos.append(Domino(6, i‬‬ ‫)]3[‪>>> print(liste_dominos‬‬ ‫>‪>> compte1.depot‬‬ ‫)002(‪>>> compte1.retrait‬‬ ‫)(‪>>> compte1.affiche‬‬ ‫.‪Le solde du compte bancaire de Duchmol est de 950 euros‬‬ ‫)(‪>>> compte2 = CompteBancaire‬‬ ‫)52(‪>>> compte2.depot‬‬ ‫)(‪>>> compte2.affiche‬‬ ‫.‪Le solde du compte bancaire de Dupont est de 1025 euros‬‬

‫• ‪ (accelerer(taux, duree‬يسمح بتبديل سعة السيارة. تبديل السعة يساوى حسب سعة النتتتج :‬ ‫على سعة 62 مت في الدقيقة. ويسمح بالعدلت السلبية )و هو التباطلؤ(. الختلف في الستعة لتم يستمح لته إذا‬ ‫العدل × الدة. على سبيل اللثال، إذا كان تسارع السيارة بمعدل 3,1 مت في اللثانية لتتدة 02 ثانيتتة، ستتوف تحصتتل‬

‫•‪ (choix_conducteur(nom‬يسمح بتحديد )أو تغيي( اسم السائق.‬

‫•‪ ()affiche_tout‬يسمح بإظهار خصائص الوجتتودة فتتي الستتيارة، وهتذا معنتتاه شتتكتها، لتتونه واستم ستائقها‬ ‫أملثلة استخدام لهذا الصنف :‬ ‫وسعتها.‬

‫كان السائق "عشخص" .‬

‫)'‪>>> a1 = Voiture('Peugeot', 'bleue‬‬ ‫)'‪>>> a2 = Voiture(couleur = 'verte‬‬ ‫)'‪>>> a3 = Voiture('Mercedes‬‬ ‫)'‪>>> a1.choix_conducteur('Roméo‬‬ ‫)'‪>>> a2.choix_conducteur('Juliette‬‬ ‫)21 ,8.1(‪>>> a2.accelerer‬‬ ‫)11 ,9.1(‪>>> a3.accelerer‬‬ ‫! ‪Cette voiture n'a pas de conducteur‬‬ ‫)(‪>>> a2.affiche_tout‬‬ ‫.‪Ford verte pilotée par Juliette, vitesse = 21.6 m/s‬‬ ‫)(‪>>> a3.affiche_tout‬‬ ‫.‪Mercedes rouge pilotée par personne, vitesse = 0 m/s‬‬

‫الصناف والساليب والميراث‬

‫291‬

‫21.4 عرف الصنف ‪ ()Satellite‬التذي يستمح بتملثيتل كائنتات تحتتاكي القمتار الصتناعية التت تطلتق فتي الفضتاء حتتول‬ ‫الرض. النش لهذا الصنف يهي سمات التملثيل التالية، مع القيم الفتاضية البينة :‬
‫,001 = ‪masse‬‬ ‫.0 = ‪vitesse‬‬

‫عند إنشاء ملثيل لكائن جديد ‪ ،()Satellite‬يمكن اختيار اسمه وكتلته وسعته.‬ ‫• ‪ (impulsion(force, duree‬تسمح بتفاوت سعة القمر الصناعي. لعرفة كيفية فعل هذا، تذكر دروس‬ ‫الساليب التالية سوف يتم تعريفها :‬

‫الفيياء : ستتعة التفتاوة ‪ Δv‬التت يمتر بهتا الكتائن بكتلتتة ‪ m‬تخضتتع لحركتة قتوة ‪ F‬فتتي غضتون وقتت ‪t vaut‬‬ ‫‪F×t‬‬ ‫=‪ )v‬كه(‪ . δ‬على سبيل اللثال : قمر صتناعي يتزن 003 كيلتوغرام يخضتتع لقتوة 006 نيتتوتن لتدة 01 ثتواني‬ ‫‪m‬‬ ‫سوف تزداد سعته)أو تنقص( 02م/ثانية.‬

‫•‪ ()energie‬تقوم بإرجاع إلى البنامج الذي استدعاؤها قيمة الطاقة الحركية للقمر الصناعي. .‬ ‫‪m×v‬‬ ‫=‪E c‬‬ ‫2‬
‫2‬

‫• ‪ ()affiche_vitesse‬عرض اسم القمر الصناعي وسعته الحالية.‬ ‫تذكي / يتم حساب الطاقة الحركية باستخدام الصيغة :‬ ‫أملثلة استخدام لهذا الصنف :‬

‫)01= ‪>>> s1 = Satellite('Zoé', masse =250, vitesse‬‬ ‫)51 ,005(‪>>> s1.impulsion‬‬ ‫)(‪>>> s1.affiche_vitesse‬‬ ‫.‪vitesse du satellite Zoé = 40 m/s‬‬ ‫)‪>>> print (s1.energie‬‬ ‫000002‬ ‫)51 ,005(‪>>> s1.impulsion‬‬ ‫)(‪>>> s1.affiche_vitesse‬‬ ‫.‪vitesse du satellite Zoé = 70 m/s‬‬ ‫)‪>>> print (s1.energie‬‬ ‫005216‬

‫مساحات أسماء الصناف لوالمثيل‬ ‫لقتد تعلمتتت ستابقا )انظتتر للصتفحة 86( أن التغيتتات التتت يتتم تعريفهتتا داختل دالتة هتتي متغيتات خاصتتة )محليتتة(، ل يمكنهتتا‬ ‫الوصول إلى تعليمات الوجودة خارج الدالة. وهذا يتيح لها استخدام نفتتس الستتماء فتتي أجتتزاء مختلفتتة متتن البنامتتج، متتن دون‬ ‫خطر تداخلهم.‬ ‫لوصف هذا بطريقة أخرى، يمكن أن نقول أن كل دالة لديها مساحة أسمائها، بغض النظر عن مساحة السماء الرئيسة.‬ ‫و تعلمت أيضا أن التعليمات الوجودة داخل الدالة يمكنها الوصول إلى التغيات التتت تتتم تعريفهتتا علتتى مستتتوى الرئيستت، لكتتن‬ ‫فقط بالتشاور : يمكنها استخدام قيم هذه التغيات، لكن ليس تعديلها )إل لو استدعيت عبارة ‪.(global‬‬

‫391‬

‫مساظحات أسماء الصناف والمثيل‬ ‫لذا يوجد تسلسل هرمي بي مساحات السماء. سوف نرى نفس الشء عن الصناف والكائنات. وفي الحقيقة :‬

‫• كل صنف لتديه مستاحة الستماء الخاصتتة بته. التغيتات التت هتتي جتزء متن الصتنف تستمى بمتغيتات الصتنف أو ستمات‬ ‫الصنف.‬ ‫• كل كائن ملثيل )تم صتتنعه متن صتنف( يحصتتل علتتى مستتاحة الستماء الخاصتتة بتته. التغيتات التت هتتي جتزء منهتتا تستتمى‬ ‫متغيات اللثيل أو سمات اللثيل.‬ ‫• الصناف يمكنها استخدام )لكن ليس تعديل( التغيات الت تم تعريفها في الستوى الرئيس.‬ ‫• اللثيل يمكنه استخدام )لكن ليس تعديل( متغيات الت تم تعريفها في الستوى الرئيس للصنف والتغيات الت تم تعريفها‬ ‫في التسوى الرئيس للبنامج .‬ ‫‪ recreation، rentree‬و ‪ .rendezVous‬كل واحد تم تملثيله مع قيتم مختلفتتة ومستتقلة. يمكننتتا تعتديل وإعتتادة‬
‫21 = ‪>>> recreation.heure‬‬ ‫)(‪>>> rentree.affiche_heure‬‬ ‫0:03:01‬ ‫)(‪>>> recreation.affiche_heure‬‬ ‫81:51:21‬

‫على سبيل اللثال انظتتر إلتتى الصتنف ‪ ()Time‬التذي تتم تعريفتته ستابقا. فتتي الصتفحة 091، ملثلنتتا 3 كائنتات متن هتذا الصتنف:‬ ‫عرض هذه التغيات كل واحدة من هذه الكائنات، دون أن يلؤثر أي واحد على الخر :‬

‫أرجو الن أن تقوم بتمي وتجربة اللثال أدناه :‬
‫:)‪>>> class Espaces(object‬‬ ‫...‬ ‫33 = ‪aa‬‬ ‫...‬ ‫:)‪def affiche(self‬‬ ‫...‬ ‫)‪print(aa, Espaces.aa, self.aa‬‬ ‫...‬ ‫21 = ‪>>> aa‬‬ ‫)(‪>>> essai = Espaces‬‬ ‫76 = ‪>>> essai.aa‬‬ ‫)(‪>>> essai.affiche‬‬ ‫76 33 21‬ ‫)‪>>> print(aa, Espaces.aa, essai.aa‬‬ ‫76 33 21‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫1‬ ‫2‬ ‫3‬ ‫4‬ ‫5‬ ‫6‬ ‫7‬ ‫8‬

‫9 #‬

‫في هذا اللثال، السم ‪ aa‬يستخدم لتعريف ثلثة متغيتات مختلفتة : الولتى فتي مستاحة أستماء الصتنف )فتي الستطر اللثتاني(،‬ ‫وواحدة أخرى في مساحة السماء الرئيسة )في السطر الخامس(، وأخيا في مساحة أسماء اللثيل )في السطر السابع(.‬ ‫في السطر الرابع والسطر التاسع يبي كيفية الوصول إلى هذه الفضتتائات اللثلثتتة للستتماء )فتتي داختتل الصتتف، أو فتتي الستتتوى‬ ‫الرئيس(، وذلك باستتخدام تأهيتتل بالنقتا ط. ولحتتظ أيضتتا متترة أخترى استتخدام ‪ self‬للعشتارة إلتتى اللثيتل فتتي داختتل تعريتتف‬ ‫الصنف .‬

‫الصناف والساليب والميراث‬

‫491‬ ‫الرث‬

‫الصناف هي الداة الرئيسية للبمجة الشيئية )أو ‪ ،( OOP‬التت تعتتب اليتوم تقنيتة البمجتتة الكتث فعاليتة. واحتدة متن الزايتا‬ ‫الرئيسية لهذا النوع من البمجة يكمن في أن نتمكن من استخدام دائما فئة موجود لنشاء واحدة أخرى، والت سوف ترث جميع‬ ‫خصائصه لكن تستطيع تغيي بعضها أو إضافة خصائص جديدة. وهذه العملية تدعى العشتقاق. ويقوم بإنشاء تسلستل هرمتي‬ ‫للصناف من العامة إلى الخاصة.‬ ‫على سبيل اللثال سوف نعرف الصنف ‪،()Mammifere‬تت الذي يحتوي على خصائص هتتذه الجموعتتة متتن الحيوانتتات. ومتتن‬ ‫هتتذا الصتتنف الصتتل )الم(، يمكننتتا اعشتتتقاق واحتدة أو أكتتث متتن هتتذه الصتتناف الفرعيتتة ملثتتل صتتنف ‪،()Primate‬تت وصتتنف‬ ‫‪،()Rongeur‬تت وصتتنف ‪،()Carnivore‬تت إلتتخ.، والتتت ستتوف تتترث جميتتع خصتتائص الصتتنف ‪،()Mammifere‬تت ثتتم‬ ‫نضيف إليها خصائص هذه الجموعة.‬ ‫بداية من الصنف ‪ ،()Carnivore‬نستطيع اعشتقاق صنف ‪ ،()Belette‬والصنف ‪ ،()Loup‬والصنف ‪ ،()Chien‬إلخ.‬ ‫وهم يرثون جميع خصائص صنف الصل والصنف الذي فوقه. ملثال :‬
‫:)‪>>> class Mammifere(object‬‬ ‫...‬ ‫"; ‪caract1 = "il allaite ses petits‬‬ ‫:)‪>>> class Carnivore(Mammifere‬‬ ‫...‬ ‫"; ‪caract2 = "il se nourrit de la chair de ses proies‬‬ ‫:)‪>>> class Chien(Carnivore‬‬ ‫...‬ ‫"; ‪caract3 = "son cri s'appelle aboiement‬‬ ‫)(‪>>> mirza = Chien‬‬ ‫)3‪>>> print(mirza.caract1, mirza.caract2, mirza.caract‬‬ ‫; ‪il allaite ses petits ; il se nourrit de la chair de ses proies‬‬ ‫; ‪son cri s'appelle aboiement‬‬

‫في هذا اللثال، نرى أن الكائن ‪ ، mirza‬لديه ملثيل لصنف ‪ ،()Chien‬ولم يرث فقط سمات الت تم تعريفها في هذا الصنف،‬ ‫بل حت سمات الت تم تعريفها للصناف الصل.‬ ‫لقد رأينا في هذا اللثال كيف نشع في اعشتقاق صنف من الصنف الصل )الم( : باستخدام تعليمتتة ‪،class‬تت ثتتم كالعتتادة استتم‬ ‫الذي نريد تعيينه لهذا الصنف، وفي ما بي قوسي استتم الصتتنف الصتتل. الصتتناف الول التتت تستتتمد منهتتا الصتتناف الختترى‬ ‫تسمى السلف.‬ ‫لحظ أن السمات الستخدمة في هذا اللثال هي سمات أصناف )و ليستتت ستتمات اللثيتتل(. اللثيتتل ‪ mirza‬يمكنتته الوصتتول لهتذه‬ ‫السمات، لكن ليس تغييها:‬

‫الرث 591‬
‫"; ‪>>> mirza.caract2 = "son corps est couvert de poils‬‬ ‫)2‪>>> print(mirza.caract‬‬ ‫; ‪son corps est couvert de poils‬‬ ‫)(‪>>> fido = Chien‬‬ ‫)2‪>>> print(fido.caract‬‬ ‫; ‪il se nourrit de la chair de ses proies‬‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫1‬ ‫2‬ ‫3‬ ‫4‬ ‫5‬ ‫6‬

‫في اللثال الجديد، فتتي الستطر الول، لتم يغيتت ستمة 2‪ caract‬للصتنف ‪،()Carnivore‬ت علتتى عكتس متا تتراه فتتي الستطر‬ ‫اللثالث. يمكنك التحقق من خلل صنع ملثيل جديد ‪) fido‬من السطر 4 إلى السطر 6(.‬ ‫إذا كنت قد فهمت جيدا الفقرات السابقة، فإنك سوف تفهم أن التعليمة في السطر 1 تصنع متغيا جديدا للثيتتل مرتبتتط فقتتط متتع‬ ‫الكتتائن ‪ .mirza‬ولتتذلك يوجتتد الن متغيتتان لهمتتا نفتتس الستتم 2‪ : caract‬واحتتدة فتتي مستتاحة أستتماء للكتتائن ‪،mirza‬‬ ‫واللثانية في مساحة أسماء الصنف ‪.()Carnivore‬‬ ‫لكن كيف يمكننا أن نفس ما يحدث في السطرين 2 و 3 ؟‬ ‫كما رأينا أعله، اللثيل ‪ mirza‬يمكنه الوصول للمتغيات الت تقع في مساحة أستماء الصتناف الصتتل. فتإذا وجتد متغيتات‬ ‫بنفس السم في العديد من هذه الساحات، فأي واحدة سيختار أثناء تشغيل التعليمة ملثل الت في السطر اللثاني ؟‬ ‫لحل هذا التعارض، يتبع بيلثون قاعدة الولويات في غاية البساطة. فعندما تسأله لستخدام قيمة متغي يدعى ‪ ،alpha‬على‬ ‫سبيل اللثال، فإنه يبدأ في البحث عن هذا السم في الساحة الحلية )الداخلية(. فإذا وجد التغي ‪ alpha‬في الساحة الحلية،‬ ‫يستخدمه ويوقف البحث. وإذا لم يجده، يقوم بيلثون بفحص مساحة أسماء هيكل الصتتل، ثتم هيكتتل فتتوق الصتتل، وإلتخ إلتى أن‬ ‫يصل إلى الستوى الرئيس للبنامج.‬ ‫في السطر اللثاني من ملثالنا، فإنه متغي اللثيل هو الذي يتم استتتخدامه. وفتتي الستتطر الختتامس، فتتإنه فتتي الستتوى الصتنف فتتوق‬ ‫الصل يوجد به متغي باسم 2‪ caract‬لذا هذا الذي قام بعرضه ..‬ ‫الميراث لوالتعدد‬ ‫حلل بعناية السكريبت في الصفحة التالية. أنها تنفذ عدة مفاهيم مذكورة أعله، ول سيما مفهوم الياث.‬ ‫لفهم السكريبت، يجب عليك تذكر بعض الفاهيم الكيميائية. في مادة الكيمياء الخاصة بك، فإنك بالتأكيد قد تعلمتتت أن التتذرات‬ ‫هتتي كيانتتات تتكتتون متتن عتتدد متتن البوتونتتات)جستتيمات مشتتحونة بطاقتتة كهربائيتتة موجبتتة(، واللكتونتتات )عشتتحنتها ستتالبة(‬ ‫والنيوترونات )محايدة(.‬

‫الصناف والساليب والميراث‬

‫691‬

‫نوع الذرة )أو العنص( يتم تحديده من خلل عدد البوتونات، والذي يستتمى أيضتتا بالعتدد التذري. فتتي حتالته الساستية، التذرة‬ ‫تحتوي على إلكتونات بنفس عدد البوتونات، وبالتالي فهي متعادلة كهربائيتا. كمتا أن لهتا عتدد متغيتت متن النيوترونتات، لكتن‬ ‫هذا ل يلؤثر بأي عشكل من العشكال على الشحنة الكهربائية عموما.‬ ‫في ظروف معينة، يمكن للذكرة أن تكتسب أو أن تفقد إلكتون. وفي هذه الحالتتة يكتستتب عشتتخنة كهربائيتتة عامتتة ويصتتبح أيتتون‬ ‫)اليون السلب إذا إكتسبت الذرة إلكتون أو أكث واليون اليجابي إذا فقدت(. الشتتحنة الكهربائيتتة لليتتون تستتاوي الفتترق بيتت‬ ‫عدد البوتونات وعدد اللكتونات الت تحتويها.‬ ‫السكريبت في الصفحة التاليتة يصتنع كائنتات ‪ ()Atome‬وكائنتات ‪ .()Ion‬ذكرنتا بتالعلى أن اليتون هتو ببستاطة ذرة تتم‬ ‫تغييها. في برمجتنا، الصنف الذي يقوم بتعريف كائنات ‪ ()Ion‬سيكون صنف فرعي من الصنف ‪ : ()Atome‬سوف يتترث‬ ‫جميع سماته وأساليبه، ثم يضيف عليها خصائصه.‬ ‫واحدة من هذه الساليب التتت تمتتت إضتتافتها )الستلوب ‪ (()affiche‬تستتتبدل الستلوب متن نفتس استم التوروث متن الصتنف‬ ‫‪ .()Atome‬الصناف ‪ ()Atome‬و ‪ ()Ion‬لديهم كل واحد منهم أسلوب بنفس السم، لكن يعمل بشتتكل مختلتتف. لنتحتتدث‬ ‫عن هذه الحالة من تعدد العشكال. يمكننا القول أن السلوب ‪ ()affiche‬من الصنف ‪ ()Atome‬كان فوق الطاقة .‬ ‫من الواضع أنه من المكن صتتنع ملثيتتل لي عتتدد متتن التذرات واليونتتات متتن هتتذين الصتتنفي. أو واحتتدة داختتل الختترى، الصتتنف‬ ‫‪،()Atome‬تت يجب عليه أن يحتوي على نسخة مبسطة من الجدول الدوري للعناص )الجتتدول التتدوري(، بحيتتث يمكنتتك تعييتت‬ ‫اسم العنص الكيميائي، وعدد النيوترونات، لكل كائن صنعته. كما أنه ليتتس متتن الرغتتوب نستتخ هتتذا الجتتدول لكتتل ملثيتتل، ستتوف‬ ‫نضعه في سمة الصنف. وبالتالي هذ الجدول لن يتواجد إل في مكان واحد في الذاكرة، حتتت تبقتتى فتتي متنتتاول جميتتع الكائنتتات‬ ‫الت سيتم إنتاجها من هذا الصنف .‬
‫:‪class Atome‬‬ ‫"""‪"""atomes simplifiés, choisis parmi les 10 premiers éléments du TP‬‬ ‫,)4,'‪table =[None, ('hydrogène',0),('hélium',2),('lithium‬‬ ‫,)7,'‪('béryllium',5),('bore',6),('carbone',6),('azote‬‬ ‫])01,'‪('oxygène',8),('fluor',10),('néon‬‬ ‫:)‪def __init__(self, nat‬‬ ‫"‪"le n° atomique détermine le n. de protons, d'électrons et de neutrons‬‬ ‫‪self.np, self.ne = nat, nat‬‬ ‫العدد الذري = ‪# nat‬‬ ‫]1[]‪self.nn = Atome.table[nat‬‬ ‫:)‪def affiche(self‬‬ ‫)(‪print‬‬ ‫)]0[]‪print("Nom de l'élément :", Atome.table[self.np‬‬ ‫\."‪print("{0} protons, {1} électrons, {2} neutrons‬‬ ‫))‪format(self.np, self.ne, self.nn‬‬

‫791‬
‫:)‪class Ion(Atome‬‬ ‫"""‪"""les ions sont des atomes qui ont gagné ou perdu des électrons‬‬ ‫:)‪def __init__(self, nat, charge‬‬ ‫"‪"le n° atomique et la charge électrique déterminent l'ion‬‬ ‫)‪Atome.__init__(self, nat‬‬ ‫‪self.ne = self.ne - charge‬‬ ‫‪self.charge = charge‬‬ ‫:)‪def affiche(self‬‬ ‫)‪Atome.affiche(self‬‬ ‫)‪print("Particule électrisée. Charge =", self.charge‬‬ ‫### : البرنامج الرئيسي ###‬ ‫)5(‪a1 = Atome‬‬ ‫)1 ,3(‪a2 = Ion‬‬ ‫)2- ,8(‪a3 = Ion‬‬ ‫)(‪a1.affiche‬‬ ‫)(‪a2.affiche‬‬ ‫)(‪a3.affiche‬‬

‫الميراث والتعدد‬

‫عند تشغيل هذا البنامج سوف يظهر التالي :‬
‫‪Nom de l'élément : bore‬‬ ‫‪5 protons, 5 électrons, 6 neutrons‬‬ ‫‪Nom de l'élément : lithium‬‬ ‫‪3 protons, 2 électrons, 4 neutrons‬‬ ‫1 = ‪Particule électrisée. Charge‬‬ ‫‪Nom de l'élément : oxygène‬‬ ‫‪8 protons, 10 électrons, 8 neutrons‬‬ ‫2- = ‪Particule électrisée. Charge‬‬

‫في مستوى البنامج الرئيس، يمكنك أن ترى أننا ملثلنا كائنات ‪ ()Atome‬عددها التتذري )التتذي يجتتب أن يكتتون متتا بيتت 1 و‬ ‫01(. لتملثيتتل كائنتتات ‪،()Ion‬تت يجتتب أن نتتوفر العتتدد التتذري وعشتتحنته الكهربائيتتة العامتتة )موجبتتة أو ستتالبة(. نفتتس الستتلوب‬ ‫‪ ()affiche‬يبي خصائص هذه الكائنات، سواء أن كانت ذرات أو أيونات، وفي حالة اليون خط إضافي )تعدد العشكال( .‬ ‫التعليقات‬ ‫تعريف الصنف ‪ ()Atome‬يبدأ بتعيي التغي ‪ .table‬التغي الذي يتم تعريفه هنا هو جزء من مساحة أستتماء الصتتنف.‬ ‫إذا هذا هو سمة الصنف، الذي نضع فيها قائمة العلومتتات حتتول 01 أول عناصتت الجتتدول التدوري لنتدليف )استتم الشتتخص التتذي‬ ‫اختع هذا الجدول(.‬

‫الصناف والساليب والميراث‬

‫891‬

‫لكل واحدة من هذه العناص، قائمة تحتوي علتتى مصتتفوفة مغلقتتة )‪) : (tuple‬استم العنصتت، عتتدد النيوترونتتات(، واللؤشتت التتذي‬ ‫يتوافق مع العدد الذري. وبما أنه ل توجد عناص عددها التذري صتفر، لتذا وضتعنا للملؤشتت صتفر فتي القائمتة، الكتائن الختاص.‬ ‫يمكننا وضع هنا،ك أي قيمة أخرى، لن هذا اللؤش لن يستخدم الكائن ‪ None‬لبيلثون .‬ ‫تليها تعارف السلوبي :‬ ‫•النش __‪ ()__init‬يستخدم أساسا هنا لصنع ثلثة سمات اللثيل، لتخزيتتن فتتي التذاكرة أعتتداد البوتونتتات واللكتونتتات‬ ‫والنيوترونتات علتى التتوالي لكتل كتائن ذرة صتنع متن هتذا الصتنف )تتذكر أن ستمات اللثيتل هتتي متغيتات مرتبطتة برامتت‬ ‫‪.(self‬‬ ‫لحظ أن التقنية الستخدمة للحصول على عدد النيوترونات من سمة الصتتنف، ممتتا يتتدل علتتى استتم الصتتنف ملؤهتتل بنقتتا ط،‬ ‫ملثل في التعليمة: 1[]‪.[self.nn = Atome.table[nat‬‬ ‫•السلوب ‪ ()affiche‬يستخدم سمات اللثيل، ليجاد عدد البوتونات واللكتونات والنيوترونتتات للكتتائن الحتتالي، وستتمة‬ ‫الصنف )الت هي مشتكة بي جميع الكائنات( لستخراج اسم العنص الطابق .‬ ‫تعريف صنف ‪ ()Ion‬يتضمن في أقواسه اسم الصنف ‪ ()Atome‬أعله.‬ ‫أساليب هذا الصنف هي بدائل الصنف ‪ .()Atome‬سيقومون باحتمال استدعاء هذه. هذه اللحظة مهمة : كيتتف يمكننتتا، فتتي‬ ‫إطار تعريف الصنف، استدعاء السلوب الذي تم تعريفه في صنف آخر.‬ ‫ل ينبغي أن نغفل، في الحقيقة، عن السلوب الذي يرتبط دائما باللثيل الذي سيتم صنعه من هذا الصنف )اللثيل يملثتتل بواستتطة‬ ‫‪ self‬في تعريفه(. إذا كان السلوب يجب عليه استدعاء أسلوب آخر تم تعريفه في صنف آخر، يجب أن يكون قادر علتتى نقتتل‬ ‫الرجع اللثيل الذي ينبغي أن يقتن بها. كيف نفعل هذا؟ هذا بسيط جدا:‬ ‫في تعريف الصنف، قد نرغب باستدعاء أسلوب تم تعريفه في صنف اخر، يمكننا ببساطة استدعاؤها مباشرة،‬

‫عن طريق صنف اخر، بتمرير مرجع المثيل كبرامتر أول .‬

‫وبالتتتالي فتتي ستتكريبتنا ، علتتى ستتبيل اللثتتال، الستتلوب للصتتنف ‪ ()affiche‬للصتتنف ‪ ()Ion‬يمكنتته استتتدعاء الستتلوب‬ ‫‪ ()affiche‬للصنف ‪ : ()Atome‬العلومات العروضة ستكون الكائن-اليتون الحتالي، لن مرحعته تتم تمريتتره فتي تعليمتتة‬ ‫تدعى:‬
‫)‪Atome.affiche(self‬‬

‫991‬

‫الميراث والتعدد‬

‫في هذه التعليمة، ‪ self‬بالطبع هو مرجع اللثيل الحالي. بنفس الطريقة )سوف نرى أملثلة أختترى كتتلثية فيمتتا بعتتد(، الستتلوب‬ ‫النش للصنف ‪ ()Ion‬استدعى السلوب النش للصنفه الصل، في :‬
‫)‪Atome.__init__(self, nat‬‬

‫هذا الستدعاء ضوري، بحيث يتم تهيئة كائنات الصنف ‪ ()Ion‬بنفس الطريقة كائنات الصنف ‪ Atome(). Si nous‬إذا‬ ‫كنا لم نقم بهذا الستتدعاء، الكائنتات-اليونتات لتن يرثتتوا تلقائيتا ستمات ‪ ne، np‬و ‪،nn‬ت لن هتذه ستمات اللثيتل تتم صتنعها‬ ‫بواسطة أسلوب النش للصنف ‪ ،()Atome‬و ذلك لن يتم استدعاؤه تلقائيا عند إنشاء كائنات من صنف مشتق.‬ ‫افهم إ ذا أن الياث ل ينطبق إل على الصناف، وليتس علتتى ملثيتل هتذه الصتناف. وعنتدما نقتول أن صتنفا مشتتقا يترث جميتتع‬ ‫ً‬ ‫خصائص صنفه الصل، هذا ل يعن أن الخصائص اللثيل للصنف الصل ينقل تلقائيا لملثال الصنف البن. ووفقا لذلك، تذكر:‬ ‫في أسلوب منشئ الصنف المشتق، يجب تقريبا دائما أن تقوم باستدعاء أسلوب المنشئ من صنف الصل .‬

‫الصناف والساليب والميراث‬

‫002‬

201

‫وظحدات تحتوي على مكتبات الصناف‬ ‫لوحدات تحتوي على مكتبات الصناف‬

‫أنت تعرف بالفعل منذ وقت طويل استخدام وحدات بيلثون )انظر للصفحات 25 و97(. وأنت تعرف أنها يتم تجميعها في مكتبات‬ ‫متكونة من الصناف والدالت. كتمرين مرجعة، سوف تقتوم بصتنع وحتدة جديتدة متن الصتتناف، بتتمي أستطر التعليمتات فتي‬ : formes.py ‫السفل في ملف وحدة الت سوف تسميها‬ class Rectangle(object): "Classe de rectangles" def __init__(self, longueur =0, largeur =0): self.L = longueur self.l = largeur self.nom ="rectangle" def perimetre(self): return "({0:d} + {1:d}) * 2 = {2:d}".\ format(self.L, self.l, (self.L + self.l)*2) def surface(self): return "{0:d} * {1:d} = {2:d}".format(self.L, self.l, self.L*self.l) def mesures(self): print("Un {0} de {1:d} sur {2:d}".format(self.nom, self.L, self.l)) print("a une surface de {0}".format(self.surface())) print("et un périmètre de {0}\n".format(self.perimetre())) class Carre(Rectangle): "Classe de carrés" def __init__(self, cote): Rectangle.__init__(self, cote, cote) self.nom ="carré" if __name__ == "__main__": r1 = Rectangle(15, 30) r1.mesures() c1 = Carre(13) c1.mesures()

‫عند حفظ هذه الوحدة، يمكنك استخدامه بطريقتي : إما أن تقتتوم بتشتتغيله ملثتتل أي برنامتتج، وإمتتا متتن خلل استتتدعائه فتتي أي‬ : ‫سكريبت أو من سطر الوامر، لستخدام أصنافه. انظر لهذا اللثال‬
>>> import formes >>> f1 = formes.Rectangle(27, 12) >>> f1.mesures() Un rectangle de 27 sur 12 a une surface de 27 * 12 = 324 et un périmètre de (27 + 12) * 2 = 78 >>> f2 = formes.Carre(13) >>> f2.mesures() Un carré de 13 sur 13 a une surface de 13 * 13 = 169 et un périmètre de (13 + 13) * 2 = 52

‫الصناف والساليب والميراث‬

‫202‬

‫نحن نرى في هذا السكريبت أن الصنف ‪ ()Carre‬تم إنشاؤه من الصنف ‪ ()Rectangle‬لتذا هتتو يتترث جميتتع خصائصتته.‬ ‫وبعبارة أخرى، الصنف ‪ ()Carre‬هو ابن الصنف ‪.()Rectangle‬‬ ‫يجتتتتتب عليتتتتته استتتتتتدعاء منشتتتتتت الصتتتتتنف الصتتتتتل )‬ ‫‪ ،( (... ،Rectangle.__init__(self‬وأن يمرر له مرجع اللثيل )‪ (self‬كأول برامت.‬ ‫أما بالنسبة للتعليمة :‬
‫:"__‪if __name__ == "__main‬‬

‫قتتتتتد تلحتتتتتظ متتتتترة أختتتتترى أن منشتتتتتت الصتتتتتنف ‪()Carre‬‬

‫تم وضعها في نهاية الوحدة، وتستخدم لعرفة إذا كانت الوحدة تم تشغيلها كبنامج مستقل )في هذه الحالة يجب أن يتم تنفيذ‬ ‫التعليمات الت تليها(، أو تم استخدامه كمكتبة لصنف تم استدعاؤه في مكان آخر. في هذه الحالة هذا الجزء متن الكتود ليتس لته‬ ‫أي تأثي .‬

‫تمارين‬
‫21.5 عرف الصنف ‪ .()Cercle‬و الصناف الت تم صتنعا متن هتذا الصتنف تكتتون دوائتر بأحجتام مختلفتتة. بالضتافة إلتى‬ ‫أسلوب منش )الذي سوف يستخدم البامت ‪،(rayon‬تت يمكنك تعريف السلوب ‪،()surface‬تت الذي يقتتوم بإرجتتاع‬ ‫مساحة الدائرة.‬

‫قتتم بتعريتتف الصتتنف ‪ ()Cylindre‬الشتتتق متتن التتذي قبلتته. النشتت لهتتذا الصتتنف الجديتتد يتضتتمن برامتتتين ‪ rayon‬و‬ ‫‪ .hauteur‬أضتف الستلوب ‪ ()volume‬التذي ستيقوم بإرجتاع حجتم الستطوانة )تتذكي : حجتم الستطوانة =‬ ‫مساحة القطع × الرتفاع( .‬ ‫ملثال استخدام لهذا الصنف :‬
‫)7 ,5(‪>>> cyl = Cylindre‬‬ ‫))(‪>>> print(cyl.surface‬‬ ‫45.87‬ ‫))(‪>>> print(cyl.volume‬‬ ‫87.945‬

‫21.6 أكمل التمرين السابق بإضافة صنف جديد ‪،()Cone‬تت سوف يشتق هذه التترة متتن الصتتنف ‪ ،()Cylindre‬والنشتت‬ ‫يتضمن أضتا برامتتين ‪ rayon‬و ‪ .hauteur‬هتذا الصتنف الجديتد لتديه أستلوبه ‪ ،()volume‬والتذي ستيقوم‬ ‫بإرجاع حجم الخرو ط )تذكر حجم الخرو ط = حجم السطوانة القابلة مقسومة على 3(.‬ ‫ملثال لستخدام لهذا الصنف :‬
‫)7,5(‪>>> co = Cone‬‬ ‫))(‪>>> print(co.volume‬‬ ‫62.381‬

‫302‬

‫وظحدات تحتوي على مكتبات الصناف‬

‫21.7 عرف الصنف ‪ ()JeuDeCartes‬الذي يسمح بتملثيتتل الكائنتتات التتت ستتلوكها مشتتابه لستتلو،ك لعبتتة ورق حقيقيتتة.‬ ‫الصنف يجب عليه أن يحتوي على القل على أربعة الساليب التالية :‬ ‫•أسلوب النش : إنشاء وملتتء قائمتتة ثتم 25 عنصتت، والتت كتل واحتد منهتتا مكتتون متن مصتفوفة مغلقتتة ) ‪ (tuple‬متن‬ ‫عددين صحيحي. هذه قائمتة الصتفوفة الغلقتتة )‪ (tuple‬تحتتوي علتتى خصتائص لكتل واحتدة متن 25 بطاقتتة. لكتل‬ ‫واحدة منها، يجب تخزين بشكل منفصل عدد صحيح يشي إلى قيمة )2، 3، 4، 5، 6، 7، 8، 9، 01، 11، 21، 31،‬ ‫41 ، الربعة الخية قيم جا،ك واللكة واللك والس(، والعدد الصحيح الخر يشي إلى لتتون الورقتتة )و هتتذا معنتتاه‬ ‫3،2،1،0 للقلب والاس وو النوادي وبستوني(.‬ ‫في هذه القائمة، العنص )2،11( معناه جا،ك النوادي، والقائمة يجب أن تكتمل بنوع :‬ ‫])2, 0(, )0,3(, )0,3(, )0,4(, ..... )3,21(, )3,31(, )3,41([‬ ‫•السلوب ‪ : ()nom_carte‬هتتذا الستتلوب يجتتب عليتته أن يقتتوم بإرجتتاع فتتي عشتتكل سلستتلة، بهتتا هويتتة البطاقتتة‬ ‫ويجتتتتتتب أن تكتتتتتتون مصتتتتتتفوفة مغلقتتتتتتة )‪ ( tuple‬لوصتتتتتتف البامتتتتتتت. علتتتتتتى ستتتتتتبيل الملثتتتتتتال، التعليمتتتتتتة :‬
‫3 ,41((‪ (((print(jeu.nom_carte‬يجب أن تعرض: ‪As de pique‬‬

‫•السلوب ‪ : ()battre‬كما يعلم الجميع، معناه خلتط الوراق. هتذا الستلوب ستوف يخلتط قائمتتة العناصتت التت‬ ‫تحتوي على الوراق، بغض النظر عن العدد .‬ ‫•السلوب ‪ : ()tirer‬عندما يتم استدعاء هذا السلوب، يتم سحب ورقة . الصفوفة الغلقة )‪ (tuple‬التتذي يحتتتوي‬ ‫على القيمة واللون يتم إرساله للبنامج الذي استدعاه. يتم دائما سحب ) إزالة من القائمتتة( أول ورقتتة فتتي القائمتتة.‬ ‫فإذا تم استدعاء هذا السلوب ولم يعد يوجد أوراق في القائمة، يجب إرسال الكائن الخاص ‪ None‬إلى البنامج‬ ‫الذي استدعاه.‬ ‫أملثلة استخدام للصنف ‪: ()JeuDeCartes‬‬
‫)(‪jeu = JeuDeCartes‬‬ ‫)(‪jeu.battre‬‬ ‫:)35(‪for n in range‬‬ ‫)(‪c = jeu.tirer‬‬ ‫:‪if c == None‬‬ ‫)'! ‪print('Terminé‬‬ ‫:‪else‬‬ ‫))‪print(jeu.nom_carte(c‬‬
‫#‬ ‫#‬ ‫#‬ ‫#‬ ‫#‬

‫تملثيل كائن‬ ‫خلط الوراق‬ ‫:صنع 25 ورقة‬ ‫ل توجد أي ورقة في القائمة‬ ‫قيمة ولون الورقة‬

‫الصناف والساليب والميراث‬

‫402‬

‫21.8 أكمل التمرين السابق : عرف لعبي ‪ A‬و ‪ .B‬قم بتملثيل ورقت لعب )واحد لكل لعب( وقم بخلطهتتا. ثتتم بمستتاعدة حلقتتة‬ ‫التكرار، اسحب 25 مرة ورقة لكل واحد من هذان اللعبان وقارن قيمتهما. إذا كانت الول الكب قيمة يتم إضافة نقطتتة‬ ‫للعب ‪ .A‬فإذا حدث العكتتس فيتتتم إضتتافة نقطتة لللعتتب ‪ .B‬فتتإذا كتانت القيمتتتان متعتتادلتي، يتتتم التترور إلتى الستتحب‬ ‫التالي. عند انتهاء الحلقة، أحسب نقا ط ‪ A‬و ‪ B‬لعرفة الفائز .‬ ‫21.9 اكتب سكريبت جديد يقوم باستداد كود التمرين 2.21 )الحساب الصفي( عن طريق استدعائه كوحدة. وعرف صتتنف‬ ‫بصنع حسابات مدخرات يضاف إليه بعض الفائدة بعد مرور الوقت. للتبستتيط، نحتتن نفتتتض أنتته يتتتم حستتاب فائتتدة‬ ‫‪،()CompteEpargne‬تت مشتتتقة متتن صتتنف ‪ ()CompteBancaire‬التتت تتتم استتتدعاؤها، والتتت تستتمح‬ ‫عشهرية.‬ ‫منش صنفك الجديد يجب عليه أن يهي فائدة عشهرية بالتقصي تساوي 3,0 %. وأسلوب ‪(changeTaux(valeur‬‬ ‫يسمح بتغيي معدل الفائدة .‬ ‫السلوب ‪ (capitalisation(nombreMois‬يجب أن:‬ ‫•يعرض عدد العشهر والفائدة الت يتم أخذها في الحساب .‬ ‫• يحسب الال التحصل عليه من خلل الفائدة والعشهر الت تم اختيارها .‬ ‫أملثلة استخدام هذا الصنف :‬
‫)006 ,'‪>>> c1 = CompteEpargne('Duvivier‬‬ ‫)053(‪>>> c1.depot‬‬ ‫)(‪>>> c1.affiche‬‬ ‫.‪Le solde du compte bancaire de Duvivier est de 950 euros‬‬ ‫)21(‪>>> c1.capitalisation‬‬ ‫.% 3.0 ‪Capitalisation sur 12 mois au taux mensuel de‬‬ ‫)(‪>>> c1.affiche‬‬ ‫.‪Le solde du compte bancaire de Duvivier est de 984.769981274 euros‬‬ ‫)5.(‪>>> c1.changeTaux‬‬ ‫)21(‪>>> c1.capitalisation‬‬ ‫.% 5.0 ‪Capitalisation sur 12 mois au taux mensuel de‬‬ ‫)(‪>>> c1.affiche‬‬ ‫.‪Le solde du compte bancaire de Duvivier est de 1045.50843891 euros‬‬

‫31‬
‫31الأصناف وواجهات المستخدم الرسوةمية‬
‫البمجة الشيئية هي مناسبة خاصة لتطوير التطبيقات مع واجهات الستخدم الرستتومية. مكتبتتات الصتتناف ملثتتل ‪ tkinter‬أو‬ ‫‪ wxPython‬توفر أساس ودجات واستعا جتدا، حيتتث نستتتطيع أن نكيتف إحتياجاتنتتا متن العشتتقاق. فتي هتذا الفصتل، ستوف‬ ‫نستخدم مرة أخرى مكتبة ‪ ، tkinter‬لكن سوف نطبتق الفتاهيم الوضتحة فتتي الصتفحات الستابقة، وسنستعى لتستليط الضتوء‬ ‫على مزايا البمجة الشيئية في برامجنا .‬

‫كود اللوانء : مشرلوع صغير مغلف بشكل جيد‬ ‫سنبدأ مع مشوع صغي مستوحى من الدورات في مجال اللكتونيات. التطبيق الذي سنصفه أدناه يمكنه العلثور بستتعة علتتى‬ ‫رمز 3 ألوان الطابقة للمقاوم الكهربائي لقيمة محددة جدا.‬ ‫للتذكي، إن وظيفة القاوم هي مقاومة )اعتاض( قليل أو كلثي من تدفق التيار الكهربائي. القاوم يظهر بشتتكل ملمتتوس فتتي عشتتكل‬ ‫أنبوبي من أجزاء صغية بها ثلثة خطو ط من اللوان )عادة 3 (. هذه الخطو ط تشي إلى القيمة العددية للمقاومة، اعتمادا على‬ ‫التالي :‬ ‫أسود = 0 ; بن = 1 ; أحمر = 2 ; برتقالي = 3 ; أصفر = 4 ;‬ ‫أخض = 5 ; أزرق = 6 ; بنفسجي = 7 ; رمادي = 8 ; أبيض = 9.‬ ‫القاومة موجهة بحيث يتتم وضتتع الخطتو ط )الشتائح( اللونتتة علتتى اليستتار. قيمتتة القاومتة - تعتترف بتالوم )‪ – (Ω‬يتتم قتتراءة‬ ‫الخطو ط )الشطة( من اليسار : أول خطي يشيان إلى أول رقمي من القيمة الرقمية. ثم يجب إلحتاق هتتذين الرقميتت بعتدد متن‬ ‫الصفار مساو للخط اللثالث .‬ ‫ٍ‬ ‫ملثال : اللوان من اليسار هي : أصفر وبنفسجي وأخض.‬

‫الصناف وواجهات المستخدم الرسومية‬

‫602‬ ‫قيمة القاوم هي 0000074 ‪ ،Ω‬أو 0074 ‪ ،kΩ‬أو 7,4 ‪. MΩ‬‬

‫ٍ‬ ‫هذا النظام ل يسمح بتوضيح القيمة الرقمية إل مع رقمي فقط. ومتتع ذلتتك هتتذا منتشتت علتتى نظتتاق واستتع. وهتتو كتتاف بالنستتبة‬ ‫لعظم التطبيقات "العادية" )الراديو، التلفاز، إلخ( .‬ ‫مواصفات برنامجنا‬ ‫يجب علتتى برنامجنتتا أن يقتوم بعتترض نافتذة تحتتتوي علتتى رستم للمقتتاوم،‬ ‫ويجب على الستخدم إدختال القيمتتة العدديتتة للمقتاوم ثتم الضتغط علتتى >‬ ‫‪ 1e11 : 43# self.signaleErreur() # ‫المدخلت خافطئة أو خارجة‬ 44# else: 45# li =[0]*3 # ‫قائمة من 3 رموز لعرض‬ 46# logv = int(log10(v)) # ‫الجزء الصحيح من الخوارزمية‬ 47# ordgr = 10**logv # ‫ترتيب الحجم‬ 48# # ‫: استخراج أول أرقام هامة‬ 49# li[0] = int(v/ordgr) # ‫جزء صحيح‬ 50# decim = v/ordgr - li[0] # ‫جزء ظحقيقي‬ 51# # ‫: استخراج أول أرقام هامة‬ 52# li[1] = int(decim*10 +.5) # +.5 ‫لتقريب يبشكل صحيح‬ 53# # ‫:عدد الصفار المرتبطة يبالرقمين الكبيرين‬ 54# li[2] = logv -1 55# # ‫:تلوين الخطوط الثلثة‬ 56# for n in range(3): 57# self.can.itemconfigure(self.ligne[n], fill =self.cc[li[n]]) 58# 59# def signaleErreur(self): 60# self.entree.configure(bg ='red') # ‫تلوين خلفية‬ 61# self.root.after(1000, self.videEntree) # ‫امسحه يبعد 1 ثانية‬ ُ 62# 63# def videEntree(self): 64# self.entree.configure(bg ='white') # ‫استعد الخلفي البيضاء‬ 65# self.entree.delete(0, len(self.v1ch)) # ‫ازالة الحروف المكتويبة‬ 66# 67# # ‫: البرنامج الرئيسي‬ 68# if __name__ == '__main__': 69# from tkinter import * 70# from math import log10 # 10 ‫خوارزمية يبأساس‬ 71# f = Application() # ‫تمثيل كائن التطبيق‬

‫الصناف وواجهات المستخدم الرسومية‬

‫802‬ ‫تعليقات‬

‫• السطر الول : الصنف تم تعريفه من صنف مستقل )أي أنه ل يستمد من أي صنف أصتتل، لكتتن فقتتط الكتتائن، وهتتو ستتلف‬ ‫جميع الصناف الخرى( .‬ ‫•الستتطر متتن 2 إلتتى 41 : منشتت صتتنف اللثيتتل للويتتدجات الطلوبتتة : مستتاحة رستتوم، ملصتتق )‪ (Label‬وأزرار. ولتحستتي‬ ‫إمكانية قراءة البنامج، وضعنا ملثيل لللوحة )مع رسم للمقاوم( في أستتلوب منفصتتل: ‪.()dessineResistance‬‬ ‫يرجى ملحظة أنه للحصول على كود أصغر حجما، نحن ل نقوم بحفظ الزرار واللصتتقات )‪ (Label‬فتتي متغيتتات )كمتتا‬ ‫شحنا سابقا في الصفحة 401(، و ذلك لننا ل نريد صنع مرجتتع لهتتا فتتي أمتتاكن مختلفتتة متن البنامتج. نحتن استتتحدمنا‬ ‫لماكن الويدجات في النافذة السلوب ‪ ()grid‬الذي وصفناه في الصفحة 101.‬ ‫•السطر من 51 إلى 71 : يتم تخزين كود اللوان في قائمة بسيطة.‬ ‫•السطر 81 : التعليمة الخية لنش بداية البنامج. فإذا كنت تفضل بدء البنامج بشكل مستقل عن صنعه، يجب عليك‬ ‫فتتي هتتذه الحالتتة حتتذف هتتذا الستتطر، ونستتتدعي ‪ ()mainloop‬فتتي الستتتوى الرئيستت للبنامتتج، بإضتتافة التعليمتتة:‬ ‫‪ ()f.root.mainloop‬في السطر 17.‬

‫•السطر 02 إلى 03 : رسم القاوم يتكون من خط وأول شيحة رمادية فاتحتتة، لجستتم القتتاوم وابنيتته. وثلثتتة مستتتطيلت‬ ‫أخرى كشائح ملونة وتتغي ألوانه اعتمادا على مدخلت الستخدم. هذه الشائح تكون لونها أسود في البداية ومرجعهتتم‬ ‫في قائمة ‪.self.ligne‬‬ ‫•السطر من 23 إلى 35 : هذه الستطر تحتتتوي علتتى أستاس وظتائف البنامتتج. متدخلت الستتتخدم يتتتم قبولهتا فتتي عشتكل‬ ‫سلسل نصية. في السطر 63 ، فإننا نحاول تحويل هذه السلسلة إلى قيمة رقمية من نوع حقيقي. فإذا فشل التحويل، يتم‬ ‫تخزين الخطأ. فإذا تحول إلى قيمة رقمية، نتأكد من أنه داخل النطاق السموح بتته )متن 01 ‪ Ω‬إلتتى 11^01 ‪ .(Ω‬فتتإذا تتم‬ ‫الكشف عن خطأ، فإننا ننبه الستخدم على أن مدخلته لها خطأ عن طريق تلوين حقل الدختتال بلتتون أحمتتر، ويتتتم إفتتراغ‬ ‫محتواياته )السطر من 55 إلى 16(.‬ ‫•السطر 54 و 64 : إن الرياضيات أتت لنجدتنا لستخراج القيمة الرقمية من ترتيبها الكبي )هذا معناه، من أقتترب 01 أس‬ ‫)قوة( (. يرجي الرجوع إلى كتاب رياضيات لزيد من التوضيح عن اللوغاريتمات .‬ ‫•السطر : 74-84 : بمجرد معرفة نظام القيمة السية، سيكون من السهل نسبيا إستخراج العدد التتذي تتتم التعامتتل متتع أول‬ ‫وبهذا فالرقم الدخل )4( و الذي ستكون القيمة السية له )01^4(. ولستخراج رقمه الول العتب، يجب قسمته علتتى 01^‬ ‫ُ َ‬ ‫4 )00001( و الحتفاظ فقط بالجزء الصحيح من النتيجة )3(.‬ ‫منلتي معتتتبتي. فملثل، نفتتض أن القيمتتة التتت تتم إدخالهتتا هتتي 78513 . اللوغتتاريتم لهتذا الرقتم ستيكون 88005،4...‬ ‫ً‬

‫902‬

‫كود اللوان : مشروع صغير مغلف يبشكل جيد‬

‫نتيجة عملية القسمة الت قمنا بها في الفقرة السابقة هي كالتالي: سوف نقوم بأخذ الجزء‬

‫•السطر من 94 إلى 15 :‬

‫الكسي للعدد في السطر 94 و الذي هو 7861،0 في ملثالنا، فإذا ضبناه في عشة، ستكون هذه النتيجة الجديتتدة تحمتتل‬ ‫جزءاً صحيحاً واحدًا )والذي هو في ملثالنا ثاني منلة معتبة وقيمتها واحد(.‬ ‫• يمكننا يسهولة أن نستخرج الرقم الخي، لكتن بمتتا أن هتتذا الخيتت، يجتتب علينتتا أن نقتوم بتقريبته بشتتكل صتتحيح. للقيتام‬ ‫بذلك، يجب أن نقوم ببساطة بإضافة 5,0 إلى ناتتتج الضتتب فتتي 01 ليتتتم تقريبتته بشتتكل صتتحيح، وذلتتك قبتتل استتتخراج‬ ‫القيمتتة النهائيتتة. وفتي ملثالنتا هتذا : إن النتيجتة التت نحصتل عليهتا هتتي 786،1 + 5،0 = 781.2، و بالتتالي فتتإن العتدد‬ ‫الصحيح للنتيجة )2( هي القيمة القربة الت نبحث عنها.‬ ‫•السطر 35 : عدد الصفار التت ترتبتتط برقميتت مهميتت الوافقتتة لحستتاب ترتيتتب الحجتم. يمكنتتك ببستاطة إزالتتة وحتدة فتتي‬ ‫الخوارزمية.‬ ‫•الستتطر 65 : لتعييتت لتتون جديتتد لكتتائن يمكتتن رستتمه علتتى اللوحتتة، نستتتخدم الستتلوب ‪ .()itemconfigure‬ستتوف‬ ‫‪ grâce à aux‬بملؤشات اللثلثة 3[‪ [li[1]، li[2] ، li‬الت تحتوي على ثلثة أرقام.‬ ‫31.1 قم بتعديل السكريبت بالعلى بحيث يصبح صورة الخلفية أزرق فاتتتح )‪ ،(light blue‬ويصتتبح جستتم القاومتتة لتتونه‬ ‫بيج )يشبه اللون البن - ‪ ،(beige‬والسلك القاومة يصبح أنحف، وشائح اللوان الت تدل على القيمة تصبح أكب .‬ ‫31.2 عدل السكريبت في العلى بحيث تصبح صورة الرسومة أكب مرتان .‬ ‫31.3 عد السكريبت أعله بحيث يصبح من المكن إدخال قيمة القاوم الت ما بي 1 و 01 ‪Ω. P‬ولهذه القيم الشبجة الولى‬ ‫اللونة يجب أن تبقى سوداء، والشيحتان التبقيتان يشيان القيم بت ‪ Ω‬واللثانية بت ‪.Ω‬‬ ‫31.4 عدل السكريبت أعله بحيث أن الزر > ‪ ‬ ‫‪ >> from oscillo import‬‬ ‫)(‪>>> g1 = OscilloGraphe‬‬ ‫)(‪>>> g1.pack‬‬

‫بعد استدعاء صنف الوحدة ‪ ،oscillo‬قمنا بتملثيل كائن أول 1‪ ،g‬للصنف ‪.()OscilloGraphe‬‬ ‫بما أننا لم نضع أي برامت، الكائن لديه حجمه الفتاض، تم تعريفه في منش الصنف. لحظ أننا لتم نقتم بتعريتتف أول نافتتذة‬ ‫الصل لكي نضع بها الويدجات. ‪ tkinter‬يسامح هذا النسيان وهو وفره لنا تلقائيا !‬
‫)052=‪>>> g2 = OscilloGraphe(haut=200, larg‬‬ ‫)(‪>>> g2.pack‬‬ ‫)(‪>>> g2.traceCourbe‬‬

‫لهذه التعليمات، صنعنا ودجة ثاني من نفس الصنف، وهذه الرة مع تحديد أبعادها )الطول والعرض، ل يهم التتيب(.‬ ‫ثم قمنا بتفعيل السلوب ‪ ()traceCourbe‬الرتبط بهذا الودجة. لننا لم نوفر لها أي برامت، ويظهر الش ط التتوجب التتذي‬ ‫يتوافق مع القيم الفتاضية للبامتات ‪ A‬و ‪ f‬و ‪. φ‬‬
‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫>>>‬ ‫)022=‪g3 = OscilloGraphe(larg‬‬ ‫)‪g3.configure(bg='white', bd=3, relief=SUNKEN‬‬ ‫)5=‪g3.pack(padx=5,pady‬‬ ‫)'‪g3.traceCourbe(phase=1.57, coul='purple‬‬ ‫)'‪g3.traceCourbe(phase=3.14, coul='dark green‬‬

‫الصناف وواجهات المستخدم الرسومية‬

‫612‬

‫لفهم تكوين الودجة اللثاللثتة، يجتب أن تتتذكر الصتنف ‪ ()OscilloGraphe‬تتم صتنعه باعشتتقاق متن الصتنف ‪.()Canvas‬‬ ‫وهو يرث جميع خصائصه، والذي يتيح لنا اختيار لون الخلفية، والحتتدود ... إلتتخ، باستتتخدام نفتتس البامتتتات التتت وضتتعناها‬ ‫عندما كونا اللوحة.‬ ‫ثم قمنا بعرض قطعتتي متعتاقبتي، وذلتك عتن طريتق استتدعاء الستلوب ‪،()traceCourbe‬ت مرتيت، والتت نقتدم البامتتات‬ ‫للتطور واللون.‬

‫تمرين‬
‫31.8 قم بصنع ودجة رابعة، بقياس 004 × 003، بلون خلفية أصفر، وقم بإظهار العديتتد متتن النحنيتتات الوافقتتة لتتددات‬ ‫مختلفة.‬

‫712‬

‫مخطط الذيبذيبات : ودجة مخصصة‬

‫لقد حان الوقت لتحليل هيكل الصنف الذي سمحنا له بتملثيل هذه الويدجات. ستتوف نقتتوم الن بحفتتظ هتتذا الصتتنف فتتي وحتتدة‬ ‫تدعى ‪) oscillo.py‬انظر للصفحة 412(.‬ ‫المواصفات‬ ‫نحن نريد الن تعريف صنف لودجة جديدة، قادر على إظهار تلقائيا رسوم بيانية إطالة/وقت متوافقة مع حركات الذبذبات.‬ ‫يجب على هذه الودجة أن تكون قادرة على صنع ملثيل في أي وقت. ويجب عليها أن تظهر محتتورين ديكتتارتي ‪ X‬و ‪ Y‬متتع أستتهم.‬ ‫ويملثل الحور ‪ X‬مرور الوقت باللثانية الواحدة وسوف تكون مجهزة بت 8 فتات.‬ ‫و سوف يتم ربط السلوب ‪ ()traceCourbe‬بهذه الودجة. وهذا قتد يكتون ستبب الرستوم البيانيتتة إستتطالة/الزمتن لحركتتة‬ ‫الهتازية، والت يجب علينا تقديم التواتر )هزة تتواح ما بي 52.0 إلى 01 هرتز( ومرحلة )ما بيتت 0 و ‪ 2π‬راديتتان( والستتعة‬ ‫)بي 1 إلى 01 : نطاق تعسفي(.‬ ‫التطبيق‬ ‫•السطر 4 : تم صنع الصنف ‪ ()OscilloGraphe‬بالنشقاق من الصنف ‪ .()Canvas‬وهو يرث جميع خصائصه :‬ ‫يمكن تكوين كائنات لهذا الصنف الجديد باستخدام العديد من الخيارات التاحة بالفعل للصنف ‪.()Canvas‬‬ ‫•السطر 6 : إن السلوب النش يستخدم ثلثة برامتات، وكلهتتا اختياريتتة، لن لكتتل واحتتدة منهتتا قيمتتة افتاضتتية. يستتتخدم‬ ‫أدناه(. البامتا ‪ larg‬و ‪) haut‬للعرض‬ ‫البامت ‪ boss‬لتلقي العشارة فقط لرجع نافذة )انظر الملثلة‬ ‫والرتفاع( لتعيي قيم لخيارات ‪ width‬و ‪ height‬للوحة الصل، في لحظة تملثيله‬ ‫•لقد قمنا بتفعيل النش للصنف ‪ ()Canvas‬فتتي الستتطر 9، وقمنتتا بإضتافة خيتارين لتته فتتي الستتطر 01. لحتتظ أننتا كنتتا‬ ‫نستطيع أن نختص هذان السطران في سطر واحد وهو :‬
‫.)‪Canvas.__init__(self, width=larg, height=haut‬‬

‫و كما شحنا )انظر إلى الصفحة 891(، يجب علينا تمرير للمنش مرجع اللثيل )‪ (self‬كبامت أول.‬ ‫•السطر 11 : إنه من الضوري حفظ البامتات ‪ larg‬و ‪ haut‬في متغي ملثيل، لننا يجل علينا الوصول إليه أيضا في‬ ‫السلوب ‪.()traceCourbe‬‬ ‫•السطران 31 و 41 : لرسم محاور ‪ X‬و ‪ ،Y‬ستوف نستتخدم البامتتات ‪ larg‬و ‪ ،haut‬ويتتم وضتع هتذه الحتاول تلقائيتا‬ ‫على البعاد. يستخدم الخيار ‪ arrow=LAST‬لعرض سهم صغي في نهاية كل خط .‬ ‫•السطر من 61 إلى 91 : لرسم مقياس أفقي، نبدأ من خفض 52 بكسل من عرض التاح، لكي يتم تشكيل مساحات فتتي كتتل‬ ‫الجانبي. ثم نقسمها إلى 8 أقسام، وهو تصور عشكل عمودي للثمانية خطو ط صغية .‬

‫الصناف وواجهات المستخدم الرسومية‬

‫812‬

‫•السطر 12 : يمكتن استتدعاء الستلوب ‪ ()traceCourbe‬متع أربعتتة برامتتتات. كتتل واحتد منهتتا يمكتن حتذفه، لن كتتل‬ ‫البامتات لديها قيم افتاضية. ويمكن توفي البامتات في أي ترتيب ، كما شحنا في الصفحة 97.‬ ‫•الستتطر متتن 32 إلتتى 13 : لرستتم منحنتت، التغيتت ‪ t‬يتتتم القيتتم متتن 0 إلتتى 0001، ويحستتب كتتل متترة إستتتطالة ‪ e‬القابلتتة،‬

‫بمساعدة الصيغة النظرية )السطر 62(. تم العلثور على أزواج القيم ‪ t‬و ‪ e‬وتم تحجيمهتتم وتحتتويلهم إلتتى إحتتداثيات ‪x, y‬‬
‫السطر 72 و 82، ثم تراكمت في قائمة ‪.curve‬‬ ‫•الستطر 03 و 13 : يرستم الستتلوب ‪ ()create_line‬النحنتت القابتتل فتتي عمليتتة واحتدة، ويقتوم بإرجتتاع رقتم ترتيتتب‬ ‫للكائن الجديد الذي تم تملثيله في اللوحة )و هتذا رقتم التتتتيب ستوف يستتمح لنتتا بالوصتتول إليتته بعتتد ذلتتك : لستتحه، علتتى‬ ‫سبيل اللثال(. الخيار 1= ‪ smooth‬يحسن مظهر النهائي بتجانسه .‬

‫تمارين‬
‫31.9 عدل السكريبت بحيث يصتتبح الحتتور هتتو الرجتتع العمتتودي يضتم إليتته أيضتتا مقيتتاس، متتع 5 أجتتزاء ‪et d’autre de‬‬ ‫‪.l’origine‬‬ ‫31.01 ملثل ودجات الصنف ‪ ()Canvas‬الذي يشتق منه، ودجة الهاص بك بمكنه دمج ملؤشات نصتية. ببستاطة استتتخدم‬ ‫السلوب )( ‪ .()create_text‬هذا السلوب ينتطر على القل ثلثة برامتات. الحداثيات ‪ x , y‬لكان الذي تريد‬ ‫أن تظهر نصك فيه ثم النص الذي تريد إظهاره بطبيعة الحال. ويمكن تمرير برامتتتات أخترى بشتتكل خيتتارات، لتحديتد‬ ‫علتتتى ستتتبييل اللثتتتال الختتتط والحجتتتم. لنتتتى كيتتتف يعمتتتل هتتتذا، أضتتتف ملؤقتتتتا الستتتطر التتتتالي فتتتي منشتتت الصتتتنف‬ ‫‪ ،()OscilloGraphe‬ثم قم بإعادة تشغيل السكريبت :‬
‫)‪self.create_text(130, 30, text = "Essai", anchor =CENTER‬‬

‫912‬

‫مخطط الذيبذيبات : ودجة مخصصة‬

‫استخدم هذا السلوب لضافة إلى ودجة اللؤشات التالية القصوى لحاور الرجع: ‪) e‬للستتتطالة( علتتى طتتور محتتور‬ ‫العمودي، و ‪) t‬للوقت أو الزمن( على طول الحور الفقي. قد تبدو النتيجة على الشكل اليس .‬ ‫لتأكد من أن هذه الشطات لتن تكتتون مرئيتتة أكتتث متن اللزم، يمكنتتك تلتتوين ملمحهتتا بتاللون الرمتتادي )الخيتتار = ‪fill‬‬ ‫31.11 ومرة أخرى، يمكنك إكمال الودجة الخاصة بك بإظهتتار عشتبكة الرجعتتو التتت هتتي شتتائط بستتيطة علتتى طتتول الحتتاور،‬ ‫ِ‬ ‫‪ ،(’’grey‬كما في الشكل بالعلى.‬ ‫31.21 أكمل الويدجت الخاص بك بإظهار الرقام.‬ ‫المؤشرات ، لودجة مركبة‬ ‫في التمرين السابق، قمت بصنع نوع جديد من الويدجات الت قمت بحفظها في وحدة ‪ .oscillo.py‬حافظ على هذه الوحدة‬ ‫سوف تنضم قريبا لشوع أكب تعقيدا.‬ ‫في الوقت الراهن، سوف تقوم بصنع ودجة أخرى، وهذه الرة أكث تفاعل. ستكون نوع من أنواع لوحتتات التحكتتم تحتتتوي علتتى‬ ‫ثلثة متلجات وخانة اختيار. ملثل سابقتها، يهدف هذا الودجة لعادة استخدامه في تطبيق تجميعي .‬

‫عرض ودجة المقياس )‪(Scale‬‬

‫دعونا نبدأ أول متن خلل إستكشتتاف ودجتتة القاعتتدة، والتت لتتم نستتتخدمها حتتت الن : الودجتتة ‪ Scale‬يشتتبه التتتحلق التتذي‬ ‫يتحلق أمام مقياس. يسمح للمستخدم اختيار سعة القيمة بأي برامت.‬ ‫السكريبت الضغي بالسفل يوضح لك كيف وضع برامت واستخدامها في نافذة :‬
‫* ‪from tkinter import‬‬ ‫:)‪def updateLabel(x‬‬ ‫))‪lab.configure(text='Valeur actuelle = ' + str(x‬‬ ‫)(‪root = Tk‬‬ ‫,': ‪Scale(root, length=250, orient=HORIZONTAL, label ='Réglage‬‬ ‫,02= ‪troughcolor ='dark grey', sliderlength‬‬ ‫,52= ‪showvalue =0, from_=-25, to=125, tickinterval‬‬ ‫)(‪command=updateLabel).pack‬‬

‫الصناف وواجهات المستخدم الرسومية‬
‫)‪lab = Label(root‬‬ ‫)(‪lab.pack‬‬ ‫)(‪root.mainloop‬‬

‫022‬

‫هذه السطر ل تتطلب الكلثي من التعليق.‬ ‫يمكنتتك إنشتتاء ودجتتات ‪ Scale‬بتتأي حجتتم كتتان )الخيتتار ‪،(length‬تت فتتي إتجتتاه أفقتتي )كمتتافي ملثالنتتا( أو عمتتودي )الخيتتار‬ ‫‪.(orient = VERTICAL‬‬

‫الخيار ‪ ) _from‬انتبه : ل تنس الرمتتز "تحتتت الستتطر"، لن هتتذا إلزامتتي لكتتي ل يتتتم الخلتتط بيتت هتتذه الكلمتتة وكلمتتة ‪from‬‬
‫و الدالة تحدد في خيار ‪ command‬بإنه يستدعي تلقائيا في كل متترة عنتتدما ستتم وضتتع اللؤشتت، والكتتان الحتتالي للملؤشتت‬ ‫حسب القيار يتم تمريره كبامت. لذا فهو من السهل جدا استخدام هذه القيمتتة لتعييتت أي معالجتتة. انظتتر علتتى ستبيل اللثتتال إلتتى‬ ‫البامت ‪ x‬لدالة ‪ ،()updateLabel‬في ملثالنا.‬ ‫الودجة ‪ Scale‬هي واجهة بديهية للغاية وتوفر للمستخدمي برامجك العديد من العدادات. سوف نقوم الن بدمج عتتدة نستتخ‬ ‫منها في صنف ودجة جديد : لوحة تحكم لختيتتار التتتدد، والحركتتة والطتتور لحركتتات الذبتتذبات، ثتتم ستتنقوم بعتترض ريتتم بيتتاني‬ ‫إستطالة/الوقت بمساعدة ودجة ‪ oscilloGraphe‬الذي درسناه في الصفحات السابقة .‬ ‫بناء لوحة تحكم بثليثة متزلجات/مؤشرات‬ ‫ملثل سابقتها، السكريبت الوصوف بالسفل يجب أن يتم حفظه في وحده، والذي يجب أن يتتتم تستتميته بتتت ‪.curseurs.py‬‬ ‫الصناف الت قمت بحفظها سيتم إعادة استخدامها )بالستدعاء( في تطبيق مركب والتذي ستتوف نتحتدث عنتته فتتي وقتت لحتتق.‬ ‫ولحظوا أننا تستطيع تقصي الكوج بالسفل لطرق مختلفة )سوف نتحدث عنها لحقا . نحن لم نحسن الكود، لن هتتذا يتطلتب‬
‫17‬

‫الحجوزة!( و ‪ to‬لضبط النطاق. يتم تعريف الفتة بي الرقام في الخيار ‪ ،tickinterval‬إلخ.‬

‫دمج مفهومات إضتافية )العبتارة ‪ ،( lambda‬والتت نفصتل أن نتجنبهتا فتي التوقت الحتالي. أنتت تعتترف بالفعتتل أن أستطر الكتتود‬ ‫الوجود في أسفل السكريبت لختبار عملها. سوف تحصل على نافذة ملثل هذه :‬

‫* ‪1# from tkinter import‬‬ ‫‪2# from math import pi‬‬

‫17يكنك ب اليطبع حفظ العديد من الصن اف ف نفس الوحدة .‬

221

‫المؤشرات ، ودجة مركبة‬

3# 4# class ChoixVibra(Frame): 5# """Curseurs pour choisir fréquence, phase & amplitude d'une vibration""" 6# def __init__(self, boss =None, coul ='red'): 7# Frame.__init__(self) # ‫منشئ الصنف الصل‬ 8# # ‫: تهيئة يبعض سمات المثيل‬ 9# self.freq, self.phase, self.ampl, self.coul = 0, 0, 0, coul 10# # ‫: متغيرة ظحالة خانة الختيار‬ 11# self.chk = IntVar() # ' ‫ 'كائن-متغير‬tkinter 12# Checkbutton(self, text='Afficher', variable=self.chk, 13# fg = self.coul, command = self.setCurve).pack(side=LEFT) 14# # ‫: تعريف ثلثة ويدجات من نوع متزلجات‬ 15# Scale(self, length=150, orient=HORIZONTAL, sliderlength =25, 16# label ='Fréquence (Hz) :', from_=1., to=9., tickinterval =2, 17# resolution =0.25, 18# showvalue =0, command = self.setFrequency).pack(side=LEFT) 19# Scale(self, length=150, orient=HORIZONTAL, sliderlength =15, 20# label ='Phase (degrés) :', from_=-180, to=180, tickinterval =90, 21# showvalue =0, command = self.setPhase).pack(side=LEFT) 22# Scale(self, length=150, orient=HORIZONTAL, sliderlength =25, 23# label ='Amplitude :', from_=1, to=9, tickinterval =2, 24# showvalue =0, command = self.setAmplitude).pack(side=LEFT) 25# 26# def setCurve(self): 27# self.event_generate('') 28# 29# def setFrequency(self, f): 30# self.freq = float(f) 31# self.event_generate('') 32# 33# def setPhase(self, p): 34# pp =float(p) 35# self.phase = pp*2*pi/360 # ‫تحويل الدرجة -< راديان‬ 36# self.event_generate('') 37# 38# def setAmplitude(self, a): 39# self.ampl = float(a) 40# self.event_generate('') 41# 42# #### ‫### : كود لتجريبة الصنف‬ 43# 44# if __name__ == '__main__': 45# def afficherTout(event=None): 46# lab.configure(text = '{0} - {1} - {2} - {3}'.\ 47# format(fra.chk.get(), fra.freq, fra.phase, fra.ampl)) 48# root = Tk() 49# fra = ChoixVibra(root,'navy') 50# fra.pack(side =TOP) 51# lab = Label(root, text ='test') 52# lab.pack() 53# root.bind('', afficherTout) 54# root.mainloop()

‫هذه لوحة التحكم تسمح للمستحدمي بضبط القيم البامتات العينة )تتتردد وطتتور وستتعة(، ومتن ثتم يمكتن استتخدامه لعتترض‬ . ‫)( الذي قمنا بصنعه سابقا، كما وضحنا في التطبيق‬OscilloGraphe ‫رسم بياني إطالة/الزمن في ودجة للصنف‬

‫الصناف وواجهات المستخدم الرسومية‬

‫222‬ ‫تعليقات‬

‫•السطر 6 : يستخدم السلوب النش برامت الختياري ‪ .coul‬هتتذا البامتتت يستتمح باختيتتار لتتون غرافيتتك للوحتتة التحكتتم‬ ‫للودجة. البامت ‪ boss‬لتلقي مرجع النافذة الصل المكنة )سوف نراها لحقا(.‬ ‫•السطر 7 : تفعيل منش الصنف الصل )لوراثة وظائفه(.‬ ‫•الستتطر 9 : بيتتان ببعتتض التغيتتات اللثيتتل. وستتيتم تحديتتد قيمهتتم بواستتطة الستتاليب فتتي الستتطر 92 إلتتى 94 )معالجتتة‬ ‫الحداث(.‬ ‫•السطر 11 : هذه التعليمة تقوم بتملثيتتل كتتائن متتن صتتنف ‪،()IntVar‬تت والتذي هتتو جتتزء متتن وحتتدة ‪ tkinter‬وهتتو مشتتابه‬ ‫للصناف ‪ ()DoubleVar()، StringVar‬و ‪ .()BooleanVar‬كل هذه الصناف تسمح بتعريف متغيتتات‬ ‫‪ ،tkinter‬والت هي في الواقع كائنات، لكنها تتصف ملثل التغيات في ويدجات ‪) tkinter‬انظر لحقا(. وبالتالي الرجع‬ ‫في ‪ self.chk‬يحتوي على ما يعادل متغي من نوع صحيح، في عشكل مستخدم من قبل ‪ .tkinter‬للوصتتول إلتتى قمتتته‬ ‫من بيلثتون، يجتتب استتخدام الستاليب الخاصتتة بهتذا الكتتائن : الستلوب ‪ ()set‬يستتمح بتعييتت قيمتتة، والستتلوب ‪()get‬‬ ‫يسمح بإستجاعها )سوف نراه في السطر 74(.‬

‫•السطر 21 : الخيار ‪ variable‬لتغي ‪ checkbutton‬يقوم بربط التغي ‪ tkinter‬الذي قمنا بتعريفه في السطر‬ ‫الستتابق. نحتتن ل يمكننتتا أن نقتتوم برمجتتع مباشتت لتغيتت عتتادي فتتي تعريتتق ودجتتة ‪ ،tkinter‬لن ‪ tkinter‬كتتتب بلغتتة ل‬ ‫تستخدم نفس إتفاقيات بيلثتون لتنستيق التغيتات. الكائنتات تتم بنائهتا متن أصتناف متغيتات ‪ tkinter‬ضتورية لضتمان‬ ‫الواجهة.‬ ‫•السطر 31 : الخيار ‪ command‬يشي إلى أسلوب الذي يجب على النظام استدعاءه عندما يقون الستتتخدم بتتالنقر متتن‬ ‫الفأرة على خانة الختيار.‬ ‫•السطر من 41 إلى 42 : هذه السطر تقوم بتعريف ثلثة ويدجات متلجتات، فتي ثلثتة تعليمتتات متشتابهة. وستيكون متن‬ ‫الفضل إختصار هذه تعليمات إلى واحدة فقط، يتم تكرارها ثلثة مرات بمساعدة حلقة. وهذا يتطلب مفهوم لم أقم بشحه‬ ‫بعد )الدالت أو العبارات ‪ ،(lambda‬وتعريف معالج الحداث الذي يتم ربطه بهذه الويدجات ستصبح أكث تعقيتتدا. حتتت‬ ‫هذا الوقت سوف تبقى التعليمات منفصلة : سنحاول تحسينها لحقا.‬ ‫•السطر من 62 إلى 04 : الويدجات الربعة تم تعريفهم في السطر سابقة لدى كل واحدة منها خيار ‪ .command‬لكل‬ ‫واحدة منها، أسلوب استدعاء الخيار ‪ command‬مختلتتف : مربتتع الختيتار يفعتتل الستلوب ‪،()setCurve‬ت فيقتتوم‬ ‫التلج الول بتنشيط السلوب ‪ ،()setFrequency‬والتلج اللثاني يفعل الستتلوب ‪ ،()setPhase‬وأمتتا اللثتتالث‬ ‫فيقعل الستتلوب ‪ .()setAmplitude‬لحتتظ أن الخيتتار ‪ command‬لودجتتات ‪ Scale‬تمتترر برامتتت للستتلوب‬

‫322‬

‫المؤشرات ، ودجة مركبة‬

‫الرتبتتتط )موضتتتع الحتتتالي للمتلتتتج(، لتتتذا فقتتتط الخيتتتار ‪ command‬ل يقتتتوم بتمريتتتر شتتتء فتتتي حالتتتة الودجتتتة‬ ‫‪.Checkbutton‬‬ ‫هذه الساليب الربعة )و الت هي معالجة الحداث الت تم إنشاؤها بواسطة خانة و 3 متلجات( وتسبب كتل واحتدة منهتتا‬
‫27‬
‫‪a‬‬

‫مهمة عنص جديد ، وذلك باستدعاء السلوب ‪.()event_generate‬‬ ‫عندما يتم استدعاء هذا السلوب، يقوم بيلثون بإرجاع لنظام التشغيل نفتتس رستالة-العناصتت التت ستتوف تظهتر إذا ضتتغظ‬
‫‪a‬‬

‫الستخدم على >‪ ‪ ‪ ‪ ‪ ‪. ‪ enfoncement‬الضغطة ‪ 1-‪ ‬

‫242‬

‫فتتتتتتتي هتتتتتتتذه الحالتتتتتتتة، فتتتتتتتإنه تتتتتتتتم ربتتتتتتتط ثلثتتتتتتتة معرفتتتتتتتات أحتتتتتتتداث >‪", " gun.x1 -self.rc \ and yo < gun.y1 +self.rc and yo > gun.y1 -self.rc : self.anim =False # ‫: )رسم انفجار القذيفة )دائرة صفراء‬ self.explo = self.boss.create_oval(xo -12, yo -12, xo +12, yo +12, fill ='yellow', width =0) self.hit =id # ‫مرجع إصايبة الهدف‬ self.boss.after(150, self.fin_explosion) break def fin_explosion(self): "effacer l'explosion ; réinitaliser l'obus ; gérer le score" self.boss.delete(self.explo) # ‫مسح النفجار‬ self.explo =False # ‫إذن لفطلق نار جديد‬ # ‫: إشارة نجاح إلى النافذة الرئيسية‬ self.appli.goal(self.id, self.hit) def fin_animation(self): "actions à accomplir lorsque l'obus a terminé sa trajectoire"

‫تحليل يبرنامج محدد‬
111# self.appli.disperser() # ‫نقل المدافع‬ 112# # ‫: )إخفاء القذيفة )يبإرسالها خارج اللوظحة‬ 113# self.boss.coords(self.obus, -10, -10, -10, -10) 114# 115# class Pupitre(Frame): 116# """Pupitre de pointage associé à un canon""" 117# def __init__(self, boss, canon): 118# Frame.__init__(self, bd =3, relief =GROOVE) 119# self.score =0 120# self.appli =boss # ‫مرجع التطبيق‬ 121# self.canon =canon # ‫مرجع المدفع المرتبط‬ 122# # ‫: نظام تحكم في زاوية الفطلق‬ 123# self.regl =Scale(self, from_ =85, to =-15, troughcolor=canon.coul, 124# command =self.orienter) 125# self.regl.set(45) # ‫الزاوية الولية للفطلق‬ 126# self.regl.pack(side =LEFT) 127# # ‫: علمة تعريف المدفع‬ 128# Label(self, text =canon.id).pack(side =TOP, anchor =W, pady =5) 129# # ‫: زر الفطلق‬ 130# self.bTir =Button(self, text ='Feu !', command =self.tirer) 131# self.bTir.pack(side =BOTTOM, padx =5, pady =5) 132# Label(self, text ="points").pack() 133# self.points =Label(self, text=' 0 ', bg ='white') 134# self.points.pack() 135# # ‫: وضع على يمين أو اليسار اعتمادا على اتجاه المدفع‬ 136# if canon.sens == -1: 137# self.pack(padx =5, pady =5, side =RIGHT) 138# else: 139# self.pack(padx =5, pady =5, side =LEFT) 140# 141# def tirer(self): 142# "déclencher le tir du canon associé" 143# self.canon.feu() 144# 145# def orienter(self, angle): 146# "ajuster la hausse du canon associé" 147# self.canon.orienter(angle) 148# 149# def attribuerPoint(self, p): 150# "incrémenter ou décrémenter le score, de points" 151# self.score += p 152# self.points.config(text = ' %s ' % self.score) 153# 154# class Application(Frame): 155# '''Fenêtre principale de l'application''' 156# def __init__(self): 157# Frame.__init__(self) 158# self.master.title('>>>>> Boum ! Boum ! >> fichierDonnees ="E:/python3/essais/bd_test.sq‬‬

‫اسم اللف يمكن أن يتضمن اسم السار وأي امتداد. ومن المكن استخدام اسم خاص :‪ ،:memory‬يشي إلى أن يتم معالجة قواعد‬ ‫البيانات في الذاكرة العشوائية )رام( فقط. وبذلك يمكنك اختصار الوقت والوصول إلى البيانات، والتطبيق سيكون سيعا جتتدا،‬ ‫وقد يكون ذا فائدة في سياق برنامج لعبة على سبيل اللثال، ش ط أن تكون هنالك آلية خاصة للحفظ على القرص.‬
‫58‬ ‫‪ (/SQLite (http://www.sqlite.org‬هو مرك قواعد بي ان ات الكاثر اسةتخدام ا ف الع ال . يةتم اسةتخدامه ف العديد من‬ ‫الدوات ماثل ‪ ,,Firefox, Skype, Google Gears‬و ف بعض منةتج ات أبل و أدوب و مك اف و ف الكةتب ات القي اسية ف العديد‬ ‫من الغ ات البمة ماثل ‪ PHP‬و بياثون . و هو أيض ا الكاثر شعبية ف النظم الضومنة, ب ا ف ذلك الواتف الذكية الدياثة . و هو‬ ‫م ان و خ ال من القو ق .‬

‫إدارة قواعد البيانات‬

‫603‬

‫سوف تقوم إذا بصنع كائن-اتصال، بمساعد دالة-صتتنع ‪ .()connect‬هتتذا الكتتائن يتفاعتتل بيتت البنامتتج وقاعتتدة البيانتتات .‬ ‫العملية مماثلة تماما لفتح ملف نص، وملثيل كائن سيصنع ملف التخزين )إذا كان اللف غي موجود( :‬
‫)‪>>> conn =sqlite3.connect(fichierDonnees‬‬

‫تم الن وضع كائن التصال في مكانه، وسوف تكون قادرا على التفاعل معه باستتتخدام ‪ .SQL‬ستتيكون هتتذا ممكنتتا مباشتتة عتتن‬ ‫طريق استخدام بعض أساليب هذا الكائن ، لكن من الفضل أن تضع في مكانه لتحاور مع كائن-واجهة أخرى يسمى اللؤش. بتتل‬
‫68‬

‫هو نوع من الذاكرة العازلة، لتخزين البيانات في الذاكرة بشكل ملؤقت عند القيام بمعالجتها، فضل عن عمليتتات تقتتوم لهتتا عليهتتا،‬ ‫قبل نقلها إلى قاعدة البيانات النهائية. هتذه التقنيتتة يجتتل متن المكتن إلغتتاء إذا لتزم المتتر عمليتتة أو أكتتث التت مهتتي غيتت كافيتتة،‬ ‫وإعادتها إلى معالجتها، دون أن تتأثر قاعدة البيانات )يمكنك معرفة الزيد عم هذا الفهتوم متن خلل إحتدى وثتائق التت تتعامتتل‬ ‫مع لغة ‪. (SQL‬‬
‫)(‪>>> cur =conn.cursor‬‬

‫قاعدة البيانات تتكون دائما من جدول أو أكث، يحتتتوي علتتى الستتجلت )أو الحفوظتتات(، وهتتي تحتتتوي علتتى أنتتواع مختلفتتة متن‬ ‫الجالت. وهذه الفاهيم ربما كنت على دراية بها إذا كنتت قتد عملتت متع أي جتدول : الستتجلت يتتم حفظهتا فتتي أستطر الجتدول،‬ ‫والجالت في خليا السطر. سوف نكتب أول استعلم ‪ SQL‬لنطلب منه إنشاء جدول جديد :‬
‫)")‪>>> cur.execute("CREATE TABLE membres (age INTEGER, nom TEXT, taille REAL‬‬

‫يتم التعبي عن الستعلم في سلسلة نصية كلسيكية، والت نريد تمريرها للملؤش عب أسلوبه ‪ .()execute‬لحظ جيدا أن‬ ‫بحروف كبية تعليمات هذه اللغة، وذلك للتفرقة بي تعليمات بيلثون الحيطة بها، ولكن بالطبع يمكنك أن تتبع عادات أخرى.‬

‫‪ SQL‬يتجاهل حالة الحرف، بحيث يمكن ترمي استعلمات ‪ SQL‬بحروف كبية أو صغية )أو معتتا(. اختنتتا عشخصتتيا الكتابتتة‬

‫كما يرجى ملحظة أن أنواع البيانات ل تحمل نفس السماء في بيلثتتون وفتي ‪ .SQL‬ل ينبغتتي علتتى التجمتتة أن تزعجتتك كتلثيا.‬ ‫ملحظة بسيطة وهي أن السلسل النصية يتم ترميها إفتاضتتيا بتتت 8-‪ ،Utf‬حستتب التفاقيتتة ذاتهتتا متتع اللفتتات النصتتية )انظتر‬ ‫للصفحة 221(.‬ ‫يمكننا الن إدخال السجلت :‬
‫)")38.1,'‪>>> cur.execute("INSERT INTO membres(age,nom,taille) VALUES(21,'Dupont‬‬ ‫)")75.1,'‪>>> cur.execute("INSERT INTO membres(age,nom,taille) VALUES(15,'Blumâr‬‬ ‫)")96.1,'‪>>> cur.execute("INSERT Into membres(age,nom,taille) VALUES(18,'Özémir‬‬

‫68‬ ‫وحدة ‪ SQLite‬توفر بعض الس اليب الخةتصرة للوصول إل البي ان ات دون اسةتخدام الؤشر )أو على نو أد ق, وذلك ب اسةتخدام‬ ‫مؤشر ضومن( . هذه الس اليب ل تةتوافق مع الةتقني ات القي اسية, و نن نفضل ت اهل ذلك هن ا .‬

‫703‬

‫قواعد البيانات‬

‫انتبه، في هذه الرحلة من العمليات، سيتم حفظ السجلت في ملؤش عازل، لكنا لتم تنقتل بعتد إلتى قاعتدة البيانتات. لتذا يمكنتتك‬ ‫إلغائها تماما، إذا لزم المر، كما سنى بعد قليل. وسيتم تشغيل نقل البيانات من خلل السلوب ‪ ()commit‬لكائن التصال‬ ‫::‬
‫)(‪>>> conn.commit‬‬

‫و بعد النتهاء من العمل يمكنك إغلق اللؤش، وكذلك التصال .‬
‫78‬

‫)(‪>>> cur.close‬‬ ‫)(‪>>> conn.close‬‬

‫االتصال بقاعدة بيانات موجودة‬ ‫بعد العمليات أعله، تم إنشاء ملف يسمى 3‪ bd_test.sq‬في موقع محدد في جهاز،ك. لقد قمت الن بالخروج من بيلثون وربما‬ ‫قد أغلقت حاسوبك : البيانتات التتت تتم حفظهتتا، كيتتف يمكننتتا الوصتتول إليهتتا متترة أخترى ؟ المتتر فتتي غايتتة البستاطة : يكفتتي أن‬ ‫تستخدم بالضبط هذه التعليمات :‬
‫3‪>>> import sqlite‬‬ ‫)"3‪>>> conn =sqlite3.connect("E:/python3/essais/bd_test.sq‬‬ ‫)(‪>>> cur =conn.cursor‬‬

‫يتم تنفيذ الستعلم بالطبع بمساعدة استعلمات ‪ ،SQL‬الذي يعكي للسلوب ‪ ()execute‬للملؤش، دائما فتتي عشتكل سلستلة‬ ‫نصية :‬
‫)"‪>>> cur.execute("SELECT * FROM membres‬‬

‫هذا الستعلم يقوم بطلب تحديد مجموعة معينة من السجلت، سيتم تحويلها من قاعدة البيانات إلتى اللؤشتت. فتتي هتتذه الحالتتة،‬ ‫التحديد ليس عنص واحد، لننا طلبنا أن يتم استداد جميع سجلت الجدول ‪. membres‬‬ ‫تذكر أن الرمز * يستخدم كثيرا في المعلوماتية ك"جوكر" بمعني "كل" .‬ ‫ً‬ ‫السجلت الحددة هي الن في اللؤش. فإذا أردنا أن نراها، يجب علينا استخراجها. وهذا يتم بطريقتي، وقد تبدو للوهلة الولتتى‬ ‫مختلفة، لكن في الواقع أن الطريقتي لكائن-اللؤش يتم صنعها من بيلثون هي مكررة، وهذا يعن، جهاز توليد التسلسلت .‬
‫88‬

‫الةتيطبيق ات الت تسةتخدم قواعد بي ان ات كبية غ الب ا م ا تكون تيطبيق ات مةتعددة السةتخدمي . وسوف نرى لحق ا )صفحة :‪Error‬‬ ‫‪ (Reference source not found‬أن ماثل هذه الةتيطبيق ات تنفذ عدة "أبن اء" لةتنفيذ مةتزامن للبن امج, وتدعى الواضيع, من‬

‫78‬

‫أجل الةتع امل مع اليطلب ات الوازية من عدة مسةتخدمي مةتلفي . وب الةت ال سوف يكون لكل واحد ك ائن ات اتص الت و مؤشر داخل‬ ‫البن امج نفسه, و أنه لن يكون هن الك تض ارب . ف ح الة ‪ ,SQLite‬و هو نظ ام مسةتخدم منفرد, إغل ق التص الت يةتسبب أيض ا‬ ‫بإغل ق اللف الذي يةتوي على ق اعدة البي ان ات, و الت سوف يةتلف عن النظ ام الكبي .‬ ‫88‬ ‫الةتكرارات هي جزء من ميزات الةتقدمة لبياثون . نن لن ندرسه ا ف هذا الكةت اب, و كذلك العديد من الدوات الخرى الاثية‬ ‫للهةتوم ام, ماثل تعريف الوظيفي للقوائم, و الديكورات, إل . و سوف تظل أشي اء كاثية ل تزال لسةتكرش افه ا' إذا كنت تريد اسةتكرش اف‬

‫إدارة قواعد البيانات‬

‫803‬

‫يمكنك الذهاب مباشة إلى التسلسل النتج، بمستتاعدة حلقتة ‪ for‬الكلستتيكية، وستتوف تحصتتل علتتى مجموعتتة متن الصتفوفات‬ ‫الغلقة :‬
‫:‪>>> for l in cur‬‬ ‫...‬ ‫)‪print(l‬‬ ‫...‬ ‫)38.1 ,'‪(21, 'Dupont‬‬ ‫)75.1 ,'‪(15, 'Blumâr‬‬ ‫)96.1 ,'‪(18, 'Özémir‬‬

‫... أو يتم جمعها في قائمة أو مصفوفة مغلقة لزيد من العالجة )بمساعدة الدالت الدمجة ‪ ()list‬و ‪: (()tuple‬‬
‫)"‪>>> cur.execute("SELECT * FROM membres‬‬ ‫)‪>>> list(cur‬‬ ‫])96.1 ,'‪[(21, 'Dupont', 1.83), (15, 'Blumâr', 1.57), (18, 'Özémir‬‬

‫بطريقة أكث كلسيكية، يمكنك أيضا استدعاء الدالة ‪ ()fetchall‬للملؤش، الت تقوم بإرجاع قائمة مصفوفات مغلقة :‬
‫)"‪>>> cur.execute("SELECT * FROM membres‬‬ ‫)(‪>>> cur.fetchall‬‬ ‫])96.1 ,'‪[(21, 'Dupont', 1.83), (15, 'Blumâr', 1.57), (18, 'Özémir‬‬

‫كما أن اللؤش ل يزال مفتوحا، يمكنك بالطبع إضافة سجلت إضافية :‬
‫)")57.1,'‪>>> cur.execute("INSERT INTO membres(age,nom,taille) VALUES(19,'Ricard‬‬

‫في برنامج عملي، البيانات الت تريد تسجيلها يتم حفظها في متغيات تنشتتأ فتتي الغتتالب فتتي متغيتتات بيلثتتون. وستتوف تحتتتاج‬ ‫أيضا إلى إنشاء سلسلة نصية تحتوي على طلب استعلم ‪ ،SQL‬لتشمل قيما من هذه التغيات. فمن الستحسن استخدامها لهتتذا‬ ‫الغرض في التقنيات الهادية لتنسيق السلسل، لن هذه قد تفتح ثغرة أمنية في برامجهتتا، وتستتمح لقتحامهتتا متن خلل طريقتتة‬ ‫تدعى ‪) SQL Injection‬حقن ‪ . (SQL‬ولذلك يجب التأكد من تنسق استتتعلماتك للوحتتدة الواجهتتة نفستتها. والتقنيتتة الستتليمة‬
‫98‬

‫أدناه : سلسلة "رئيس" تستخدم علمة استتتفهام كعلمتتات التحويتتل، وتنستتيق نفستته معتمتتد متتن قبتتل الستتلوب ‪()execute‬‬ ‫للملؤش:‬
‫])56.1,"‪>>> data =[(17,"Durand",1.74),(22,"Berger",1.71),(20,"Weber‬‬ ‫:‪>>> for tu in data‬‬ ‫...‬ ‫)‪cur.execute("INSERT INTO membres(age,nom,taille) VALUES(?,?,?)", tu‬‬ ‫...‬ ‫)(‪>>> conn.commit‬‬

‫هذه اللغة !‬ ‫98‬ ‫هذه الرشكلة المنية تنرشأ عن طريق تيطبيق ات الويب, الجوم يةتم ب اسةتخدام حقل نوذج ‪ HTML‬و يؤدي إل حقن الةتعليوم ات‬ ‫‪ SQL‬ب البي ان ات البياثة حيث يةتوقع البن امج أن السلسل غي مؤذية . و مع ذلك, فومن السةتحسن اسةتخدام تقني ات برمة أكاثر‬ ‫أمن ا, حت ولو تيطبيق بسيط لرشخص واحد .‬

‫903‬

‫قواعد البيانات‬

‫في هذا اللثال، سلسلة الستتتعلم تحمتتل 3 علمتتات استتفهام، والتت هتتي علماتنتتا. ستوف يتتم استتتبدالهم بتتت 3 عناصتت متن نتتوع‬ ‫مصفوفات مغلقة في كل تكرار للحلقة، وحدة الواجهة مع ‪ SQLite‬يتم تحميلها مع كل متغي وفقا لنوعه.‬ ‫في هذه الرحلة من العمليات، قد تعتقد أن كتل متتا رأينتاه هتتو معقتد للغايتتة لكتابتتة وقتتراءة العلومتتات فتتي ملتتف. لتن يكتتون أكتث‬ ‫بساطة إذا استخدمت معالجتات ملفتات التت نعرفهتتا ؟ نعتم ول. هتذا صتحيح بالنستبة للكميتات الصتغية متن العلومتتات التت ل‬ ‫تحتاج إلى تغيي كبي مع مرور الوقت. لكننتتا ل يمكننتتا التدفاع عنتته إذا أختتذنا مشتتكلة بستتيطة للتعتتديل أو حتذف أو إضتتافة أي‬ ‫سجل. في قاعدة البيانات، هذا بسيط جدا :‬
‫)"'‪>>> cur.execute("UPDATE membres SET nom ='Gerart' WHERE nom='Ricard‬‬

‫لحذف سجل أو أكث، استخدم استعلم ملثل هذه :‬
‫)"'‪>>> cur.execute("DELETE FROM membres WHERE nom='Gerart‬‬

‫مع ما نعرفه من اللفات النصية، يجب علينا بالتأكيد كتابة العديد من السطر)كود( للحصول على نفتتس الشتتء ! ولكتتن هنالتتك‬ ‫الكلثي ملثي للهتمام .‬ ‫انتبه‬ ‫التعليمــة ‪ .()conn.commit‬يمكنــك إلغــاء جميــع التغييــرات منــذ ‪ ()commit‬الســابق، وإغل ق التصــال‬ ‫باستخدام المر ‪()conn.close‬‬ ‫ل تن س أن تغييرات المؤشر تحدث في الرام، وبالتالي لن يتـم حفـظ أي شـيء بشـكل دائمــا مــا لـم تقـم بتشـغيل‬ ‫َ‬

‫البحث التحديدي في قاعدة بيانات‬

‫تمرين‬
‫61.1 قبتتل الضتت قتتدما، وبوصتتفها تمريتتن تجميعتتي، ستتوف أطلتتب منتتك إنشتتاء قاعتتدة بيانتتات " ‪ "Musique‬تحتتتوي علتتى‬ ‫الجدولي التاليي )هذه بعض العمال، لكن يجب أن تكتتون قتادرا علتى التعامتتل متع عتدد متن البيانتات بشتتكل صتتحيح‬ ‫لختبار دالت البحث والفرز العتمد من قبل ‪: (SGBDR‬‬
‫‪Oeuvres‬‬ ‫‪(comp (chaîne‬‬ ‫‪(titre (chaîne‬‬ ‫‪(duree (entier‬‬ ‫‪(interpr (chaîne‬‬ ‫‪Compositeurs‬‬ ‫‪(comp (chaîne‬‬ ‫‪(a_naiss (entier‬‬ ‫‪(a_mort (entier‬‬

‫إدارة قواعد البيانات‬

310

‫ مع البيانات التالية )اغتنم هذه الفرصة لظهار مهاراتك الت تعلمتها متتن خلل كتابتتة‬Compositeurs ‫ابدأ بملء جدول‬ :(!‫سكربت صغي لتسهيل إدخال العلومات: تحتاج إلى حلقة‬ comp Mozart Beethoven Haendel Schubert Vivaldi Monteverdi Chopin Bach Shostakovich a_naiss 1756 1770 1685 1797 1678 1567 1810 1685 1906 a_mort 1791 1827 1759 1828 1741 1643 1849 1750 1975

: ‫، أدخل البيانات التالية‬oeuvres ‫في جدول‬ comp Vivaldi Mozart Brahms Beethoven Beethoven Schubert Haydn Chopin Bach Beethoven Mozart Mozart Beethoven titre Les quatre saisons Concerto piano N°12 Concerto violon N°2 Sonate "au clair de lune" Sonate "pathétique" Quintette "la truite" La création Concerto piano N°1 Toccata & fugue Concerto piano N°4 Symphonie N°40 Concerto piano N°22 Concerto piano N°3 duree 20 25 40 14 17 39 109 42 9 33 29 35 37 interpr T. Pinnock M. Perahia A. Grumiaux W. Kempf W. Kempf SE of London H. Von Karajan M.J. Pires P. Burmester M. Pollini F. Bruggen S. Richter S. Richter

‫ على سنة اليلد وسنة موت اللحنيتت. متدة تنفيتتذ هتذا فتتي دقتائق. بتالطبع يمكنتتك‬a_mort ‫ و‬a_naiss ‫يحتوي الحقلن‬ .‫إضافة العديد من السجلت للملحني واللؤلفي الت تردها، لكن تلك الذكورة أعله ينبغي أن تكون كافية لبقية الظهر‬ ،‫في ما يلي، نحن نفتض أنك قد قمت بتمي البيانات في الجدولي أعله. إذا كانت لديك صعوبة في كتابة السكربت الطلوب‬ .Error: Reference source not found ‫يرجى الرجوع إلى تمرين 1.61 في‬ " ‫ بدائي، الذي يسمح لك بالنصال بقاعدة البيانتتات‬SQL ‫السكربت الصغي بالسفل يوفر أغراض العلومات فقط. بل هو عميل‬ ‫ - موسيقى" الت يجب أن تكون الن موجودة في الدليل الخاص بك، ويتم فتح اللؤش لستخدامه للستعلم. لحظ‬musique que rien n’est transcrit sur le disque tant que la méthode commit() n’a pas été ‫مرة أخرى أننا‬ .invoquée
# ‫ استخدام قاعدة يبيانات صغيرة تقبل تعليمات‬SQL import sqlite3 baseDonn = sqlite3.connect("musique.sq3")

311

‫قواعد البيانات‬

cur = baseDonn.cursor() while 1: print("Veuillez entrer votre requête SQL (ou pour terminer) :") requete = input() if requete =="": break try: cur.execute(requete) # ‫ تشغيل استعلم‬SQL except: print('*** Requête SQL incorrecte ***') else: for enreg in cur: # ‫إظهار الناتج‬ print(enreg) print() choix = input("Confirmez-vous l'enregistrement de l'état actuel (o/n) ? ") if choix[0] == "o" or choix[0] == "O": baseDonn.commit() else: baseDonn.close()

‫هتذا التطتبيق البستيط جتدا متن الواضتح أنته ملثتال. ينبغتي أن نضتيف خيتار لختيتار قاعتدة البيانتات والتدليل. استتخدمنا لنتع‬ ‫السكربت من "زرع" عندما يقوم الستخدم بتمي استعلم غي صحيح، استخدمنا هنا معالجتتة الستتلثناءات التت قمنتتا بشتحها‬ .125 ‫في الصفحة‬ (select) ‫الستعلم التحديد‬ ‫،ت الت سنى الن بعض ممياتتته. وتتذكر مترة أخترى أننتا ستنتناول‬select ‫ هي التعليمة‬SQL ‫واحدة من أقوى تعليمات لغة‬ .‫ يجب أن يشح في كتب عديدة‬SQL ‫هنا جزءا صغيا جدا من هذا الوضوع : الوصف التفصيلي لت‬ ً ً : ‫عشغل إذا السكربت أعله، وحلل بدقة ما يحدث عند تقديم الستعلمات التالية‬ select * from oeuvres select * from oeuvres where comp = 'Mozart' select comp, titre, duree from oeuvres order by comp

select titre, comp from oeuvres where comp='Beethoven' or comp='Mozart' order by comp select count(*) from oeuvres select sum(duree) from oeuvres select avg(duree) from oeuvres select sum(duree) from oeuvres where comp='Beethoven' select * from oeuvres where duree >35 order by duree desc select * from compositeurs where a_mort 1‪return "Bonjour à tous !1‪return "La programmation, c'est génial !‬ ‫‪ == العثور على التسمية #‬ ‫#32‬ ‫]:2[‪label =ligne‬‬ ‫*[ مسح #‬ ‫#42‬ ‫)(‪label =label[:-1].strip‬‬ ‫.‪# suppression LF et esp évent‬‬ ‫#52‬ ‫]2-:[‪label =label‬‬ ‫]* مسح #‬ ‫#62‬ ‫""= ‪txt‬‬ ‫#72‬ ‫:‪else‬‬ ‫#82‬ ‫:"#####"== ]5:[‪if ligne‬‬ ‫#92‬ ‫‪Glob.html[label] =txt‬‬ ‫#03‬ ‫:‪else‬‬ ‫#13‬ ‫‪txt += ligne‬‬ ‫#23‬ ‫:‪finally‬‬ ‫#33‬ ‫)(‪fi.close‬‬ ‫سيتم إغلق الملف في جميع الحالت #‬ ‫#43‬

‫التشابهة ، بإدراجها في نمط عشائع. هذا النمط، ملثل جميع الخرين، بأتي من ملف ‪ spectacles.htm‬لكن الدالتتة الستتابقة قتتد‬
‫:)‪35# def mep(page‬‬ ‫#63‬ ‫تقوم يبإرجاع >الصفحة< الممررت، التي وضع يبها يبرامتر في : ‪ HTML‬توليد دالة "التخطيط" لل #‬

‫الدالة اللثانية، على الرغم من أنها بسيطة، فهي تلؤدي عمل رائعا : بل في الواقع من عشأنه أن يسمح لنا بتقديم جميع الصتفحات‬

‫قدمته لنا في قاموس ‪ ،Glob.html‬تحت اسم "‪: "miseEnPage‬‬

‫رأس وتذييل الصفحة الملئمة‬

‫#73‬ ‫#83‬

‫)‪return Glob.html["miseEnPage"].format(page‬‬

‫الدالة اللثاللثة تصنع قطعة قطعة سلسلة نصية تحتوي على كود ‪ HTML‬الزم لوصف الجدول. هذا الجتتدول ستتيتم ملئتته تلقائيتتا‬ ‫مع قائمة البامج الدرجة حاليا في قاعدة البيانتتات. نتترى هنتتا بشتتكل واضتح جتدا مستتاهمة البمجتتة الساستتية لتحقيتتق موقتتع‬ ‫ديناميكي، وهذا يعن موقعا يتم تحديث صفحاته باستمرار استنادا إلى البيانات التتت يقتتدمها التتزوار بأنفستتهم. أو وفقتتا لختلتتف‬ ‫الحداث :‬
‫:)(‪39# def listeSpectacles‬‬ ‫#04‬ ‫.‪ HTML‬إنشاء قائمة من العروض المتاظحة، في جدول #‬ ‫#14‬ ‫"‪req ="SELECT ref_spt, titre, date, prix_pl, vendues FROM spectacles‬‬ ‫#24‬ ‫)‪res =BD.executerReq(req‬‬ ‫‪# ==> res sera une liste de tuples‬‬ ‫#34‬ ‫'‪tabl ='\n‬‬ ‫#44‬ ‫""= ‪tabs‬‬ ‫#54‬ ‫:)5(‪for n in range‬‬ ‫#64‬ ‫ملظحظة : لتظهر كسلسلة منسقة، يجب أن تقوم يبمضاعفة القواس #‬ ‫#74‬ ‫)‪tabs += "{{{0}}}".format(n‬‬ ‫#84‬ ‫"‪ligneTableau ="" +tabs +"\n‬‬ ‫#94‬ ‫: السطر الول من الجدول تحتوي على رؤوس العمدة #‬ ‫#05‬ ‫\.‪tabl += ligneTableau‬‬ ‫#15‬ ‫)"‪format("Réf.", "Titre", "Date", "Prix des places", "Vendues‬‬ ‫#25‬ ‫: ‪ BD‬السطر التالية : يتم استخراج محتواها من #‬ ‫#35‬ ‫:‪for ref, tit, dat, pri, ven in res‬‬ ‫#45‬ ‫)‪tabl += ligneTableau.format(ref, tit, dat, pri, ven‬‬ ‫#55‬ ‫">‪return tabl +""‪‬ ‫‪) . %s" % (nom, msgClient‬‬ ‫)‪print(message‬‬ ‫: إرسال رسالة إلى جميع العملء #‬ ‫:‪for cle in conn_client‬‬ ‫:‪if cle != nom‬‬ ‫ل يتم إعادة إرسالها إلى المرسل #‬ ‫))"8‪conn_client[cle].send(message.encode("Utf‬‬ ‫: إغلق التصال #‬ ‫)(‪self.connexion.close‬‬ ‫قطع التصال من جانب الخادم #‬ ‫]‪del conn_client[nom‬‬ ‫ظحذف المدخلت في القاموس #‬ ‫)‪print("Client %s déconnecté." % nom‬‬ ‫ينتهي الخيط هنا #‬ ‫: ‪ socket‬تهيئة الخادم - وضع #‬ ‫)‪mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM‬‬ ‫:‪try‬‬ ‫))‪mySocket.bind((HOST, PORT‬‬

‫التصال عبر الشبكة وخاصية التعدد) ‪(multithreading‬‬
‫#93‬ ‫#04‬ ‫#14‬ ‫#24‬ ‫#34‬ ‫#44‬ ‫#54‬ ‫#64‬ ‫#74‬ ‫#84‬ ‫#94‬ ‫#05‬ ‫#15‬ ‫#25‬ ‫#35‬ ‫#45‬ ‫#55‬ ‫#65‬ ‫#75‬ ‫#85‬ ‫#95‬ ‫:‪except socket.error‬‬ ‫)".‪print("La liaison du socket à l'adresse choisie a échoué‬‬ ‫)(‪sys.exit‬‬ ‫)"... ‪print("Serveur prêt, en attente de requêtes‬‬ ‫)5(‪mySocket.listen‬‬ ‫: انتظار ودعم التصالت المطلويبة من العملء #‬ ‫}{ = ‪conn_client‬‬ ‫قاموس اتصالت العملء #‬ ‫:1 ‪while‬‬ ‫)(‪connexion, adresse = mySocket.accept‬‬ ‫: صنع كائن خيط جديد لتوليد التصال #‬ ‫)‪th = ThreadClient(connexion‬‬ ‫)(‪th.start‬‬ ‫: ظحفظ التصال في قاموس #‬ ‫)(‪it = th.getName‬‬ ‫رقم الخيط #‬ ‫‪conn_client[it] = connexion‬‬ ‫\% ".‪print("Client %s connecté, adresse IP %s, port %s‬‬ ‫))]1[‪(it, adresse[0], adresse‬‬ ‫: التحاور مع العميل #‬ ‫".‪msg ="Vous êtes connecté. Envoyez vos messages‬‬ ‫))"8‪connexion.send(msg.encode("Utf‬‬

‫883‬

‫تعليقات‬ ‫•السطور من 53 إلى 34 : تهيئة الخادم هي تعريف نفسه للخادم البدائي الذي تم شحه في بداية الفصل السابق .‬ ‫•* السطر 64 : مراجع الختلفة للتصالت يجب أن يتم تخزينهم . يمكننا وضعها في قائمتتة، لكتن متن الفضتل وضتعها فتي‬ ‫قاموس، وذلك لسببي : الول هتتو أننتا بحاجتتة إلتى إضتافة أو إزالتة هتتذه الراجتتع فتتي أي ترتيتتب، لن العملء سيتصتتلون‬ ‫ويقطعون التصال بإرادتهم . والسبب اللثاني هو أننا يمكن أن نقوم بسهولة بتعريف معرف فريد لكل اتصتتال، والتذي يمكتن‬ ‫أن يكون بملثابة مفتاح وصول في القاموس . هذا العرف سوف يقدم تلقائيا من قبل الصنف ‪.()Thread‬‬ ‫•السطور من 74 إلى 15 : يبدأ البنامج هنا من خلل تكرار حلقة دائمة، والتتت متتن عشتتأنها أن تنتظتتر باستتتمرار التصتتالت‬ ‫الجديدة . لكل واحدة من هذه التصالت، يتم إتشتتاء كتتائن جديتد ‪ ()ThreadClient‬والتتت يمكتتن العنايتتة بهتتا بشتتكل‬ ‫مستقل عن الخرين .‬

‫•* السطور من 25 إلى 45 : الحصول على معرف فريد يتم باستخدام السلوب ‪ .()getName‬يمكننا هنا أن نتمتع لن‬ ‫بيلثون يقوم تلقائيا بتعيي اسم فريد لكل موضوع جديد : هتتذا الستم كمعتترف )أو مفتتتاح( للعلثتتور علتتى اتصتتال منتتاظر فتتي‬ ‫قاموسنا . سوف ترى أنه عبارة عن سلسلة، من نموذج "‪) "Thread-N‬الحرف ‪ N‬يدل على ترتيب الوضوع( .‬ ‫•السطور من 51 إلى 71 : ضتتع فتتي اعتبتار،ك أن الكائنتات ‪ ()ThreadClient‬كاتصتتال، وجميتتع هتتذه الكائنتات تعمتتل‬ ‫بشكل مواز . السلوب ‪ ()getName‬يمكن استخدامه داخل أي من هذه العناص للعلثور علتى هتتويته . ونحتن نستتتخدم‬ ‫هذه العلومات للتميي بي التصال الحالي من جميع الخرين )انظر للسطر 62( .‬

‫983‬

‫إدارة مهام متعددة في نفس الوقت يباستخدام المواضيع ) ‪(theards‬‬

‫•السطور من 81 إلى 32 : فائدة الوضوع هو الحصول على كل الرسائل متتن عميتتل معيتت . لتتذلك هتتي حلقتتة دائمتتة التكتترار،‬ ‫والت سوف تتوقف عندما تستلم رسالة معينة " ‪ ،"fin‬أو عند استلم رسالة فارغة )عند قطع التصال من شيك( .‬ ‫•السطور من 42 إلى 72 : كل رسالة مستقبلة من عميل يجتتب إعتتادة توجيههتتا إلتتى كتتل الخريتتن . نحتتن نستتتخدم همتتا حلقتة‬ ‫‪ for‬لتكرار على)التدوير( مفاتيح القاموس والتصالت، والت تسمح لنتتا بعتتد ذلتتك بإيجتتاد التصتتالت نفستتها . وهنالتتك‬ ‫اختبار بسيط )السطر 62( يمنعنا من إعادة إرسال الرسالة إلى العميل الذي من أين يأتي .‬ ‫•السطر 13 : عندما نغلق ‪ socket‬اتصال، فمن الفضل إزالتة مرجعهتا فتي القتاموس، لنتته هتذا الرجتع لتم يعتد يستتخدم .‬ ‫ويمكننا القيام بذلك دون اتخاذ احتياطات خاصة، حيث أن عناص القاموس غي مرتبتتة )ويمكننتتا إضتتافة أو إزالتتة فتتي أي‬ ‫ترتيب( .‬ ‫لعبة القصف، نسخة الشبكة‬ ‫في الفصل 51 علقنا في تطوير لعبة قتال صغية تواجه اللعبي بالقصف . إن فائدة هذه اللعبة ل تزال محتتدودة للغايتتة، كمتتا‬ ‫أنها تلعب على حاسوب واحد . سوف نقوم الن، يإضافة التقنيات الت تعلمناها الن . ملثل نظام "الدردعشة" الذي شتتحناه فتتي‬

‫الصفحات السابقة، فإن التطبيق الكامل سوف يتكتتون الن متتن برنتتامجي متفصتتلي : برنامتتج ختتادم ستتيتم تشتتغيله علتتى جهتتاز‬

‫التصال عبر الشبكة وخاصية التعدد) ‪(multithreading‬‬

‫093‬

‫واحد، وتطبيق العميل الذي يمكن تشغيله من أي جهاز .و نظر لطبيعة بيلثون الحمولة، ستتوف تكتتون قتتادرا علتتى تنظيتتم معتتار،ك‬ ‫بي أجهزة الحاسوب الت تديرها أنظمة تشغيل مختلفة )لينكس ↔ ويندوز ↔ ما،ك ( .‬

‫193‬

‫لعبة القصف، نسخة الشبكة‬ ‫برنامج الخادم : فكرة عامة‬

‫برامج الخادم والعميل يشغلون نفس قاعدة البنامج، في حد ذاتها تعافى إلى حد كبي عن ماسبق الت وضتعت فتي جميتع أنحتاء‬ ‫الفصتتل 51 . لتتذا نفتتتض هتتذا لتتا تبقتتى متتن هتتذه الدراستتة التتت تتتم حفتتظ نستتختي ستتابقا متتن اللعبتتة فتتي ملفتتات وحتتدات‬ ‫‪ canon03.py‬و ‪ ,canon04.py‬اللثبتة في الدليل الحالي . في الواقع يمكننا استخدام الكتتلثي متتن التعليمتتات البمجيتتة‬ ‫الت تحتويها، وسنستخدم بحكم استدعاء ووراثة الصناف .‬ ‫من وحدة 40‪ ,canon‬سوف نعيد استخدام الصنف ‪ ()Canon‬على هذا النحو، فتتإنه لكتل متن البنامتتج الختادم للبنامتج‬ ‫العميل . من هذه الوحدة، سوف نستدعي الصنف ‪ ,()AppBombardes‬والتذي ستوف نشتتتق منتته الصتتنف الرئيستت متن‬ ‫تطبيق خادمنا: ‪ .()AppServeur‬ستتوف تجتتد أيضتتا أنهتتا تنتتتج بنفستتها الصتتنف الفرعتتي ‪ ,()AppClient‬ودائمتتا عتتن‬ ‫طريق الياث.‬ ‫بعد" .‬ ‫و أخيتتتا، ستتتيتم إضتتتافة صتتتنفي جديتتتدين إلتتتى متتتا ستتتبق، كتتتل واحتتتدة متخصصتتتة فتتتي إنشتتتاء كتتتائن موضتتتوع : الصتتتنف‬ ‫‪ ,()ThreadClients‬منهتتتتا ملثيتتتتل التتتتذي يراقتتتتب باستتتتتمرار لتلقتتتتي طلبتتتتات ‪ socket‬متتتتن العملء الجتتتتدد والصتتتتنف‬ ‫‪ ,()ThreadConnexion‬الذي سينش كائنات ‪ socket‬اللزمة لجراء حوار مع كل عميل متصل بالفعل .‬ ‫هذه الصناف الجديدة ستكون مصدر إلهام من تلك الت قمنا بتطويرها لخادم الدردعشة في الصفحات السابقة . والفرق الرئيس‬ ‫هو أن لدينا ترابط محدد لتفعيل مواضيع خاصة للكود الذي ينتظر اتصالت العملء، بحيتتث يمكتن للتطتبيق الرئيستت أن يفعتل‬ ‫عشيئا أخر خلل ذلك الوقت .‬ ‫من هنا، عملنا الكبي الذي نتتواجه هتتو تطتتوير بروتوكتتول اتصتتال للحتتوار بيتت الختتادم والعملء . متتا هتتو الجديتتد ؟ ببستتاطة نقتتوم‬ ‫بتعريف مصمون الرسائل الت سيتم تبادلها بي اللت التصلة . ل تقلق : تطوير هذه "اللغة" يمكن أن يكون متقدما . نبتتدأ متتن‬ ‫خلل إنشاء قاعدة حوار، ثم نضيف تدريجيا "مفردات" .‬ ‫و يمكن تحقيق الكلثي من هذا العمل من خلل مساعدة برنامج العميل الذي سبق ووضعناه لنظام الدردعشتتة . ويستتتخدم لرستتال‬ ‫"الوامر" إلى الخادم الذي نطوره، ويتم تصحيح الطاعة : بوضوح، الجراءات الذي سوف نضتتعها تتتدريجيا علتتى ختتادم ستتوف‬ ‫يتم اختبارها تدريجبا، استجابة للرسائل الت أصدرها "باليد" العميل .‬

‫من وحدة 30‪ ,canon‬سوف نستدعي صنف ‪ ()Pupitre‬الت من عشأنها أن تلؤدي إلى نسخة أكث ملئمة ل "التحكم عتتن‬

‫التصال عبر الشبكة وخاصية التعدد) ‪(multithreading‬‬

‫293‬ ‫بروتوكول االتصاالت‬

‫و غن عن القول أن البوتوكول هو الوضح أدناه هو إجراء تعسفي تمامتتا . وستتيكون متتن المكتتن تمامتتا اختيتتار اتفاقيتتات أختترى‬ ‫مختلفة تماما . يمكنك بالطيع انتقاد الختيارات، وربما ترغب في استبدالها بأخرى أكث فاعلية أو أبسط .‬ ‫أنت تعرف مسبقا أن الرسائل التبادلة هي سلسل بسيطة من وحدات البايتات . توقع أن هذه الرسائل ستتوف تنقتتل العديتتد متتن‬ ‫العلومات في وقت واحد، ولقد قررنا أن كل واحد منهم يمكن أن يحمل العديد من الجالت، الت ستفصتتل بفواصتتل . عنتتد استتتلم‬ ‫أي من هذه الرسائل، يمكننا بعد ذلك بسهولة استعادة جميع الكونات في القائمة، وذلك باستخدام أسلوب الدمج ‪.()split‬‬ ‫هذا ملثال عن نوع تحاور، كما يمكن اتباعها على جانب العميل . الرسائل النجمية هي الت وردة من الختتادم، والختترى هتتي تلتتك‬ ‫الصادرة من قبل العميل نفسه :‬
‫#1‬ ‫#2‬ ‫#3‬ ‫#4‬ ‫#5‬ ‫#6‬ ‫#7‬ ‫#8‬ ‫#9‬ ‫#01‬ ‫#11‬ ‫#21‬ ‫#31‬ ‫#41‬ ‫#51‬ ‫#61‬ ‫#71‬ ‫*‪*serveur OK‬‬ ‫‪client OK‬‬ ‫*,‪*canons,Thread-3;104;228;1;dark red,Thread-2;454;166;-1;dark blue‬‬ ‫‪OK‬‬ ‫*‪*nouveau_canon,Thread-4,481,245,-1,dark green,le_vôtre‬‬ ‫,52,‪orienter‬‬ ‫‪feu‬‬ ‫*,082,945,4-‪*mouvement_de,Thread‬‬ ‫‪feu‬‬ ‫*,872,405,4-‪*mouvement_de,Thread‬‬ ‫*,0;2-‪*scores,Thread-4;1,Thread-3;-1,Thread‬‬ ‫*,32,2-‪*angle,Thread‬‬ ‫*,02,2-‪*angle,Thread‬‬ ‫*,2-‪*tir_de,Thread‬‬ ‫*,191,704,2-‪*mouvement_de,Thread‬‬ ‫*2-‪*départ_de,Thread‬‬ ‫*‪*nouveau_canon,Thread-5,502,276,-1,dark green‬‬

‫• عندما يبدأ عميل جديد،يرسل طلب اتصال إلى الخادم، الذي يرسل له رسالة عتتودة : "‪ . "serveur OK‬عنتتد استتتلم هتتذا‬ ‫الخي، سيستجب العميل من خلل إرستتال "‪ . "client OK‬هتتذا الول تبتتادل مجملت والتتت هتتي ليستتت ضتتورية، لكنتته‬ ‫يضمن أن البلغ على ما يرام في كل التجاهي . ذلك يحذر أن العميل على استعداد للعمل، سيقوم الخادم بإرستال وصتتف‬ ‫للمدافع بالفعل في اللعبة )إن وجدت( : اسم الستخدم، الوقع على اللوحة. التوجه، واللون )السطر 3( .‬ ‫•ردا على استلم العميل )السطر 4 (، سيقوم الخادم بتلثبيت مدفع حديد في فضاء اللعبة، فهو يشي إلتتى خصتتائص التلثتتبيت،‬ ‫وليس فقط للعميل الذي تسبب بذلك، ولكن حت جميع العملء الخرين التصلي . والرسالة الرسلة للعميل الجديتتد تحمتتل‬ ‫فرق )لنه هو صاحب مدفع الجديد( : بالضاف إلى المبات الوجودة في الدفع، والت يتم توفيها للجميتتع، ولتتديه حقتتل‬ ‫إضافي يحتوي ببساطة على "‪) "le_vôtre‬قارن على سبيل اللثال بي السطر 5 مع السطر 71، مما يدل على اتصاله متتن‬ ‫لعب أخر( . هذه العشارة الضافية تسمح للعميل بتميي بي مدفع، في رسائل عدة متماثلتتة، والتتت تحتتتوي علتتى تعريتتف‬ ‫موحد مسند إلى الخادم .‬

‫393‬

‫لعبة القصف، نسخة الشبكة‬

‫•الرسائل في السطور 6 و 7 هي أوامر مرسلة من قبل العميل )إنشتاء والتحكتتم فتتي إطلق النتتار( . فتتي النستتخة الستابقة متن‬ ‫اللعبة، كنا قد وافقنا علتتى أن التدافع ستتتحر،ك قليل )و بشتتكل عشتتوائي( بعتد كتتل طلقتتة . بالتتالي فتتإن الختتادم هتتو التذي‬ ‫سيقوم بهذه العملية، ثم يقوم بإرسال النتائج إلى كافة الستخدمي التصتتلي . الرستتالة التتواردة إلتتى الختتادم فتتي الستتطر 8‬ ‫هي ملؤش على هذه الخطوة )الحداثيات القدمة هي إحداثيات ناتجة عن الدفع العن( .‬ ‫•السطر 11 يقوم بنسخ نوع الرسالة الرسلة من قبل الخادم عندما يتم ضب الهدف . وترسل أيضا نتائج اللعبي الجديدة‬ ‫إلى جميع اللعبي لجميع العملء .‬ ‫•رسائل الخادم في السطر 21 و 31 و 41 تشي إلى الجراءات الت اتخذها اللعب الختتر )إعتتداد تتبتتع إطلق النتتار( . متترة‬ ‫أخرى، يتم نقل الدفع عشوائيا بعد كل إطلق نار )السطر 51( .‬ ‫•السطران 61 و 71 : عندما يقطع أحد العملء التصتتال، يقتتوم الختتادم بتتإعلم العملء الخريتتن، بإختفتتاء التتدفع فتتي فضتتاء‬ ‫اللعب على جميع الماكن . وعلى العكس، يمكن للعملء الجدد أن يقوموا باتصال جديد في أي وقت للعب اللعبة .‬ ‫ملحظات إضافية‬ ‫الحقل الول من كل رسالة يشي إلتتى مضتتمونها . الرستتائل الرستتلة متن العميتتل بستتيطة جتتدا : فهتتي تتوافتتق متتع الجتتراءات التتت‬ ‫اتخذها معظتتم اللعتتبي )تغييتت فتتي زاويتتة الطلق والستتيطرة علتتى النتتار( . والتتت تتم إرستتالها متن قبتتل الختتادم هتتي قليل أكتتث‬ ‫تعقيدا . يتم إرسال معظمهم إلتى كافتة الستتتخدمي التصتلي للحفتاظ علتى التقتدم الحترز . ونتيجتتة ذلتك، يجتب أن تكتتون لهتذه‬ ‫الرسائل معرف اللعب التذي يستتيطر علتتى العمتتل أو يتتأثر أو يغيتت . لقتد رأينتا أعله أن هتذه العرفتتات هتتي أستماء تتم صتتنعها‬ ‫تلقائيا من قبل خادم الواضيع، في كل مرة يتصل بها عميل جديد .‬ ‫بعض رسائل اللعبة تحتوي على معلومات بالجال . فتتي هتتذه الحالتتة، التغييتتات "الجتتالت-الفرعيتتة" تكتتون مفصتتولة بفواصتتل‬ ‫منقوطة )السطران 3 و 11( .‬ ‫برنامج خادم : الجزء الول‬ ‫سوف نجد في الصفحات التالية سكريبت كامل لبنامج خادم . سوف نقدم إليتتك فتتي ثلثتتة قطتتع علتتى التتتوالي تقليقتتات الكتتود،‬ ‫ولكن ترقيم السطر مستمر . على الرغم من أنه بالفعل طويل جدا ومعقد، سوف تشعر أنك تستحق ربما الزيد متتن التحستتي، ل‬ ‫سيما من حيث العرض العام . نت،ك لك المر للضافة بنفسك جميع اللحتق التت قتد تبتدو مفيتدة )علتى ستبيل اللثتال، اقتتاح‬ ‫لختيار إحداثيات الجهاز الصيف عند بدء التشغيل، وشيط قوائم وإلخ( :‬
‫#1‬ ‫#2‬ ‫#3‬ ‫#4‬ ‫#5‬ ‫#######################################################‬ ‫لعبة القصف – نسخة الخادم #‬ ‫#‬ ‫# 4002 ‪# (C) Gérard Swinnen, Verviers (Belgique) - July‬‬ ‫‪ : GPL‬رخصة #‬ ‫# 0102 .‪rév‬‬ ‫قبل تشغيل هذا السكريبت، تأكد من أن عنوان #‬ ‫#‬

(multithreading )‫التصال عبر الشبكة وخاصية التعدد‬
6# 7# 8# 9# 10# 11# 12# 13# 14# 15# 16# 17# 18# 19# 20# 21# 22# 23# 24# 25# 26# 27# 28# 29# 30# 31# 32# 33# 34# 35# 36# 37# 38# 39# 40# 41# 42# 43# 44# 45# 46# 47# 48# 49# 50# 51# 52# 53# 54# 55# 56# 57# # IP ‫.في السفل نفس في جهازك‬ # # ‫يمكنك اختيار رقم منفذ اخر، أو‬ # # ‫.تغيير إظحداثيات فضاء اللعبة‬ # # ‫في جميع الظحوال، تأكد من أن نفس الختيارات‬ # # ‫.تم وضعها في كل سكريبت عميل‬ # ####################################################### host, port = '192.168.1.168', 36000 largeur, hauteur = 700, 400 from tkinter import * import socket, sys, threading, time import canon03 from canon04 import Canon, AppBombardes class Pupitre(canon03.Pupitre): """Pupitre de pointage amélioré""" def __init__(self, boss, canon): canon03.Pupitre.__init__(self, boss, canon) def tirer(self): "déclencher le tir du canon associé" self.appli.tir_canon(self.canon.id) def orienter(self, angle): "ajuster la hausse du canon associé" self.appli.orienter_canon(self.canon.id, angle) def valeur_score(self, sc =None): "imposer un nouveau score , ou lire le score existant" if sc == None: return self.score else: self.score =sc self.points.config(text = ' %s ' % self.score) def inactiver(self): "désactiver le bouton de tir et le système de réglage d'angle" self.bTir.config(state =DISABLED) self.regl.config(state =DISABLED) def activer(self): "activer le bouton de tir et le système de réglage d'angle" self.bTir.config(state =NORMAL) self.regl.config(state =NORMAL) def reglage(self, angle): "changer la position du curseur de réglage" self.regl.config(state =NORMAL) self.regl.set(angle) self.regl.config(state =DISABLED) # ‫إظحداثيات فضاء اللعبة‬

394

.canon03 ‫)( تم بناؤه عن طريق العشتقاق من صنف لديه نفس السم تتم استتتدعاؤه متتن وحتدة‬Pupitre ‫•الصنف‬ .()orienter ‫)( و‬tirer ‫يرث جميع خصائصه، لكن نحن بحاجة لتجاوز أساليبه‬
111

‫ولذلك فإنه‬

. ‫111 تذكي : ف الصنف الرشةتق, يكنك تعريف أسلوب جديد مع نفس اسم أسلوب الصنف الصل, لةتغيي وظ ائفه ا ف الصنف الرشةتق‬ .(196 ‫و هذا يسومى ت اوز هذا السلوب )انظر أيض ا إل صفحة‬

‫593‬

‫لعبة القصف، نسخة الشبكة‬

‫• في الصدار الفردي للبنامج، في الواقع، يمكنك التحكم بكل مدفع من خلل لوحة التحكم . في نسخة الشبكة، العميل هتتو‬ ‫الذي سيقوم بالتحكم عن بعد بتشغيل الدافع . ولذلك، العميل هو الذي يتحكم عن بعد بالدفع . ول يمكن للواحات التحكتتم‬ ‫الت تظهر في نافتتذة الختتادم بتكتترار النتتاورات التتت يقتتوم بهتتا اللعبتتون متتن خلل كتتل عميتتل . زر الطلق وملؤشتت الرتفتتاع‬ ‫معطلن )غي مفعلن(، لكن اللؤشات تطيع الوامر الت تم إرسالها من قبل التطبيق الرئيس .‬ ‫•هذا الصنف الجديد ‪ ()Pupitre‬سوف يستخدم في كتتل نستتخة متن برنامتج العميتتل . فتتي نافتتذته ملثتل التت فتتي الختتادم،‬ ‫جميع لوحات التحكم تظهر كمكررات، لكن واحد منهم سيكون جاهزا تماما : الذي يتوافق مع مدفع اللعب .‬ ‫•كتتتتل هتتتتذه الستتتباب تتتتتلؤدي إلتتتتى ظهتتتتور أستتتتاليب جديتتتدة ‪ ()activer(), desactiver(), reglage‬و‬ ‫‪ ,()valeur_score‬الذين سيتم استدعاؤهم من قبل التطبيق الرئيس، ردا على الرسائل التبادلة بي الخادم وعملئه‬ ‫.‬ ‫•يتتتم استتتخدام الصتتنف ‪ ()ThreadConnexion‬أدنتتاه لنشتتاء ملثيتل لجموعتتة متن الكائنتتات الواضتتيع التتت تتستلم‬ ‫بالتوازي جميع التصالت من العملء . يحتوي أسلوبه ‪ ()run‬علتتى الوظتتائف الساستتية للختتادم، حلقتتة التعليمتتات التتت‬ ‫تدير استقبال الرسائل من عميل معي، والت لكل واحدة منها سلسلة من ردود الفعل . سوف تجد تنفيذ ملموس لبوتوكول‬ ‫التصال الوضح في الصفحات السابقة )بعض الرسائل تتتم صتتنعها بواستتطة الستتاليب ‪ ()depl_aleat_canon‬و‬ ‫‪ ()goal‬من صنف ‪ ()AppServeur‬الذي سيتم شحه لحقا(.‬
‫:)‪58# class ThreadConnexion(threading.Thread‬‬ ‫#95‬ ‫"""‪"""objet thread gestionnaire d'une connexion client‬‬ ‫#06‬ ‫:)‪def __init__(self, boss, conn‬‬ ‫#16‬ ‫)‪threading.Thread.__init__(self‬‬ ‫#26‬ ‫‪self.connexion = conn‬‬ ‫التصال ‪ socket‬مرجع #‬ ‫#36‬ ‫‪self.app = boss‬‬ ‫مرجع نافذة التطبيق #‬ ‫#46‬ ‫#56‬ ‫:)‪def run(self‬‬ ‫#66‬ ‫"‪"actions entreprises en réponse aux messages reçus du client‬‬ ‫#76‬ ‫)(‪nom = self.getName‬‬ ‫معرف العميل = اسم الخيط #‬ ‫#86‬ ‫:1 ‪while‬‬ ‫#96‬ ‫)"8‪msgClient = self.connexion.recv(1024).decode("Utf‬‬ ‫#07‬ ‫))‪print("**{0}** de {1}".format(msgClient, nom‬‬ ‫#17‬ ‫]0[)','(‪deb = msgClient.split‬‬ ‫#27‬ ‫:""== ‪if deb == "fin" or deb‬‬ ‫#37‬ ‫)‪self.app.enlever_canon(nom‬‬ ‫#47‬ ‫: علمة يبداية هذا المدفع للعملء الخرين #‬ ‫#57‬ ‫)(‪self.app.verrou.acquire‬‬ ‫#67‬ ‫:‪for cli in self.app.conn_client‬‬ ‫#77‬ ‫:‪if cli != nom‬‬ ‫#87‬ ‫)‪message = "départ_de,{0}".format(nom‬‬ ‫#97‬ ‫))"8‪self.app.conn_client[cli].send(message.encode("Utf‬‬ ‫#08‬ ‫)(‪self.app.verrou.release‬‬ ‫#18‬ ‫: إغلق هذا الموضوع #‬ ‫#28‬ ‫‪break‬‬ ‫#38‬ ‫:"‪elif deb =="client OK‬‬ ‫#48‬ ‫: علمة إلى عميل جديد أن المداقع مسجلة يبالفعل #‬

(multithreading )‫التصال عبر الشبكة وخاصية التعدد‬
85# 86# 87# 88# 89# 90# 91# 92# 93# 94# 95# 96# 97# 98# 99# 100# 101# 102# 103# 104# 105# 106# 107# 108# 109# 110# 111# 112# 113# 114# 115# 116# 117# 118# 119# 120# 121# 122# 123# 124# 125# 126# 127# 128# 129# 130# 131# 132# 133# 134# 135# 136# msg ="canons," for g in self.app.guns: gun = self.app.guns[g] msg =msg +"{0};{1};{2};{3};{4},".\ format(gun.id, gun.x1, gun.y1, gun.sens, gun.coul) self.app.verrou.acquire() self.connexion.send(msg.encode("Utf8")) # ‫'( انتظار الحصول على اعتراف‬OK') : self.connexion.recv(100).decode("Utf8") self.app.verrou.release() # ‫.إضافة مدفع إلى فضاء لعب الخادم‬ # ‫: السلوب الذي تم استدعاؤه يرجع صفات للمدفع الذي صنع‬ ُ x, y, sens, coul = self.app.ajouter_canon(nom) # ‫إرسال الصفات لهذا المدفع الجديد إلى كل العملء المتصلة‬

396

self.app.verrou.acquire() for cli in self.app.conn_client: msg ="nouveau_canon,{0},{1},{2},{3},{4}".\ format(nom, x, y, sens, coul) # ‫للعميل الجديد، أضف ظحقل مشير إلى أن‬ # ‫: الرسالة تتعلق يبالمدفع الخاص يبها‬ if cli == nom: msg =msg +",le_vôtre" self.app.conn_client[cli].send(msg.encode("Utf8")) self.app.verrou.release() elif deb =='feu': self.app.tir_canon(nom) # ‫: الشارة إلى هذا الفطلق للنار لجميع العملء الخرين‬ self.app.verrou.acquire() for cli in self.app.conn_client: if cli != nom: message = "tir_de,{0},".format(nom) self.app.conn_client[cli].send(message.encode("Utf8")) self.app.verrou.release() elif deb =="orienter": t =msgClient.split(',') # ‫: يمكن أن نستقبل العديد من الزوايا. نقوم يباستخدام الخيرة‬ self.app.orienter_canon(nom, t[-1]) # ‫: الشارة لهذه التغييرات لجميع العملء الخرين‬ self.app.verrou.acquire() for cli in self.app.conn_client: if cli != nom: # ‫: نقطة نهاية لن، الرسائل قد تكون مجمعة في يبعض الظحيان‬ message = "angle,{0},{1},".format(nom, t[-1]) self.app.conn_client[cli].send(message.encode("Utf8")) self.app.verrou.release() # ‫: إغلق التصال‬ self.connexion.close() # ‫قطع التصال‬ del self.app.conn_client[nom] # ‫ظحذف مرجعه في القاموس‬ self.app.afficher("Client %s déconnecté.\n" % nom) # ‫الخيط ينتهي هنا‬

(thread locks ) ‫تزامن الخيوط بالستخدام القفال‬ . ‫من خلل فحص الكود أعله، سوف تلحظ بنية معينة من كتل التعليمات الت يرسل الخادم نفس لرستتالة إلتتى جميتتع عملئتته‬ . 80 ‫على سبيل اللثال انظر إلى السطر من 47 إلى‬

‫793‬

‫لعبة القصف، نسخة الشبكة‬

‫السطر 57 يقوم ينشيط السلوب ‪ ()acquire‬لكائن "مغلق" تم إنشاؤه عن طريق النش للتطتتبيق الرئيستت )انظتتر أدنتتاه( .‬ ‫هذا الكائن هو ملثيل الصنف ‪ ,()Lock‬الذي هو جزء من وحدة ‪ threading‬الت قمنتتا باستتتدعائها فتتي بدايتتة الستتكريبت .‬ ‫السطر التالية )من 67 إلى 97 ( تسبب إرسال رسالة إلى كافة العملء التصلي )باستلثناء واحد( . ثم، يكون لكائن-القفل مسعى‬ ‫جديد، هذه الرة لسلوبه ‪.()release‬‬ ‫متتاذا يختتدم هتتذا كتتائن-القفتتل إذا ؟ بمتتا أنتته يتتتم صتتنعه متتن صتتنف متتن وحتتدة ‪ ,threading‬يمكنتتك تخميتت أن لتته فائتتدة‬ ‫للمواضيع . في الواقع، تستتتخدم هتتذه كائنتات-القفتل لزامنتتة الواضتتيع التامنتتة . متتا هتتو ؟هتتل تعلتتم أن الختتادم يبتدأ بموضتتوع‬ ‫مختلف لكل عميل متصل . ثم، تصبح كل هذه الواضيع تعمل بالتوازي . وبالتالي هنالك خطر في بعض الحيان، وهو ربما أن‬ ‫موضوعي أو أكث يمكن أن يستخدموا موردا مشتكا في نفس الوقت .‬ ‫فتتي الستطر البمجيتتة التتت ناقشتتناها، علتتى ستبيل اللثتتال، نحتن نتعامتتل متع موضتتوع يريتتد تقريبتتا استتتخدام جميتتع التصتتالت‬ ‫الوجودة لنش الرسالة . ولذلك من المكن أنه خلل هذا الوقت، موضوع آخر يريتد أن يستتخدم أيضتا واحتدة أو أخترى متن هتذه‬ ‫التصالت، والت قد يتسبب في عطب )أي تطابق بشكل فوضوي عدة رسائل( .‬ ‫يمكن حل هذه الشكلة باستخدام كائن-القفتتل )‪ . (thread lock‬هتتذا الكتتائن ل يتتتم إنشتتاؤه إل فتتي نستتخة واحتتدة، فتتي مستتاحة‬ ‫السماء الت في متناول جميع الواضيع التامنة . ويتمي أساسا في أنه دائما في حالة أو أخرى : مغلق أو غي مغلق . حتتالته‬ ‫الولية هي غي مغلق .‬ ‫االلستخدام‬ ‫عندما يكون أي موضوع على وعشك الوصتول إلتى متورد مشتت،ك، يتتم أول تفعيتل الستلوب ‪ ()acquire‬للقفتل . فتتإذا كتانت‬ ‫الحالة غي مغلق، يتم غلقه، ويمكن للموضوع الذي طلبه أن يستخدم مصادر مشتكة بأمان . عند ااإنتهاء متتن استتتخدام التتورد،‬ ‫فإنه سوف يقوم بتفعيل السلوب ‪ ()release‬للقفل، الذي سيقوم بفتح قفله )يكون غي مغلق( .‬ ‫في الواقع، إذا كان موضوع أخر يحاول تفعيتل هتتو أيضتا الستلوب ‪ ()acquire‬للقفتل، عنتدما يكتتون فتي حالتتة مقفتل، يكتتون‬ ‫السلوب "ليس في متناول يده"، مما يتسبب في منع هذا الوضوع، والذي يقوم بتعليق نشاطه حت يعود إلى حالت غي مقفل‬ ‫. وهذا بالتالي يمنع الوصول إلى مورد مشت،ك خلل الوقت الذي يستخدم فيه موضوع آخر . عندما يتم فتح القفتتل، واحتدة متتن‬ ‫الواضيع النتظار )قد يكون في الواقع أكث من واحد( يستأنف نشاطه أثناء إغلق القفل، وهكذا .‬ ‫يقوم كائن-القفل بحفظ مراجع الواضيع الذي قد منعها، بحيتث أنته يتتم إزالتة النتع لواحتد فقتط عنتدما يتتم استتدعاء الستلوب‬ ‫‪ ()release‬ويجب دائما لكل موضوع يتم تفعيله باستخدام السلوب ‪ ()acquire‬قبل الوصول إلى الوارد، ويجتتب عليتته‬ ‫نفعيل أسلوبه ‪ ()release‬بعد ذلك .‬

‫التصال عبر الشبكة وخاصية التعدد) ‪(multithreading‬‬

‫893‬

‫ش ط أن تكون جميع الواضيع التامنة تتبع نفس الجراء، هذه التقنية بسيطة تمنع إمكانية استخدام مورد مشت،ك فتتي وقتتت‬ ‫واحد من قبل العديد منهم . نقول قي هذه الحالة الواضيع قد تم مزامنتها .‬ ‫برنامج الخادم : إنهائه‬ ‫الصنفان بالسفل تكمل السكريبت الخادم . يتم تنفيذ التعليمات البمجيتتة فتتي الصتتنف ‪ ()ThreadClients‬مماثلتتة لتلتتك‬ ‫الت طورناها سابقا لجسم تطبيق برنامج الدردعشة . في هذه الحالة، ومع ذلتتك، وضتتعنا فتتي صتتنف مشتتتق متتن ‪,()Thread‬‬
‫211‬

‫لنه يحتتتاج إلتى تشتتغيل هتذا الكتود فتي موضتوع مستتتقل عتن التطتبيق الرئيستت . وبالفعتل تتم القبتض عليتته عتن طريتق حلقتة‬ ‫‪ ()mainloop‬للواجهة الرسومية .‬

‫يشتق الصنف ‪ ()AppServeur‬من صنف ‪ ()AppBombardes‬لوحدة 40‪ .canon‬ولقد أضتتفنا مجموعتتة متتن‬ ‫الساليب الكملة للقيام بتنفيذ جميع العمليات الت تنتج عن حوار مع العملء . لحظنا سابقا أن العملء يملثلون نسخة مشتتتقة‬ ‫من هذا الصنف )تمتع بنفس التعاريف الساسية للنافذة، اللوحة، إلخ( .‬
‫:)‪137# class ThreadClients(threading.Thread‬‬ ‫#831‬ ‫"""‪"""objet thread gérant la connexion de nouveaux clients‬‬ ‫#931‬ ‫:)‪def __init__(self, boss, connex‬‬ ‫#041‬ ‫)‪threading.Thread.__init__(self‬‬ ‫#141‬ ‫‪self.boss = boss‬‬ ‫مرجع نافذة التطبيق #‬ ‫#241‬ ‫‪self.connex = connex‬‬ ‫المبدئي ‪ socket‬مرجع #‬ ‫#341‬ ‫#441‬ ‫:)‪def run(self‬‬ ‫#541‬ ‫"‪"attente et prise en charge de nouvelles connexions clientes‬‬ ‫#641‬ ‫"‪txt ="Serveur prêt, en attente de requêtes ...\n‬‬ ‫#741‬ ‫)‪self.boss.afficher(txt‬‬ ‫#841‬ ‫)5(‪self.connex.listen‬‬ ‫#941‬ ‫: إدارة التصالت المطلويبة من قبل العملء #‬ ‫#051‬ ‫:1 ‪while‬‬ ‫#151‬ ‫)(‪nouv_conn, adresse = self.connex.accept‬‬ ‫#251‬ ‫: صنع كائن خيط جديد لصنع التصال #‬ ‫#351‬ ‫)‪th = ThreadConnexion(self.boss, nouv_conn‬‬ ‫#451‬ ‫)(‪th.start‬‬ ‫#551‬ ‫)(‪it = th.getName‬‬ ‫معرف فريد للخيط #‬ ‫#651‬ ‫: ظحفظ التصال في قاموس #‬ ‫#751‬ ‫)‪self.boss.enregistrer_connexion(nouv_conn, it‬‬ ‫#851‬ ‫: إظهاره #‬ ‫#951‬ ‫\% "‪txt = "Client %s connecté, adresse IP %s, port %s.\n‬‬ ‫#061‬ ‫)]1[‪(it, adresse[0], adresse‬‬ ‫#161‬ ‫)‪self.boss.afficher(txt‬‬ ‫#261‬ ‫: يبدء التواصل مع العميل #‬ ‫#361‬ ‫))"8‪nouv_conn.send("serveur OK".encode("Utf‬‬ ‫#461‬ ‫:)‪165# class AppServeur(AppBombardes‬‬ ‫#661‬ ‫""")‪"""fenêtre principale de l'application (serveur ou client‬‬ ‫#761‬ ‫:)‪def __init__(self, host, port, larg_c, haut_c‬‬ ‫#861‬ ‫‪self.host, self.port = host, port‬‬

‫211 سوف نن اقش هذا السؤال ف الصفح ات الق ادمة, لنه يفةتح بعض الوجه ات الاثية للهةتوم ام : انظر إل : تسي الرسوم‬ ‫الةتحركة ب اسةتخدام اليوط, صفحة 504.‬

399
169# 170# 171# 172# 173# 174# 175# 176# 177# 178# 179# 180# 181# 182# 183# 184# 185# 186# 187# 188# 189# 190# 191# 192# 193# 194# 195# 196# 197# 198# 199# 200# 201# 202# 203# 204# 205# 206# 207# 208# 209# 210# 211# 212# 213# 214# 215# 216# 217# 218# 219# 220# 221# 222# 223# 224# 225# 226# 227# 228# 229# AppBombardes.__init__(self, larg_c, haut_c) self.active =1 # ‫مؤشر النشاط‬ # ‫: تأكد من خروجك يبشكل صحيح عند إغلق النافذة‬ self.bind('',self.fermer_threads)

‫لعبة القصف، نسخة الشبكة‬

def specificites(self): "préparer les objets spécifiques de la partie serveur" self.master.title('>') # ‫: ويدجت نص، مرتبط مع شريط تمرير‬ st =Frame(self) self.avis =Text(st, width =65, height =5) self.avis.pack(side =LEFT) scroll =Scrollbar(st, command =self.avis.yview) self.avis.configure(yscrollcommand =scroll.set) scroll.pack(side =RIGHT, fill =Y) st.pack() # ‫: جزء خادم التصال‬ self.conn_client = {} # ‫قاموس اتصالت العميل‬ self.verrou =threading.Lock() # ‫قفل مزامنة الخيوط‬ # ‫ تهيئة الخادم - وضع‬socket : connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: connexion.bind((self.host, self.port)) except socket.error: txt ="La liaison du socket à l'hôte %s, port %s a échoué.\n" %\ (self.host, self.port) self.avis.insert(END, txt) self.accueil =None else: # ‫: يبدء خيط لمراقبة اتصال العملء‬ self.accueil = ThreadClients(self, connexion) self.accueil.start() def depl_aleat_canon(self, id): "déplacer aléatoirement le canon " x, y = AppBombardes.depl_aleat_canon(self, id) # ‫: الشارة لهذه الظحداثيات الجديدة لكافة العملء‬ self.verrou.acquire() for cli in self.conn_client: message = "mouvement_de,%s,%s,%s," % (id, x, y) self.conn_client[cli].send(message.encode("Utf8")) self.verrou.release() def goal(self, i, j): "le canon signale qu'il a atteint l'adversaire " AppBombardes.goal(self, i, j) # ‫: الشارة إلى النتائج الجديدة لكافة العملء‬ self.verrou.acquire() for cli in self.conn_client: msg ='scores,' for id in self.pupi: sc = self.pupi[id].valeur_score() msg = msg +"%s;%s," % (id, sc) self.conn_client[cli].send(msg.encode("Utf8")) time.sleep(.5) # ‫للتحسين نفصل الرسائل‬ self.verrou.release() def ajouter_canon(self, id): "instancier un canon et un pupitre de nom dans 2 dictionnaires"

(multithreading )‫التصال عبر الشبكة وخاصية التعدد‬
230# # on alternera ceux des 2 camps : 231# n = len(self.guns) 232# if n %2 ==0: 233# sens = -1 234# else: 235# sens = 1 236# x, y = self.coord_aleat(sens) 237# coul =('dark blue', 'dark red', 'dark green', 'purple', 238# 'dark cyan', 'red', 'cyan', 'orange', 'blue', 'violet')[n] 239# self.guns[id] = Canon(self.jeu, id, x, y, sens, coul) 240# self.pupi[id] = Pupitre(self, self.guns[id]) 241# self.pupi[id].inactiver() 242# return (x, y, sens, coul) 243# 244# def enlever_canon(self, id): 245# "retirer le canon et le pupitre dont l'identifiant est " 246# if self.active == 0: # ‫تم إغلق النافذة‬ 247# return 248# self.guns[id].effacer() 249# del self.guns[id] 250# self.pupi[id].destroy() 251# del self.pupi[id] 252# 253# def orienter_canon(self, id, angle): 254# "régler la hausse du canon à la valeur " 255# self.guns[id].orienter(angle) 256# self.pupi[id].reglage(angle) 257# 258# def tir_canon(self, id): 259# "déclencher le tir du canon " 260# self.guns[id].feu() 261# 262# def enregistrer_connexion(self, conn, it): 263# "Mémoriser la connexion dans un dictionnaire" 264# self.conn_client[it] = conn 265# 266# def afficher(self, txt): 267# "afficher un message dans la zone de texte" 268# self.avis.insert(END, txt) 269# 270# def fermer_threads(self, evt): 271# "couper les connexions existantes et fermer les threads" 272# # ‫: قطع التصالت مع جميع العملء‬ 273# for id in self.conn_client: 274# self.conn_client[id].send('fin'.encode("Utf8")) 275# # ‫: )فرض إنهاء خيط خادم انتظار الستعلمات )الطلبات‬ 276# if self.accueil != None: 277# self.accueil._stop() 278# self.active =0 # ‫ منع وصول إلى لظحقة‬Tk 279# 280# if __name__ =='__main__': 281# AppServeur(host, port, largeur, hauteur).mainloop()

400

‫104‬

‫لعبة القصف، نسخة الشبكة‬ ‫تعليقات‬

‫•السطر 371 : سيحدث من وقت لخر يريد "العتاض " على إغلق التطبيق التتذي قتتام الستتتخدم بتتالخروج متتن برنامجتتك،‬ ‫على سبيل اللثال لنك ترير إجباره بحفتظ نستبة متتن البيانتات الهمتتة فتتي ملتتف، أو غلتتق نوافتذ أخترى، إلتخ . فقتط اجعلتته‬ ‫يكشف عن العنص >‪ ، ‫أسلوب غير فعال‬ 66# 67# def goal(self, a, b): 68# pass # => ‫أسلوب غير فعال‬ 69# 70# 71# class ThreadSocket(threading.Thread): 72# """objet thread gérant l'échange de messages avec le serveur""" 73# def __init__(self, boss, host, port): 74# threading.Thread.__init__(self) 75# self.app = boss # ‫مرجع نافذة التطبيق‬ 76# # ‫ وضع‬socket - : ‫: اتصال يبالخادم‬ 77# self.connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 78# try: 79# self.connexion.connect((host, port)) 80# except socket.error: 81# print("La connexion a échoué.") 82# sys.exit() 83# print("Connexion établie avec le serveur.") 84# 85# def run(self): 86# while 1: 87# msg_recu = self.connexion.recv(1024).decode("Utf8") 88# print("*%s*" % msg_recu) 89# # le message reçu est d'abord converti en une liste : 90# t =msg_recu.split(',') 91# if t[0] =="" or t[0] =="fin": 92# # ‫: ظحذف هذا الخيط‬ 93# break 94# elif t[0] =="serveur OK": 95# self.connexion.send("client OK".encode("Utf8")) 96# elif t[0] =="canons": 97# self.connexion.send("OK".encode("Utf8")) # ‫اعتراف وصول‬ 98# # ‫.مسح أول واخر عنصر في القائمة‬ 99# # ‫: تبقي قوائم‬ 100# lc = t[1:-1] 101# # ‫: كل واظحد هو وصف كامل للمدفع‬ 102# for g in lc: 103# s = g.split(';') 104# self.app.ajouter_canon(s[0], s[1], s[2], s[3], s[4]) 105# elif t[0] =="nouveau_canon": 106# self.app.ajouter_canon(t[1], t[2], t[3], t[4], t[5]) 107# if len(t) >6: 108# self.app.activer_pupitre_personnel(t[1]) 109# elif t[0] =='angle': 110# # ‫.من الممكن أن نستقبل مجموعة من المعلومات المجمعة‬ 111# # ‫: لن نأخذ سوى الولى‬ 112# self.app.orienter_canon(t[1], t[2]) 113# elif t[0] =="tir_de": 114# self.app.tir_canon(t[1]) 115# elif t[0] =="scores": 116# # ‫.مسح أول واخر عنصر في القائمة‬ 117# # ‫: تبقي قوائم‬ 118# lc = t[1:-1] 119# # ‫: كل عنصر هو وصف نتيجة‬ 120# for g in lc: 121# s = g.split(';') 122# self.app.imposer_score(s[0], s[1])

‫التصال عبر الشبكة وخاصية التعدد) ‪(multithreading‬‬
‫#321‬ ‫:"‪elif t[0] =="mouvement_de‬‬ ‫#421‬ ‫)]3[‪self.app.deplacer_canon(t[1],t[2],t‬‬ ‫#521‬ ‫:"‪elif t[0] =="départ_de‬‬ ‫#621‬ ‫)]1[‪self.app.enlever_canon(t‬‬ ‫#721‬ ‫#821‬ ‫.ينتهي هنا >‪ ‬ ‫‪ ،‪ ،>> c‬‬ ‫:02 < ‪>>> while c‬‬ ‫...‬ ‫1+ ‪c = c‬‬ ‫...‬ ‫)7*‪print(c, "x 7 =", c‬‬

‫أو :‬
‫1 = ‪>>> c‬‬ ‫:02 =< ‪>>> while c‬‬ ‫...‬ ‫)7*‪print(c, "x 7 =", c‬‬ ‫...‬ ‫1+ ‪c = c‬‬

‫التمرين 3.4 :‬
‫1 = ‪>>> s‬‬ ‫:48361 =< ‪>>> while s‬‬ ‫...‬ ‫)")‪print(s, "euro(s) =", s *1.65, "dollar(s‬‬ ‫...‬ ‫2* ‪s = s‬‬

‫التمرين 4.4 :‬
‫1 ,1 = ‪>>> a, c‬‬ ‫:31 < ‪>>> while c‬‬ ‫...‬ ‫)‘ ’= ‪print(a, end‬‬ ‫...‬ ‫1+‪a, c = a *3, c‬‬

‫التمرين 6.4 :‬
‫: ‪# Le nombre de secondes est fourni au départ‬‬ ‫)!مطلوب عدد كبير ( #‬ ‫21987654321 = ‪nsd‬‬

‫ظحلول التمارين‬
# ‫:عدد الثواني في يوم واظحد‬ nspj = 3600 * 24 # ‫ عدد الثواني في السنة ) 563 يوما‬# ‫:)ل تأخذ في العتبار السنوات الكبيسة‬ nspa = nspj * 365 # ‫عدد الثواني في الشهر )على افتراض‬ # ‫:)أن كل شهر يبه 03 يوما‬ nspm = nspj * 30 # Nombre d'années contenues dans la durée fournie : na = nsd // nspa # division nsr = nsd % nspa # n. de sec. restantes # ‫:عدد الشهر المتبقية‬ nmo = nsr // nspm # division nsr = nsr % nspm # n. de sec. restantes # ‫:عدد اليام المتبقية‬ nj = nsr // nspj # division nsr = nsr % nspj # n. de sec. restantes # ‫:عدد الساعات المتبقية‬ nh = nsr // 3600 # division nsr = nsr % 3600 # n. de sec. restantes # ‫:عدد الدقائق المتبقية‬ nmi = nsr // 60 # division nsr = nsr % 60 # n. de sec. restantes print("Nombre de secondes à convertir :", nsd) print("Cette durée correspond à", na, "années de 365 jours, plus") print(nmo, "mois de 30 jours,", end=' ') print(nj, "jours,", end=' ') print(nh, "heures,", end=' ') print(nmi, "minutes et", end=' ') print(nsr, "secondes.")

418

: 4.7 ‫التمرين‬
# affichage des 20 premiers termes de la table par 7, # avec signalement des multiples de 3 : i = 1 # compteur : prendra successivement les valeurs de 1 à 20 while i < 21: # calcul du terme à afficher : t = i * 7 # affichage sans saut à la ligne (utilisation de la virgule) : print(t, end =’ ‘) # ce terme est-il un multiple de 3 ? (utilisation de l'opérateur modulo) : if t % 3 == 0: print("*", end =’ ‘) # affichage d'une astérisque dans ce cas i = i + 1 # incrémentation du compteur dans tous les cas

: 5.1 ‫التمرين‬
# # # # # Conversion degrés -> radians Rappel : un angle de 1 radian est un angle qui correspond à une portion de circonférence de longueur égale à celle du rayon. Puisque la circonférence vaut 2 pi R, un angle de 1 radian correspond à 360° / 2 pi , ou encore à 180° / pi

419
# Angle fourni au départ en degrés, minutes, secondes : deg, min, sec = 32, 13, 49 # Conversion des secondes en une fraction de minute : fm = sec/60 # Conversion des minutes en une fraction de degré : fd = (min + fm)/60 # Valeur de l'angle en degrés "décimalisés" : ang = deg + fd # Valeur de pi : pi = 3.14159265359 # Valeur d'un radian en degrés : rad = 180 / pi # Conversion de l'angle en radians : arad = ang / rad # Affichage : print(deg, "°", min, "'", sec, '" =', arad, "radian(s)")

‫ظحلول التمارين‬

: 5.3 ‫التمرين‬
# ‫تحويل °الفهرنهايت >-< °السيليزي‬ # ‫: أ( درجة الحرارة يبـ °س‬ tempC = 25 # ‫: التحويل إلى °فهرنهايت‬ tempF = tempC * 1.8 + 32 # ‫: عرض‬ print(tempC, "°C =", tempF, "°F") # ‫: ب( درجة الحرارة يبـ °ف‬ tempF = 25 # ‫: التحويل إلى °سيليزي‬ tempC = (tempF - 32) / 1.8 # ‫: عرض‬ print(tempF, "°F =", tempC, "°C")

: 5.5 ‫التمرين‬ n g # # = 1 # ‫عدد المريبعات‬ = 1 # nombre de grains à y déposer Pour la variante, il suffit de définir g comme en remplaçant la ligne ci-dessus par : g = 1.

while n < 65 : print(n, g) n, g = n+1, g*2

: 5.6 ‫التمرين‬
# ‫البحث عن ظحرف معين في السلسلة‬ # ‫:السلسلة المعطاة‬ ch = "Monty python flying circus" # ‫:مفتاح البحث‬ cr = "e"

‫ظحلول التمارين‬
# ‫:البحث الصحيح‬ lc = len(ch) # ‫عدد الظحرف التي سيتم اختبارها‬ i = 0 # indice du caractère en cours d'examen t = 0 # "drapeau" à lever si le caractère recherché est présent while i < lc: if ch[i] == cr: t = 1 i = i + 1 # ‫:عرض‬ print("Le caractère", cr, end =’ ‘) if t == 1: print("est présent", end =’ ‘) else: print("est inrouvable", end =’ ‘) print("dans la chaîne", ch)

420

: 5.8 ‫التمرين‬
# ‫إدراج ظحرف مسافة في سلسلة‬ # ‫:السلسلة المعطاة‬ ch = "Véronique" # ‫:إدراج الحرف‬ cr = "*" # Le nombre de caractères à insérer est inférieur d'une unité au # nombre de caractères de la chaîne. On traitera donc celle-ci à # partir de son second caractère (en omettant le premier). lc = len(ch) # ‫إجمالي عدد الظحرف‬ i = 1 # indice du premier caractère à examiner (le second, en fait) nch = ch[0] # nouvelle chaîne à construire (contient déjà le premier car.) while i < lc: nch = nch + cr + ch[i] i = i + 1 # ‫:عرض‬ print(nch)

: 5.9 ‫التمرين‬
# ‫عكس سلسلة أظحرف‬ # ‫:السلسلة المعطاة‬ ch = "zorglub" lc = len(ch) # ‫عدد الظحرف الجمالي‬ i = lc - 1 # ‫البدأ من الحرف الخير‬ nch = "" # ‫لبدأ سلسلة جديدة فارغة‬ while i >= 0: nch = nch + ch[i] i = i - 1 # ‫:عرض‬ print(nch)

: 5.11 ‫التمرين‬
# ‫مزج قائمتين في واظحدة‬

421
# ‫: القوائم المعطاة‬ t1 = [31,28,31,30,31,30,31,31,30,31,30,31] t2 = ['Janvier','Février','Mars','Avril','Mai','Juin', 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'] # ‫:عمل قائمة جديدة فارغة‬ t3 = [] # ‫: تجهيز ظحلقة‬ i = 0 while i < len(t1): t3.append(t2[i]) t3.append(t1[i]) i = i + 1 # ‫:عرض‬ print(t3)

‫ظحلول التمارين‬

: 5.12 ‫التمرين‬
# ‫عرض العناصر في قائمة‬ # ‫:القائمة المعطاة‬ t2 = ['Janvier','Février','Mars','Avril','Mai','Juin', 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'] # ‫:عرض‬ i = 0 while i < len(t2): print(t2[i], end =’ ‘) i = i + 1

: 5.13 ‫التمرين‬
# ‫البحث عن أكبر عدد في قائمة‬ # ‫: القائمة المعطاة‬ tt = [32, 5, 12, 8, 3, 75, 2, 15] # Au fur et à mesure du traitement de la liste, on mémorisera dans # la variable ci-dessous la valeur du plus grand élément déjà trouvé : max = 0 # ‫: استعراض لجميع العناصر‬ i = 0 while i < len(tt): if tt[i] > max: max = tt[i] # ‫تخزين أكبر عدد الجديد‬ i = i + 1 # ‫:عرض‬ print("Le plus grand élément de cette liste a la valeur", max)

: 5.14 ‫التمرين‬
# ‫فصل العداد الفردية والزوجية‬ # ‫: القوائم المعطاة‬ tt = [32, 5, 12, 8, 3, 75, 2, 15]

‫ظحلول التمارين‬ pairs = [] impairs = [] # ‫: استعراض لجميع العناصر‬ i = 0 while i < len(tt): if tt[i] % 2 == 0: pairs.append(tt[i]) else: impairs.append(tt[i]) i = i + 1 # ‫:عرض‬ print("Nombres pairs :", pairs) print("Nombres impairs :", impairs)

422

: 6.1 ‫التمرين‬
# ‫تحويل ميل/ساعة إلى كم/ساعة و متر/ثانية‬ print("Veuillez entrer le nombre de miles parcourus en une heure : ", end =’ ‘) ch = input() mph = float(ch) # ‫تحويل سلسلة لرقم ظحقيقي‬ mps = mph * 1609 / 3600 # ‫التحويل لمتر في الثانية‬ kmph = mph * 1.609 # ‫التحويل لكيلومتر في الساعة‬ # ‫:عرض‬ print(mph, "miles/heure =", kmph, "km/h, ou encore", mps, "m/s")

: 6.2 ‫التمرين‬
# ‫محيط ومساظحة أي مثلث‬ from math import sqrt print("Veuillez entrer le côté a : ") a = float(input()) print("Veuillez entrer le côté b : ") b = float(input()) print("Veuillez entrer le côté c : ") c = float(input()) d = (a + b + c)/2 # ‫نصف المحيط‬ s = sqrt(d*(d-a)*(d-b)*(d-c)) # ‫)المساظحة )اعتمادا على معادلة‬ print("Longueur des côtés =", a, b, c) print("Périmètre =", d*2, "Aire =", s)

: 6.4 ‫التمرين‬
# ‫إدخال عناصر في قائمة‬ tt = [] # ‫القائمة الكاملة فارغة‬ ch = "start" # ‫)أي قيمة )ما عدا اللشيء‬ while ch != "": print("Veuillez entrer une valeur : ") ch = input() if ch != "":

423 tt.append(float(ch)) # ‫:عرض القائمة‬ print(tt) # ‫ : مختلف عن‬tt.append(ch)

‫ظحلول التمارين‬

: 6.8 ‫التمرين‬
# Traitement de nombres entiers compris entre deux limites print("Veuillez entrer a = eval(input()) print("Veuillez entrer b = eval(input()) s = 0 # Parcours de la série n = a while n boîte cubique elif x3 == -1 : return x1*x1*x2 # deux arguments -> boîte prismatique else : return x1*x2*x3 # ‫:التجريبة‬ print(volBoite()) print(volBoite(5.2)) print(volBoite(5.2, 3)) print(volBoite(5.2, 3, 7.4))

: 7.16 ‫التمرين‬ def changeCar(ch, ca1, ca2, debut =0, fin =-1): "Remplace tous les caractères ca1 par des ca2 dans la chaîne ch"

427 if fin == -1: fin = len(ch) nch, i = "", 0 while i < len(ch) if i >= debut nch = nch else : nch = nch i = i + 1 return nch # ‫:التجريبة‬ print((changeCar("Ceci print((changeCar("Ceci print((changeCar("Ceci print((changeCar("Ceci

‫ظحلول التمارين‬

# nch : nouvelle chaîne à construire : and i = debut and i max: max = lst[i] i = i + 1 return max # ‫:التجريبة‬ serie = [9, 3, 6, 1, 7, 5, 4, 8, 2] print(eleMax(serie)) print(eleMax(serie, 2, 5)) print(eleMax(serie, 2)) print(eleMax(serie, fin =3, debut =1))

: 8.7 ‫التمرين‬ from tkinter import * # ‫ إظحداثيات‬X,Y ‫: لـ 5 ظحلقات‬ coord = [[20,30], [120,30], [220, 30], [70,80], [170,80]] # ‫: ألوان الـ 5 ظحلقات‬ coul = ["red", "yellow", "blue", "green", "black"] base = Tk() can = Canvas(base, width =335, height =200, bg ="white") can.pack() bou = Button(base, text ="Quitter", command =base.quit) bou.pack(side = RIGHT) # ‫: رسم الـ 5 ظحلقات‬ i = 0 while i < 5: x1, y1 = coord[i][0], coord[i][1] can.create_oval(x1, y1, x1+100, y1 +100, width =2, outline =coul[i]) i = i +1 base.mainloop()

‫ظحلول التمارين‬

428 :‫للتنويع‬

from tkinter import * # ‫: رسم الـ 5 ظحلقات‬ def dessineCercle(i): x1, y1 = coord[i][0], coord[i][1] can.create_oval(x1, y1, x1+100, y1 +100, width =2, outline =coul[i]) def a1(): dessineCercle(0) def a2(): dessineCercle(1) def a3(): dessineCercle(2) def a4(): dessineCercle(3) def a5(): dessineCercle(4) # ‫ إظحداثيات‬X,Y ‫: لـ 5 ظحلقات‬ coord = [[20,30], [120,30], [220, 30], [70,80], [170,80]] # ‫: ألوان الـ 5 ظحلقات‬ coul = ["red", "yellow", "blue", "green", "black"] base = Tk() can = Canvas(base, width =335, height =200, bg ="white") can.pack() bou = Button(base, text ="Quitter", command =base.quit) bou.pack(side = RIGHT) # ‫:تركيب 5 أزرار‬ Button(base, text='1', Button(base, text='2', Button(base, text='3', Button(base, text='4', Button(base, text='5', base.mainloop() command command command command command = = = = = a1).pack(side a2).pack(side a3).pack(side a4).pack(side a5).pack(side =LEFT) =LEFT) =LEFT) =LEFT) =LEFT)

429

‫ظحلول التمارين‬ : 8.10 ‫التمرينان 9.8 و‬

# Dessin d'un damier, avec placement de pions au hasard from tkinter import * from random import randrange # générateur de nombres aléatoires

def damier(): "dessiner dix lignes de carrés avec décalage alterné" y = 0 while y < 10: if y % 2 == 0: # une fois sur deux, on x = 0 # commencera la ligne de else: # carrés avec un décalage x = 1 # de la taille d'un carré ligne_de_carres(x*c, y*c) y += 1 def ligne_de_carres(x, y): "dessiner une ligne de carrés, en partant de x, y" i = 0 while i < 5: can.create_rectangle(x, y, x+c, y+c, fill='navy') i += 1 x += c*2 # espacer les carrés def cercle(x, y, r, coul): "dessiner un cercle de centre x,y et de rayon r" can.create_oval(x-r, y-r, x+r, y+r, fill=coul) def ajouter_pion(): "dessiner un pion au hasard sur le damier" # tirer au hasard les coordonnées du pion : x = c/2 + randrange(10) * c y = c/2 + randrange(10) * c cercle(x, y, c/3, 'red') ##### Programme principal : ############ # # # # Tâchez de bien "paramétrer" vos programmes, comme nous l'avons fait dans ce script. Celui-ci peut en effet tracer des damiers de n'importe quelle taille en changeant seulement la valeur d'une seule variable, à savoir la dimension des carrés : # taille des carrés

c = 30

fen = Tk() can = Canvas(fen, width =c*10, height =c*10, bg ='ivory') can.pack(side =TOP, padx =5, pady =5) b1 = Button(fen, text ='damier', command =damier) b1.pack(side =LEFT, padx =3, pady =3) b2 = Button(fen, text ='pions', command =ajouter_pion) b2.pack(side =RIGHT, padx =3, pady =3) fen.mainloop()#

: 8.12 ‫التمرين‬
# Simulation du phénomène de gravitation universelle

‫ظحلول التمارين‬ from tkinter import * from math import sqrt def distance(x1, y1, x2, y2): "distance séparant les points x1,y1 et x2,y2" d = sqrt((x2-x1)**2 + (y2-y1)**2) # théorème de Pythagore return d def forceG(m1, m2, di): "force de gravitation s'exerçant entre m1 et m2 pour une distance di" return m1*m2*6.67e-11/di**2 # ‫قانون نيوتن‬ def avance(n, gd, hb): "déplacement de l'astre n, de gauche à droite ou de haut en bas" global x, y, step # ‫: الظحداثيات الجديدة‬ x[n], y[n] = x[n] +gd, y[n] +hb # déplacement du dessin dans le canevas : can.coords(astre[n], x[n]-10, y[n]-10, x[n]+10, y[n]+10) # calcul de la nouvelle interdistance : di = distance(x[0], y[0], x[1], y[1]) # conversion de la distance "écran" en distance "astronomique" : diA = di*1e9 # (1 pixel => 1 million de km) # calcul de la force de gravitation correspondante : f = forceG(m1, m2, diA) # affichage des nouvelles valeurs de distance et force : valDis.configure(text="Distance = " +str(diA) +" m") valFor.configure(text="Force = " +str(f) +" N") # adaptation du "pas" de déplacement en fonction de la distance : step = di/10 def gauche1(): avance(0, -step, 0) def droite1(): avance(0, step, 0) def haut1(): avance(0, 0, -step) def bas1(): avance(0, 0, step) def gauche2(): avance(1, -step, 0) def droite2(): avance (1, step, 0) def haut2(): avance(1, 0, -step) def bas2(): avance(1, 0, step) # Masses des deux astres : m1 = 6e24 # (valeur de la masse de la terre, en kg) m2 = 6e24 # astre = [0]*2 # liste servant à mémoriser les références des dessins x =[50., 350.] # liste des coord. X de chaque astre (à l'écran) y =[100., 100.] # liste des coord. Y de chaque astre

430

431 step =10 # "pas" de déplacement initial

‫ظحلول التمارين‬

# Construction de la fenêtre : fen = Tk() fen.title(' Gravitation universelle suivant Newton') # Libellés : valM1 = Label(fen, text="M1 = " +str(m1) +" kg") valM1.grid(row =1, column =0) valM2 = Label(fen, text="M2 = " +str(m2) +" kg") valM2.grid(row =1, column =1) valDis = Label(fen, text="Distance") valDis.grid(row =3, column =0) valFor = Label(fen, text="Force") valFor.grid(row =3, column =1) # Canevas avec le dessin des 2 astres: can = Canvas(fen, bg ="light yellow", width =400, height =200) can.grid(row =2, column =0, columnspan =2) astre[0] = can.create_oval(x[0]-10, y[0]-10, x[0]+10, y[0]+10, fill ="red", width =1) astre[1] = can.create_oval(x[1]-10, y[1]-10, x[1]+10, y[1]+10, fill ="blue", width =1) # 2 groupes de 4 boutons, chacun installé dans un cadre (frame) : fra1 = Frame(fen) fra1.grid(row =4, column =0, sticky =W, padx =10) Button(fra1, text="", fg ='red', command =droite1).pack(side =LEFT) Button(fra1, text="^", fg ='red', command =haut1).pack(side =LEFT) Button(fra1, text="v", fg ='red', command =bas1).pack(side =LEFT) fra2 = Frame(fen) fra2.grid(row =4, column =1, sticky =E, padx =10) Button(fra2, text="", fg ='blue', command =droite2).pack(side =LEFT) Button(fra2, text="^", fg ='blue', command =haut2).pack(side =LEFT) Button(fra2, text="v", fg ='blue', command =bas2).pack(side =LEFT) fen.mainloop()

‫ظحلول التمارين‬

432 : 8.16 ‫التمرين‬

# ‫تحويل درجات الحرارة فهرنهايت >=< سيليزي‬ from tkinter import * def convFar(event): "valeur de cette température, exprimée en degrés Fahrenheit" tF = eval(champTC.get()) varTF.set(str(tF*1.8 +32)) def convCel(event): "valeur de cette température, exprimée en degrés Celsius" tC = eval(champTF.get()) varTC.set(str((tC-32)/1.8)) fen = Tk() fen.title('Fahrenheit/Celsius') Label(fen, text='Temp. Celsius :').grid(row =0, column =0) # "variable tkinter" associée au champ d'entrée. Cet "objet-variable" # assure l'interface entre TCL et Python (voir notes, page 165) : varTC =StringVar() champTC = Entry(fen, textvariable =varTC) champTC.bind("", convFar) champTC.grid(row =0, column =1) # ‫ تهيئة محتويات متغير‬tkinter : varTC.set("100.0") Label(fen, text='Temp. Fahrenheit :').grid(row =1, column =0) varTF =StringVar() champTF = Entry(fen, textvariable =varTF) champTF.bind("", convCel) champTF.grid(row =1, column =1) varTF.set("212.0") fen.mainloop()

: 8.20 ‫التمرينان 81.8 و‬
# Cercles et courbes de Lissajous from tkinter import * from math import sin, cos def move(): global ang, x, y # on mémorise les coordonnées précédentes avant de calculer les nouvelles : xp, yp = x, y # rotation d'un angle de 0.1 radian : ang = ang +.1 # sinus et cosinus de cet angle => coord. d'un point du cercle trigono. x, y = sin(ang), cos(ang) # Variante déterminant une courbe de Lissajous avec f1/f2 = 2/3 : # x, y = sin(2*ang), cos(3*ang) # mise à l'échelle (120 = rayon du cercle, (150,150) = centre du canevas) x, y = x*120 + 150, y*120 + 150 can.coords(balle, x-10, y-10, x+10, y+10) can.create_line(xp, yp, x, y, fill ="blue") # ‫تتبع المسار‬

433 ang, x, y = 0., 150., 270. fen = Tk() fen.title('Courbes de Lissajous') can = Canvas(fen, width =300, height=300, bg="white") can.pack() balle = can.create_oval(x-10, y-10, x+10, y+10, fill='red') Button(fen, text='Go', command =move).pack() fen.mainloop()

‫ظحلول التمارين‬

: 8.27 ‫التمرين‬
# ‫سقوط وترتد‬ from tkinter import * def move(): global x, y, v, dx, dv, flag xp, yp = x, y # mémorisation des coord. précédentes # ‫: ظحركة أفقية‬ if x > 385 or x < 15 : # ‫:الرتداد على الجدران الجانبية‬ dx = -dx # ‫عكس الحركة‬ x = x + dx # ‫:)اختلف السرعة العمودية )دائما للسفل‬ v = v + dv # déplacement vertical (proportionnel à la vitesse) y = y + v if y > 240: # ‫: مستوى سطح الرض 042 يبكسل‬ y = 240 # défense d'aller + loin ! v = -v # ‫ارتداد: يتم عكس السرعة‬ # ‫:إعادة الكرة‬ can.coords(balle, x-10, y-10, x+10, y+10) # ‫:رسم المسار‬ can.create_line(xp, yp, x, y, fill ='light grey') # ... et on remet ça jusqu'à plus soif : if flag > 0: fen.after(50,move)

‫ظحلول التمارين‬ def start(): global flag flag = flag +1 if flag == 1: move() def stop(): global flag flag =0 # ‫:إظحداثيات التهيئة والسرعة والتحكم الرسوم المتحركة‬ x, y, v, dx, dv, flag = 15, 15, 0, 6, 5, 0 fen = Tk() fen.title(' Chutes et rebonds') can = Canvas(fen, width =400, height=250, bg="white") can.pack() balle = can.create_oval(x-10, y-10, x+10, y+10, fill='red') Button(fen, text='Start', command =start).pack(side =LEFT, padx =10) Button(fen, text='Stop', command =stop).pack(side =LEFT) Button(fen, text='Quitter', command =fen.quit).pack(side =RIGHT, padx =10) fen.mainloop()

434

(‫التمرين 33.8 )لعبة اللثعبان‬ Nous ne fournissons ici qu’une première ébauche du script : le principe d’animation du « serpent ». Si le cœur vous en dit, vous pouvez continuer le développement pour en faire un ! véritable jeu, mais c’est du travail from tkinter import * # === ‫: تحديد يبعض معالجات الظحداث‬ def start_it():

435
"Démarrage de l'animation" global flag if flag ==0: flag =1 move() def stop_it(): "Arrêt de l'animation" global flag flag =0 def go_left(event =None): "délacement vers la gauche" global dx, dy dx, dy = -1, 0 def go_right(event =None): global dx, dy dx, dy = 1, 0 def go_up(event =None): "déplacement vers le haut" global dx, dy dx, dy = 0, -1 def go_down(event =None): global dx, dy dx, dy = 0, 1

‫ظحلول التمارين‬

def move(): "Animation du serpent par récursivité" global flag # Principe du mouvement opéré : on déplace le carré de queue, dont les # caractéristiques sont mémorisées dans le premier élément de la liste # , de manière à l'amener en avant du carré de tête, dont les # caractéristiques sont mémorisées dans le dernier élément de la liste. # On définit ainsi un nouveau carré de tête pour le serpent, dont on # mémorise les caractéristiques en les ajoutant à la liste. # Il ne reste plus qu'à effacer alors le premier élément de la liste, # et ainsi de suite ... : c = serp[0] # extraction des infos concernant le carré de queue cq = c[0] # réf. de ce carré (coordonnées inutiles ici) l =len(serp) # longueur actuelle du serpent (= n. de carrés) c = serp[l-1] # extraction des infos concernant le carré de tête xt, yt = c[1], c[2] # ‫إظحداثيات المريبع‬ # Préparation du déplacement proprement dit. # (cc est la taille du carré. dx & dy indiquent le sens du déplacement) : xq, yq = xt+dx*cc, yt+dy*cc # coord. du nouveau carré de tête # Vérification : a-t-on atteint les limites du canevas ? : if xqcanX-cc or yqcanY-cc: flag =0 # => arrêt de l'animation can.create_text(canX/2, 20, anchor =CENTER, text ="Perdu !!!", fill ="red", font="Arial 14 bold") can.coords(cq, xq, yq, xq+cc, yq+cc) # déplacement effectif serp.append([cq, xq, yq]) # mémorisation du nouveau carré de tête del(serp[0]) # effacement (retrait de la liste) # Appel récursif de la fonction par elle-même (=> boucle d'animation) : if flag >0: fen.after(50, move) # === ‫======== :البرنامج الرئيسي‬

‫ظحلول التمارين‬
# Variables globales modifiables par certaines fonctions : flag =0 # commutateur pour l'animation dx, dy = 1, 0 # indicateurs pour le sens du déplacement # Autres variables globales : canX, canY = 500, 500 # dimensions du canevas x, y, cc = 100, 100, 15 # coordonnées et coté du premier carré # Création de l'espace de jeu (fenêtre, canevas, boutons ...) : fen =Tk() can =Canvas(fen, bg ='dark gray', height =canX, width =canY) can.pack(padx =10, pady =10) bou1 =Button(fen, text="Start", width =10, command =start_it) bou1.pack(side =LEFT) bou2 =Button(fen, text="Stop", width =10, command =stop_it) bou2.pack(side =LEFT) # Association de gestionnaires d'événements aux touches fléchées du clavier : fen.bind("", go_left) # Attention : les événements clavier fen.bind("", go_right) # doivent toujours être associés à la fen.bind("", go_up) # fenêtre principale, et non au canevas fen.bind("", go_down) # ou à un autre widget. # Création du serpent initial (= ligne de 5 carrés). # On mémorisera les infos concernant les carrés créés dans une liste de listes : serp =[] # liste vide # Création et mémorisation des 5 carrés : le dernier (à droite) est la tête. i =0 while i on mémorise

nomF = input("Nom du fichier à traiter : ") codeP = input("Code postal à rechercher : ") fi = open(nomF, 'r') while 1: ligne = fi.readline() if ligne =="": break if chercheCP(ligne) == codeP: print(ligne) fi.close()

: (découpage d’une chaîne en fragments) 10.2 ‫التمرين‬ def decoupe(ch, n): "découpage de la chaîne ch en une liste de fragments de n caractères" d, f = 0, n # indices de début et de fin de fragment

‫ظحلول التمارين‬ tt = [] while d < len(ch): if f > len(ch): f = len(ch) fr = ch[d:f] tt.append(fr) d, f = f, f +n return tt def inverse(tt): "rassemble les éléments ch = "" i = len(tt) while i > 0 : i = i - 1 ch = ch + tt[i] return ch # liste à construire # on ne peut pas découper au-delà de la fin # découpage d'un fragment # ajout du fragment à la liste # indices suivants

442

de la liste tt dans l'ordre inverse" # chaîne à construire # on commence par la fin de la liste # le dernier élément possède l'indice n -1

# Test : if __name__ == '__main__': ch ="abcdefghijklmnopqrstuvwxyz123456789âêîôûàèìòùáéíóú" liste = decoupe(ch, 5) print("chaîne initiale :") print(ch) print("liste de fragments de 5 caractères :") print(liste) print("fragments rassemblés après inversion de la liste :") print(inverse(liste))

443

‫ظحلول التمارين‬ : 10.4 ‫التمرينان 3.01 و‬

# Rechercher l'indice d'un caractère donné dans une chaîne def trouve(ch, car, deb=0): "trouve l'indice du caractère car dans la chaîne ch" i = deb while i < len(ch): if ch[i] == car: return i # le caractère est trouvé -> on termine i = i + 1 return -1 # toute la chaîne a été scannée sans succès # Test : if __name__ == '__main__': print(trouve("Coucou c'est moi", "z")) print(trouve("Juliette & Roméo", "&")) print(trouve("César & Cléopâtre", "r", 5))

: 10.5 ‫التمرين‬
# Comptage des occurrences d'un caractère donné dans une chaîne def compteCar(ch, car): "trouve l'indice du caractère car dans la chaîne ch" i, nc = 0, 0 # initialisations while i < len(ch): if ch[i] == car: nc = nc + 1 # caractère est trouvé -> on incrémente le compteur i = i + 1 return nc # Test : if __name__ == '__main__': print(compteCar("ananas au jus", "a")) print(compteCar("Gédéon est déjà là", "é")) print(compteCar("Gédéon est déjà là", "à"))

: 10.6 ‫التمرين‬ prefixes, suffixe = "JKLMNOP", "ack" for p in prefixes: print(p + suffixe )

: 10.7 ‫التمرين‬ def compteMots(ch): "comptage du nombre de mots dans la chaîne ch" if len(ch) ==0: return 0 nm = 1 # la chaîne comporte au moins un mot for c in ch: if c == " ": # il suffit de compter les espaces nm = nm + 1 return nm

‫ظحلول التمارين‬
# Test : if __name__ == '__main__': print(compteMots("Les petits ruisseaux font les grandes rivières"))

444

: 10.8 ‫التمرين‬ def compteCar(ch, car): "comptage du nombre de caractères la chaîne " if len(ch) ==0: return 0 n =0 for c in ch: if c == car: n = n + 1 return n # Programme principal : def compteCarDeListe(chaine, serie): "dans la chaine , comptage du nombre de caractères listés dans " for cLi in serie: nc =compteCar(chaine, cLi) print("Caractère", cLi, ":", nc) # Test : if __name__ == '__main__': txt ="René et Célimène étaient eux-mêmes nés à Noël de l'année dernière" print(txt) compteCarDeListe(txt, "eéèêë")

: 10.9 ‫التمرين‬ def estUnChiffre(car): "renvoie si le caractère 'car' est un chiffre" if car in "0123456789": return "vrai" else: return "faux" # Test : if __name__ == '__main__': caracteres ="d75è8b0â1" print("Caractères à tester :", caracteres) for car in caracteres: print(car, estUnChiffre(car))

: 10.10 ‫التمرين‬ def estUneMaj(car): "renvoie si le caractère 'car' est une majuscule" if car in "ABCDEFGHIJKLMNOPQRSTUVWXYZÀÂÉÈÊËÇÎÏÙÜÛÔÖ": return True else: return False

445
# Test : if __name__ == '__main__': caracteres ="eÀçMöSÖÛmÇéùT" print("Caractères à tester :", caracteres) for car in caracteres: print(car, estUneMaj(car))

‫ظحلول التمارين‬

: 10.11 ‫التمرين‬ def chaineListe(ch): "convertit la chaîne ch en une liste de mots" liste, ct = [], "" # ct est une chaîne temporaire for c in ch: # examiner tous les caractères de ch if c == " ": # lorsqu'on rencontre un espace, liste.append(ct) # on ajoute la chaîne temporaire à la liste ct = "" # ... et on ré-initialise la chaîne temporaire else: # les autres caractères examinés sont ajoutés à la chaîne temp. : ct = ct + c # Ne pas oublier le mot restant après le dernier espace ! : if ct: # vérifier si ct n'est pas une chaîne vide liste.append(ct) return liste # renvoyer la liste ainsi construite # Tests : if __name__ == '__main__': li = chaineListe("René est un garçon au caractère héroïque") print(li) for mot in li: print(mot, "-", end=' ') print(chaineListe("")) # doit renvoyer une liste vide

: (utilise les deux fonctions définies dans les exercices précédents ) 10.12 ‫التمرين‬ from exercice_10_10 import estUneMaj from exercice_10_11 import chaineListe txt = "Le prénom de cette Dame est Élise" print("Phrase à tester :", txt) lst = chaineListe(txt) for mot in lst: prem = mot[0] if estUneMaj(prem): print(mot) # convertir la phrase en une liste de mots # analyser chacun des mots de la liste # extraction du premier caractère # test de majuscule

# Variante plus compacte, utilisant la composition : print("Variante :") for mot in lst: if estUneMaj(mot[0]): print(mot)

: (utilise les deux fonctions définies dans les exercices précédents ) 10.13 ‫التمرين‬ from exercice_10_10 import estUneMaj

‫ظحلول التمارين‬ from exercice_10_11 import chaineListe def compteMaj(ch): "comptage des mots débutant par une majuscule dans la chaîne ch" c = 0 lst = chaineListe(ch) # convertir la phrase en une liste de mots for mot in lst: # analyser chacun des mots de la liste if estUneMaj(mot[0]): c = c +1 return c # Test : if __name__ == '__main__': phrase = "Les filles Tidgoutt se nomment Joséphine, Justine et Corinne" print("Phrase à tester : ", phrase) print("Cette phrase contient", compteMaj(phrase), "majuscules.")

446

: (ASCII ‫التمرين 41.01 )جدول محارف‬
# Table des codes ASCII c = 32 # premier code ASCII

while c < 128 : # dernier code strictement ASCII = 127 print("Code", c, ":", chr(c), end =" - ") c = c + 1

: (échange des majuscules et des minuscules) 10.16 ‫التمرين‬ def convMajMin(ch): "échange les majuscules et les minuscules dans la chaîne ch" nouvC = "" # chaîne à construire for car in ch: code = ord(car) # les codes numériques des caractères majuscules et minuscules # correspondants sont séparés de 32 unités : if code >= 65 and code = 192 and code = 97 and code = 224 and code Utf8 (variante utilisant une variable fiSource = input("Nom du fichier à traiter (Latin-1) : ") fiDest = input("Nom du fichier destinataire (Utf-8) : ") fs = open(fiSource, 'rb') # mode de lecture fd = open(fiDest, 'wb') # mode d'écriture while 1: so = fs.readline() # la ligne lue est une séquence d'octets # Remarque : la variable so étant du type , on doit la comparer # avec une chaîne littérale (vide) du même type dans les tests : if so == b"":

449 break ch = so.decode("Latin-1") ch = ch.replace(" ","-*-") so = ch.encode("Utf-8") fd.write(so) fd.close() fs.close() # # # # #

‫ظحلول التمارين‬ fin du fichier conversion en chaîne de caractères remplacement des espaces par -*Ré-encodage en une séquence d'octets transcription

: 10.23 ‫التمرين‬
# Comptage du nombre de mots dans un texte fiSource = input("Nom du fichier à traiter : ") fs = open(fiSource, 'r') n = 0 # variable compteur while 1: ch = fs.readline() if ch == "": # fin du fichier break # conversion de la chaîne lue en une liste de mots : li = ch.split() # totalisation des mots : n = n + len(li) fs.close() print("Ce fichier texte contient un total de %s mots" % (n))

: 10.24 ‫التمرين‬
# Fusion de lignes pour former des phrases fiSource = input("Nom du fichier à traiter (Latin-1) : ") fiDest = input("Nom du fichier destinataire (Utf-8) : ") fs = open(fiSource, 'r', encoding ="Latin1") fd = open(fiDest, 'w', encoding ="Utf8") # On lit d'abord la première ligne : ch1 = fs.readline() # On lit ensuite les suivantes, en les fusionnant si nécessaire : while 1: ch2 = fs.readline() if not ch2: # Rappel : une chaîne vide est considérée break # comme "fausse" dans les tests # Si la chaîne lue commence par une majuscule, on transcrit # la précédente dans le fichier destinataire, et on la # remplace par celle que l'on vient de lire : if ch2[0] in "ABCDEFGHIJKLMNOPQRSTUVWXYZÀÂÉÈÊËÎÏÔÙÛÇ": fd.write(ch1) ch1 = ch2 # Sinon, on la fusionne avec la précédente, en veillant à en # enlever au préalable le ou les caractère(s) de fin de ligne. else: ch1 = ch1[:-1] + " " + ch2 # Attention : ne pas oublier de transcrire la dernière ligne : fd.write(ch1)

‫ظحلول التمارين‬ fd.close() fs.close()

450

: (caractéristiques de sphères ) 10.25 ‫التمرين‬
# Le fichier de départ est un fichier dont chaque ligne contient # un nombre réel (encodé sous la forme d'une chaîne de caractères) from math import pi def caractSphere(d): "renvoie les caractéristiques d'une sphère de diamètre d" d = float(d) # conversion de l'argument (=chaîne) en réel r = d/2 # rayon ss = pi*r**2 # surface de section se = 4*pi*r**2 # surface extérieure v = 4/3*pi*r**3 # volume # La balise {:8.2f} utilisé ci-dessous formate le nombre # affiché de manière à occuper 8 caractères au total, en arrondissant # de manière à conserver deux chiffres après la virgule : ch = "Diam. {:6.2f} cm Section = {:8.2f} cm² ".format(d, ss) ch = ch +"Surf. = {:8.2f} cm². Vol. = {:9.2f} cm³".format(se, v) return ch fiSource = input("Nom du fichier à traiter : ") fiDest = input("Nom du fichier destinataire : ") fs = open(fiSource, 'r') fd = open(fiDest, 'w') while 1: diam = fs.readline() if diam == "" or diam == "\n": break fd.write(caractSphere(diam) + "\n") # ‫تدوين‬ fd.close() fs.close()

: 10.26 ‫التمرين‬
# Mise en forme de données numériques # Le fichier traité est un fichier dont chaque ligne contient un nombre # réel (sans exposants et encodé sous la forme d'une chaîne de caractères) def arrondir(reel): "représentation arrondie à .0 ou .5 d'un nombre réel" ent = int(reel) # partie entière du nombre fra = reel - ent # partie fractionnaire if fra < .25 : fra = 0 elif fra < .75 : fra = .5 else: fra = 1 return ent + fra fiSource = input("Nom du fichier à traiter : ") fiDest = input("Nom du fichier destinataire : ") fs = open(fiSource, 'r') fd = open(fiDest, 'w')

451

‫ظحلول التمارين‬

while 1: ligne = fs.readline() if ligne == "" or ligne == "\n": break n = arrondir(float(ligne)) # conversion en , puis arrondi fd.write(str(n) + "\n") # ‫تدوين‬ fd.close() fs.close()

: 10.29 ‫التمرين‬
# Affichage de tables de multiplication nt = [2, 3, 5, 7, 9, 11, 13, 17, 19] def tableMulti(m, n): "renvoie n termes de la table de multiplication par m" ch ="" for i in range(n): v = m * (i+1) # calcul d'un des termes ch = ch + "%4d" % (v) # formatage à 4 caractères return ch for a in nt: print(tableMulti(a, 15)) # 15 premiers termes seulement

: (simple parcours d'une liste) 10.30 ‫التمرين‬
# -*- coding:Utf-8 -*lst = ['Jean-Michel', 'Marc', 'Vanessa', 'Anne', 'Maximilien', 'Alexandre-Benoît', 'Louise'] for e in lst: print("%s : %s caractères" % (e, len(e)))

: 10.31 ‫التمرين‬
# Élimination de doublons lst = [9, 12, 40, 5, 12, 3, 27, 5, 9, 3, 8, 22, 40, 3, 2, 4, 6, 25] lst2 = [] for el in lst: if el not in lst2: lst2.append(el) lst2.sort() print("Liste initiale :", lst) print("Liste traitée :", lst2)

‫ظحلول التمارين‬

452 : (‫التمرين 33.01 )عرض كل أيام السنة‬

## Cette variante utilise une liste de listes ## ## (que l'on pourrait aisément remplacer par deux listes distinctes) # La liste ci-dessous contient deux éléments qui sont eux-mêmes des listes. # l'élément 0 contient les nombres de jours de chaque mois, tandis que # l'élément 1 contient les noms des douze mois : mois = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']] jour = ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'] ja, jm, js, m = 0, 0, 0, 0 while ja mois[0][m]: jm, m = 1, m+1 print(jour[js], jm, mois[1][m]) # ja = jour dans l'année, jm = jour dans le mois # js = jour de la semaine. Le décalage ajouté # permet de choisir le jour de départ # élément m de l'élément 0 de la liste # élément m de l'élément 1 de la liste

: 10.36 ‫التمرين‬
# Insertion de nouveaux éléments dans une liste existante t1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] t2 = ['Janvier','Février','Mars','Avril','Mai','Juin', 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'] c, d = 1, 0 while d < 12 : t2[c:c] = [t1[d]] c, d = c+2, d+1 print(t2)

# ! l'élément inséré doit être une liste

: 10.40 ‫التمرين‬
# Crible d'Eratosthène pour rechercher les nombres premiers de 1 à 999 # Créer une liste de 1000 éléments 1 (leurs indices vont de 0 à 999) : lst = [1]*1000 # Parcourir la liste à partir de l'élément d'indice 2: for i in range(2,1000): # Mettre à zéro les éléments suivants dans la liste, # dont les indices sont des multiples de i : for j in range(i*2, 1000, i): lst[j] = 0 # Afficher les indices des éléments restés à 1 (on ignore l'élément 0) : for i in range(1,1000): if lst[i]: print(i, end =’ ‘)

453

‫ظحلول التمارين‬

: (‫التمرين 34.01 )اختبار مولد أرقام عشوائية‬ from random import random # tire au hasard un réel entre 0 et 1 n = input("Nombre de valeurs à tirer au hasard (défaut = 1000) : ") if n == "": nVal =1000 else: nVal = int(n) n = input("Nombre de fractions dans l'intervalle 0-1 (entre 2 et {0}, "\ "défaut =5) : ".format(nVal//10)) if n == "": nFra =5 else: nFra = int(n) if nFra < 2: nFra =2 elif nFra > nVal/10: nFra = nVal/10 print("Tirage au sort des", nVal, "valeurs ...") listVal = [0]*nVal # créer une liste de zéros for i in range(nVal): # puis modifier chaque élément listVal[i] = random() print("Comptage des valeurs dans chacune des", nFra, "fractions ...") listCompt = [0]*nFra # créer une liste de compteurs # parcourir la liste des valeurs : for valeur in listVal: # trouver l'index de la fraction qui contient la valeur : index = int(valeur*nFra) # incrémenter le compteur correspondant : listCompt[index] = listCompt[index] +1 # afficher l'état des compteurs : for compt in listCompt: print(compt, end =’ ‘) print()

‫التمرين 44.01 : رسم بطاقات‬ from random import randrange couleurs = ['Pique', 'Trèfle', 'Carreau', 'Cœur'] valeurs = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'valet', 'dame', 'roi', 'as'] # Construction de la liste des 52 cartes : carte =[] for coul in couleurs: for val in valeurs: carte.append("{0} de {1}".format(val, coul)) # Tirage au hasard : while 1: k = input("Frappez pour tirer une carte, pour terminer ") if k =="": break r = randrange(52) # tirage au hasard d'un entier entre 0 et 51

‫ظحلول التمارين‬ print(carte[r]) 454

Création et consultation d'un dictionnaire : 10.45 ‫التمرين‬
# Mini système de bases de données def consultation(): while 1: nom = input("Entrez le nom if nom == "": break if nom in dico: item = dico[nom] age, taille = item[0], print("Nom : {0} - âge format(nom, age, else: print("*** nom inconnu

(ou pour terminer) : ") # le nom est-il répertorié ? # consultation proprement dite item[1] : {1} ans - taille : {2} m.".\ taille)) ! ***")

def remplissage(): while 1: nom = input("Entrez le nom (ou pour terminer) : ") if nom == "": break age = int(input("Entrez l'âge (nombre entier !) : ")) taille = float(input("Entrez la taille (en mètres) : ")) dico[nom] = (age, taille) dico ={} while 1: choix = input("Choisissez : (R)emplir - (C)onsulter - (T)erminer : ") if choix.upper() == 'T': break elif choix.upper() == 'R': remplissage() elif choix.upper() == 'C': consultation()

échange des clés et des valeurs dans un dictionnaire : 10.46 ‫التمرين‬ def inverse(dico): "Construction d'un nouveau dico, pas à pas" dic_inv ={} for cle in dico: item = dico[cle] dic_inv[item] = cle return dic_inv # programme test : dico = {'Computer':'Ordinateur', 'Mouse':'Souris', 'Keyboard':'Clavier', 'Hard disk':'Disque dur', 'Screen':'Écran'}

455 print(dico) print(inverse(dico))

‫ظحلول التمارين‬

‫التمرين 74.01 : رسم بياني‬
# Histogramme des fréquences de chaque lettre dans un texte nFich = input('Nom du fichier (Latin-1) : ') fi = open(nFich, 'r', encoding ="Latin1") texte = fi.read() fi.close() print(texte) dico ={} for c in texte: c = c.upper() dico[c] = dico.get(c, 0) +1

# afin de les regrouper, on convertit # toutes les lettres en majuscules

liste = list(dico.items()) liste.sort() for car, freq in liste: print("Caractère {0} : {1} occurrence(s).".format(car, freq))

: 10.48 ‫التمرين‬
# Histogramme des fréquences de chaque mot dans un texte # Suivant l'encodage du fichier source, activer l'une ou l'autre ligne : encodage ="Latin-1" # encodage ="Utf-8" nFich = input('Nom du fichier à traiter ({0}) : '.format(encodage)) # Conversion du fichier en une chaîne de caractères : fi = open(nFich, 'r', encoding =encodage) texte = fi.read() fi.close() # afin de pouvoir aisément séparer les mots du texte, on commence # par convertir tous les caractères non-alphabétiques en espaces : alpha = "abcdefghijklmnopqrstuvwxyzéèàùçâêîôûäëïöü" lettres = "" # nouvelle chaîne à construire for c in texte: c = c.lower() # conversion de chaque caractère en minuscule if c in alpha: lettres = lettres + c else: lettres = lettres + ' ' # conversion de la chaîne résultante en une liste de mots : mots = lettres.split() # construction de l'histogramme : dico ={} for m in mots: dico[m] = dico.get(m, 0) +1 liste = list(dico.items()) # tri de la liste résultante : liste.sort()

‫ظحلول التمارين‬
# affichage en clair : for item in liste: print("{0} : {1}".format(item[0], item[1]))

456

: 10.49 ‫التمرين‬
# Encodage d'un texte dans un dictionnaire # Suivant l'encodage du fichier source, activer l'une ou l'autre ligne : encodage ="Latin-1" # encodage ="Utf-8" nFich = input('Nom du fichier à traiter ({0}) : '.format(encodage)) # Conversion du fichier en une chaîne de caractères : fi = open(nFich, 'r', encoding =encodage) texte = fi.read() fi.close() # On considère que les mots sont des suites de caractères faisant partie # de la chaîne ci-dessous. Tous les autres sont des séparateurs : alpha = "abcdefghijklmnopqrstuvwxyzéèàùçâêîôûäëïöü" # Construction du dictionnaire : dico ={} # Parcours de tous les caractères du texte : i =0 # indice du caractère en cours de lecture im =-1 # indice du premier caractère du mot mot = "" # variable de travail : mot en cours de lecture for c in texte: c = c.lower() # conversion de chaque caractère en minuscule if c in alpha: # car. alphabétique => on est à l'intérieur d'un mot mot = mot + c if im < 0: # mémoriser l'indice du premier caractère du mot im =i else: # car. non-alphabétique => fin de mot if mot != "": # afin d'ignorer les car. non-alphab. successifs # pour chaque mot, on construit une liste d'indices : if mot in dico: # mot déjà répertorié : dico[mot].append(im) # ajout d'un indice à la liste else: # mot rencontré pour la 1e fois : dico[mot] =[im] # création de la liste d'indices mot ="" # préparer la lecture du mot suivant im =-1 i += 1 # indice du caractère suivant # Affichage du dictionnaire, en clair : listeMots =list(dico.items()) # Conversion du dico en une liste de tuples listeMots.sort() # tri alphabétique de la liste for clef, valeur in listeMots: print(clef, ":", valeur)

.(Sauvegarde d’un dictionnaire (complément de l’ex. 10.45 : 10.50 ‫التمرين‬
# Mini-système de base de données def consultation(): while 1: nom = input("Entrez le nom (ou pour terminer) : ")

457 if nom == "": break if nom in dico: item = dico[nom] age, taille = item[0], print("Nom : {0} - âge format(nom, age, else: print("*** nom inconnu

‫ظحلول التمارين‬

# le nom est-il répertorié ? # consultation proprement dite item[1] : {1} ans - taille : {2} m.".\ taille)) ! ***")

def remplissage(): while 1: nom = input("Entrez le nom (ou pour terminer) : ") if nom == "": break age = int(input("Entrez l'âge (nombre entier !) : ")) taille = float(input("Entrez la taille (en mètres) : ")) dico[nom] = (age, taille) def enregistrement(): fich = input("Entrez le nom du fichier de sauvegarde : ") ofi = open(fich, "w") # écriture d'une ligne-repère pour identifier le type de fichier : ofi.write("DicoExercice10.50\n") # parcours du dictionnaire entier, converti au préalable en une liste : for cle, valeur in list(dico.items()): # utilisation du formatage des chaînes pour créer l'enregistrement : ofi.write("{0}@{1}#{2}\n".format(cle, valeur[0], valeur[1])) ofi.close() def lectureFichier(): fich = input("Entrez le nom du fichier de sauvegarde : ") try: ofi = open(fich, "r") except: print("*** fichier inexistant ***") return # Vérification : le fichier est-il bien de notre type spécifique ? : repere =ofi.readline() if repere != "DicoExercice10.50\n": print("*** type de fichier incorrect ***") return # Lecture des lignes restantes du fichier : while 1: ligne = ofi.readline() if ligne =='': # détection de la fin de fichier break enreg = ligne.split("@") # restitution d'une liste [clé,valeur] cle = enreg[0] valeur = enreg[1][:-1] # élimination du caractère de fin de ligne data = valeur.split("#") # restitution d'une liste [âge, taille] age, taille = int(data[0]), float(data[1]) dico[cle] = (age, taille) # reconstitution du dictionnaire ofi.close() ########### Programme principal : ########### dico ={} lectureFichier() while 1: choix = input("Choisissez : (R)emplir - (C)onsulter - (T)erminer : ") if choix.upper() == 'T':

‫ظحلول التمارين‬ break elif choix.upper() == 'R': remplissage() elif choix.upper() == 'C': consultation() enregistrement()

458

Contrôle du flux d’exécution à l’aide d’un dictionnaire : 10.51 ‫التمرين‬

Cet exercice complète le précédent. On ajoute encore deux petites fonctions, et on réécrit le : corps principal du programme pour diriger le flux d’exécution en se servant d’un dictionnaire def sortie(): print("*** Job terminé ***") return 1 # afin de provoquer la sortie de la boucle

def autre(): print("Veuillez frapper R, A, C, S ou T, svp.") ######## * Programme principal * ######### dico ={} fonc ={"R":lectureFichier, "A":remplissage, "C":consultation, "S":enregistrement, "T":sortie} while 1: choix = input("Choisissez :\n" +\ "(R)écupérer un dictionnaire préexistant sauvegardé dans un fichier\n" +\ "(A)jouter des données au dictionnaire courant\n" +\ "(C)onsulter le dictionnaire courant\n" +\ "(S)auvegarder le dictionnaire courant dans un fichier\n" +\ "(T)erminer : ").upper() # l'instruction ci-dessous appelle une fonction différente pour chaque # choix, par l'intermédiaire du dictionnaire : if fonc.get(choix, autre)(): break # note : toutes les fonctions appelées ici renvoient par défaut # sauf la fonction sortie() qui renvoie 1 => sortie de la boucle

: 11.1 ‫التمرين‬ from math import sqrt # fonction racine carrée def distance(p1, p2): # On applique le théorème de Pythagore : dx =abs(p1.x - p2.x) # abs() => valeur absolue dy =abs(p1.y - p2.y) return sqrt(dx*dx + dy*dy) def affiche_point(p): print("Coord. horiz.", p.x, "Coord. vert.", p.y) class Point(object): "Classe de points géométriques" # Définition des 2 points : p8, p9 = Point(), Point() p8.x, p8.y, p9.x, p9.y = 12.3, 5.7, 6.2, 9.1

459 affiche_point(p8) affiche_point(p9) print("Distance =", distance(p8,p9))

‫ظحلول التمارين‬

: 12.1 ‫التمرين‬ class Domino(object): def __init__(self, pa, pb): self.pa, self.pb = pa, pb def affiche_points(self): print "face A :", self.pa, print "face B :", self.pb def valeur(self): return self.pa + self.pb # Programme de test : d1 = Domino(2,6) d2 = Domino(4,3) d1.affiche_points() d2.affiche_points() print("total des points :", d1.valeur() + d2.valeur()) liste_dominos = [] for i in range(7): liste_dominos.append(Domino(6, i)) vt =0 for i in range(7): liste_dominos[i].affiche_points() vt = vt + liste_dominos[i].valeur() print("valeur totale des points", vt) print(liste_dominos[3], liste_dominos[4])

: 12.2 ‫التمرين‬ class CompteBancaire(object): def __init__(self, nom ='Dupont', solde =1000): self.nom, self.solde = nom, solde def depot(self, somme): self.solde = self.solde + somme def retrait(self, somme): self.solde = self.solde - somme def affiche(self): print("Le solde du compte bancaire de {0} est de {1} euros.".\ format(self.nom, self.solde)) # Programme de test : if __name__ == '__main__':

‫ظحلول التمارين‬ c1 = CompteBancaire('Duchmol', 800) c1.depot(350) c1.retrait(200) c1.affiche()

460

: 12.3 ‫التمرين‬ class Voiture(object): def __init__(self, marque = 'Ford', couleur = 'rouge'): self.couleur = couleur self.marque = marque self.pilote = 'personne' self.vitesse = 0 def accelerer(self, taux, duree): if self.pilote =='personne': print("Cette voiture n'a pas de conducteur !") else: self.vitesse = self.vitesse + taux * duree def choix_conducteur(self, nom): self.pilote = nom def affiche_tout(self): print("{0} {1} pilotée par {2}, vitesse = {3} m/s".\ format(self.marque, self.couleur, self.pilote, self.vitesse)) a1 = Voiture('Peugeot', 'bleue') a2 = Voiture(couleur = 'verte') a3 = Voiture('Mercedes') a1.choix_conducteur('Roméo') a2.choix_conducteur('Juliette') a2.accelerer(1.8, 12) a3.accelerer(1.9, 11) a2.affiche_tout() a3.affiche_tout()

: 12.4 ‫التمرين‬ class Satellite(object): def __init__(self, nom, masse =100, vitesse =0): self.nom, self.masse, self.vitesse = nom, masse, vitesse def impulsion(self, force, duree): self.vitesse = self.vitesse + force * duree / self.masse def energie(self): return self.masse * self.vitesse**2 / 2 def affiche_vitesse(self): print("Vitesse du satellite {0} = {1} m/s".\ format(self.nom, self.vitesse)) # Programme de test : s1 = Satellite('Zoé', masse =250, vitesse =10) s1.impulsion(500, 15)

461 s1.affiche_vitesse() print("énergie =", s1.energie()) s1.impulsion(500, 15) s1.affiche_vitesse() print("nouvelle énergie =", s1.energie())

‫ظحلول التمارين‬

: (‫التمرينان 5.21-6.21 )أصناف السطوانات والخاريط‬
# Classes dérivées - Polymorphisme class Cercle(object): def __init__(self, rayon): self.rayon = rayon def surface(self): return 3.1416 * self.rayon**2 class Cylindre(Cercle): def __init__(self, rayon, hauteur): Cercle.__init__(self, rayon) self.hauteur = hauteur def volume(self): return self.surface()*self.hauteur # la méthode surface() est héritée de la classe parente class Cone(Cylindre): def __init__(self, rayon, hauteur): Cylindre.__init__(self, rayon, hauteur) def volume(self): return Cylindre.volume(self)/3 # cette nouvelle méthode volume() remplace celle que # l'on a héritée de la classe parente (exemple de polymorphisme) # Programme test : cyl = Cylindre(5, 7) print("Surf. de section du cylindre =", cyl.surface()) print("Volume du cylindre =", cyl.volume()) co = Cone(5,7) print("Surf. de base du cône =", co.surface()) print("Volume du cône =", co.volume())

: 12.7 ‫التمرين‬
# Tirage de cartes from random import randrange class JeuDeCartes(object): """Jeu de cartes""" # attributs de classe (communs à toutes les instances) : couleur = ('Pique', 'Trèfle', 'Carreau', 'Cœur') valeur = (0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 'valet', 'dame', 'roi', 'as')

‫ظحلول التمارين‬ def __init__(self): "Construction de la liste des 52 cartes" self.carte =[] for coul in range(4): for val in range(13): self.carte.append((val +2, coul))

462

# la valeur commence à 2

def nom_carte(self, c): "Renvoi du nom de la carte c, en clair" return "{0} de {1}".format(self.valeur[c[0]], self.couleur[c[1]]) def battre(self): "Mélange des cartes" t = len(self.carte) # nombre de cartes restantes # pour mélanger, on procède à un nombre d'échanges équivalent : for i in range(t): # tirage au hasard de 2 emplacements dans la liste : h1, h2 = randrange(t), randrange(t) # échange des cartes situées à ces emplacements : self.carte[h1], self.carte[h2] = self.carte[h2], self.carte[h1] def tirer(self): "Tirage de la première carte de la pile" t = len(self.carte) # vérifier qu'il reste des cartes if t >0: carte = self.carte[0] # choisir la première carte du jeu del(self.carte[0]) # la retirer du jeu return carte # en renvoyer copie au prog. appelant else: return None # facultatif ### Programme test : if __name__ == '__main__': jeu = JeuDeCartes() jeu.battre() for n in range(53): c = jeu.tirer() if c == None: print('Terminé !') else: print(jeu.nom_carte(c)) # instanciation d'un objet # mélange des cartes # tirage des 52 cartes : # il ne reste aucune carte # dans la liste # valeur et couleur de la carte

: 12.8 ‫التمرين‬

On supposera que l’exercice précédent a été sauvegardé sous le nom )
( .cartes.py
# Bataille de de cartes from cartes import JeuDeCartes jeuA = JeuDeCartes() jeuB = JeuDeCartes() jeuA.battre() jeuB.battre() pA, pB = 0, 0 # instanciation du premier jeu # instanciation du second jeu # mélange de chacun # compteurs de points des joueurs A et B

463
# tirer 52 fois une carte de chaque jeu : for n in range(52): cA, cB = jeuA.tirer(), jeuB.tirer() vA, vB = cA[0], cB[0] # valeurs de ces cartes if vA > vB: pA += 1 elif vB > vA: pB += 1 # (rien ne se passe si vA = vB) # affichage des points successifs et des cartes tirées : print("{0} * {1} ==> {2} * {3}".format(jeuA.nom_carte(cA), jeuB.nom_carte(cB), pA, pB))

‫ظحلول التمارين‬

print("le joueur A obtient {0} pts, le joueur B en obtient {1}.".format(pA, pB))

: 12.9 ‫التمرين‬ from exercice_12_02 import CompteBancaire class CompteEpargne(CompteBancaire): def __init__(self, nom ='Durand', solde =500): CompteBancaire.__init__(self, nom, solde) self.taux =.3 # taux d'intérêt mensuel par défaut def changeTaux(self, taux): self.taux =taux def capitalisation(self, nombreMois =6): print("Capitalisation sur {0} mois au taux mensuel de {1} %.".\ format(nombreMois, self.taux)) for m in range(nombreMois): self.solde = self.solde * (100 +self.taux)/100 # Programme de test : if __name__ == '__main__': c1 = CompteEpargne('Duvivier', 600) c1.depot(350) c1.affiche() c1.capitalisation(12) c1.affiche() c1.changeTaux(.5) c1.capitalisation(12) c1.affiche()

: 13.6 ‫التمرين‬ from tkinter import * def cercle(can, x, y, r, coul ='white'): "dessin d'un cercle de rayon en dans le canevas " can.create_oval(x-r, y-r, x+r, y+r, fill =coul) class Application(Tk): def __init__(self): Tk.__init__(self) # constructeur de la classe parente self.can =Canvas(self, width =475, height =130, bg ="white") self.can.pack(side =TOP, padx =5, pady =5) Button(self, text ="Train", command =self.dessine).pack(side =LEFT)

‫ظحلول التمارين‬
Button(self, text ="Hello", command =self.coucou).pack(side =LEFT) Button(self, text ="Ecl34", command =self.eclai34).pack(side =LEFT) def dessine(self): "instanciation de 4 wagons dans le self.w1 = Wagon(self.can, 10, 30) self.w2 = Wagon(self.can, 130, 30, self.w3 = Wagon(self.can, 250, 30, self.w4 = Wagon(self.can, 370, 30, canevas" 'dark green') 'maroon') 'purple')

464

def coucou(self): "apparition de personnages dans certaines fenêtres" self.w1.perso(3) # 1er wagon, 3e fenêtre self.w3.perso(1) # 3e wagon, 1e fenêtre self.w3.perso(2) # 3e wagon, 2e fenêtre self.w4.perso(1) # 4e wagon, 1e fenêtre def eclai34(self): "allumage de l'éclairage dans les wagons 3 & 4" self.w3.allumer() self.w4.allumer() class Wagon(object): def __init__(self, canev, x, y, coul ='navy'): "dessin d'un petit wagon en dans le canevas " # mémorisation des paramètres dans des variables d'instance : self.canev, self.x, self.y = canev, x, y # rectangle de base : 95x60 pixels : canev.create_rectangle(x, y, x+95, y+60, fill =coul) # 3 fenêtres de 25x40 pixels, écartées de 5 pixels : self.fen =[] # pour mémoriser les réf. des fenêtres for xf in range(x +5, x +90, 30): self.fen.append(canev.create_rectangle(xf, y+5, xf+25, y+40, fill ='black')) # 2 roues, de rayon égal à 12 pixels : cercle(canev, x+18, y+73, 12, 'gray') cercle(canev, x+77, y+73, 12, 'gray') def perso(self, fen): "apparition d'un petit personnage à la fenêtre " # calcul des coordonnées du centre de chaque fenêtre : xf = self.x + fen*30 -12 yf = self.y + 25 cercle(self.canev, xf, yf, 10, "pink") # visage cercle(self.canev, xf-5, yf-3, 2) # œil gauche cercle(self.canev, xf+5, yf-3, 2) # œil droit cercle(self.canev, xf, yf+5, 3) # bouche def allumer(self): "déclencher l'éclairage interne du wagon" for f in self.fen: self.canev.itemconfigure(f, fill ='yellow') app = Application() app.mainloop()

: 13.10 ‫التمرين‬
# # Widget dérivé de , spécialisé pour dessiner des graphiques élongation/temps

465 from tkinter import * from math import sin, pi

‫ظحلول التمارين‬

class OscilloGraphe(Canvas): "Canevas spécialisé, pour dessiner des courbes élongation/temps" def __init__(self, master=None, larg=200, haut=150): "Constructeur de la base du graphique : quadrillage et axes" Canvas.__init__(self) # appel au constructeur self.configure(width=larg, height=haut) # de la classe parente self.larg, self.haut = larg, haut # mémorisation # tracé d'une échelle horizontale avec 8 graduations : pas = (larg-25)/8. # intervalles de l'échelle horizontale for t in range(0, 9): stx = 10 + t*pas # +10 pour partir de l'origine self.create_line(stx, haut/10, stx, haut*9/10, fill='grey') # tracé d'une échelle verticale avec 5 graduations : pas = haut*2/25. # intervalles de l'échelle verticale for t in range(-5, 6): sty = haut/2 -t*pas # haut/2 pour partir de l'origine self.create_line(10, sty, larg-15, sty, fill='grey') self.traceAxes() # tracé des axes de référence X et Y def traceAxes(self): "Méthode traçant les axes de référence (pourra être surchargée)." # axes horizontal (X) et vertical (Y) : self.create_line(10, self.haut/2, self.larg, self.haut/2, arrow=LAST) self.create_line(10, self.haut-5, 10, 5, arrow=LAST) # indication des grandeurs physiques aux extrémités des axes : self.create_text(20, 10, anchor =CENTER, text = "e") self.create_text(self.larg-10, self.haut/2-12, anchor=CENTER, text="t") def traceCourbe(self, freq=1, phase=0, ampl=10, coul='red'): "tracé d'un graphique élongation/temps sur 1 seconde" curve =[] # liste des coordonnées pas = (self.larg-25)/1000. # l'échelle X correspond à 1 seconde for t in range(0,1001,5): # que l'on divise en 1000 ms. e = ampl*sin(2*pi*freq*t/1000 - phase) x = 10 + t*pas y = self.haut/2 - e*self.haut/25 curve.append((x,y)) n = self.create_line(curve, fill=coul, smooth=1) return n # n = numéro d'ordre du tracé #### Code pour tester la classe : #### if __name__ == '__main__': racine = Tk() gra = OscilloGraphe(racine, 250, 180) gra.pack() gra.configure(bg ='ivory', bd =2, relief=SUNKEN) gra.traceCourbe(2, 1.2, 10, 'purple') racine.mainloop()

: 13.16 ‫التمرين‬
# # Tracé de graphiques élongation/temps pour 3 mouvements vibratoires harmoniques

from tkinter import * from math import sin, pi

‫ظحلول التمارين‬ from exercice_13_10 import OscilloGraphe class OscilloGrapheBis(OscilloGraphe): """Classe dérivée du widget Oscillographe (cf. exercice 13.10)""" def __init__(self, master =None, larg =200, haut =150): # Appel du constructeur de la classe parente : OscilloGraphe.__init__(self, master, larg, haut) def traceAxes(self): "Surchage de la méthode de même nom dans la classe parente" # tracé de l'axe de référence Y : pas = (self.larg-25)/8. # intervalles de l'échelle horizontale self.create_line(10+4*pas, self.haut-5, 10+4*pas, 5, fill ='grey90', arrow=LAST) # tracé de l'axe de référence X : self.create_line(10, self.haut/2, self.larg, self.haut/2, fill= 'grey90', arrow=LAST) # indication des grandeurs physiques aux extrémités des axes : self.create_text(20+4*pas, 15, anchor=CENTER, text="e", fill='red') self.create_text(self.larg-5, self.haut/2-12, anchor=CENTER, text ="t", fill='red') class ChoixVibra(Frame): """Curseurs pour choisir fréquence, phase & amplitude d'une vibration""" def __init__(self, master=None, coul='red'): Frame.__init__(self) # constructeur de la classe parente # Définition de quelques attributs d'instance : self.freq, self.phase, self.ampl, self.coul = 0, 0, 0, coul # Variable d'état de la case à cocher : self.chk = IntVar() # 'objet-variable' Tkinter Checkbutton(self, text='Afficher', variable=self.chk, fg = self.coul, command=self.setCurve).pack(side=LEFT) # Définition des 3 widgets curseurs : Scale(self, length=150, orient=HORIZONTAL, sliderlength =25, label ='Fréquence (Hz) :', from_=1., to=9., tickinterval =2, resolution =0.25, showvalue =0, command = self.setFrequency).pack(side=LEFT, pady =5) Scale(self, length=150, orient=HORIZONTAL, sliderlength =15, label ='Phase (degrés) :', from_=-180, to=180, tickinterval =90, showvalue =0, command = self.setPhase).pack(side=LEFT, pady =5) Scale(self, length=150, orient=HORIZONTAL, sliderlength =25, label ='Amplitude :', from_=2, to=10, tickinterval =2, showvalue =0, command = self.setAmplitude).pack(side=LEFT, pady =5) def setCurve(self): self.master.event_generate('') def setFrequency(self, f): self.freq = float(f) self.master.event_generate('') def setPhase(self, p): pp =float(p) self.phase = pp*2*pi/360 # conversion degrés -> radians self.master.event_generate('') def setAmplitude(self, a): self.ampl = float(a) self.master.event_generate('')

466

467
## Classe principale ##

‫ظحلول التمارين‬

class ShowVibra(Frame): """Démonstration de mouvements vibratoires harmoniques""" def __init__(self, master=None): Frame.__init__(self) # constructeur de la classe parente self.couleur = ['green', 'yellow', 'orange'] self.trace = [0]*3 # liste des tracés (courbes à dessiner) self.controle = [0]*3 # liste des panneaux de contrôle # Instanciation du canevas avec axes X et Y : self.gra = OscilloGrapheBis(self, larg =400, haut=300) self.gra.configure(bg ='grey40', bd=3, relief=SUNKEN) self.gra.pack(side =TOP, pady=3) # Instanciation de 3 panneaux de contrôle (curseurs) : for i in range(3): self.controle[i] = ChoixVibra(self, self.couleur[i]) self.controle[i].configure(bd =3, relief = GROOVE) self.controle[i].pack(padx =10, pady =3) # Désignation de l'événement qui déclenche l'affichage des tracés : self.master.bind('', self.montreCourbes) self.master.title('Mouvements vibratoires harmoniques') self.pack() def montreCourbes(self, event): """(Ré)Affichage des trois graphiques élongation/temps""" for i in range(3): # D'abord, effacer le tracé précédent (éventuel) : self.gra.delete(self.trace[i]) # Ensuite, dessiner le nouveau tracé : if self.controle[i].chk.get(): self.trace[i] = self.gra.traceCourbe( coul=self.couleur[i], freq=self.controle[i].freq, phase=self.controle[i].phase, ampl=self.controle[i].ampl) #### Code de test : ### if __name__ == '__main__': ShowVibra().mainloop()

‫التمرين 22.31 : قاموس ألوان‬ from tkinter import *

‫ظحلول التمارين‬

468

# Module donnant accès aux boîtes de dialogue standard pour # la recherche de fichiers sur disque : from tkinter.filedialog import asksaveasfile, askopenfile class Application(Frame): '''Fenêtre d'application''' def __init__(self): Frame.__init__(self) self.master.title("Création d'un dictionnaire de couleurs") self.dico ={} # création du dictionnaire # Les widgets sont regroupés dans deux cadres (Frames) : frSup =Frame(self) # cadre supérieur contenant 6 widgets Label(frSup, text ="Nom de la couleur :", width =20).grid(row =1, column =1) self.enNom =Entry(frSup, width =25) # champ d'entrée pour self.enNom.grid(row =1, column =2) # le nom de la couleur Button(frSup, text ="Existe déjà ?", width =12, command =self.chercheCoul).grid(row =1, column =3) Label(frSup, text ="Code hexa. corresp. :", width =20).grid(row =2, column =1) self.enCode =Entry(frSup, width =25) # champ d'entrée pour self.enCode.grid(row =2, column =2) # le code hexa. Button(frSup, text ="Test", width =12, command =self.testeCoul).grid(row =2, column =3) frSup.pack(padx =5, pady =5) frInf =Frame(self) # cadre inférieur contenant le reste self.test = Label(frInf, bg ="white", width =45, # zone de test height =7, relief = SUNKEN) self.test.pack(pady =5) Button(frInf, text ="Ajouter la couleur au dictionnaire", command =self.ajouteCoul).pack() Button(frInf, text ="Enregistrer le dictionnaire", width =25, command =self.enregistre).pack(side = LEFT, pady =5) Button(frInf, text ="Restaurer le dictionnaire", width =25, command =self.restaure).pack(side =RIGHT, pady =5) frInf.pack(padx =5, pady =5) self.pack() def ajouteCoul(self): "ajouter la couleur présente au dictionnaire"

469

‫ظحلول التمارين‬ if self.testeCoul() ==0: # une couleur a-t-elle été définie ? return nom = self.enNom.get() if len(nom) >1: # refuser les noms trop petits self.dico[nom] =self.cHexa else: self.test.config(text ="%s : nom incorrect" % nom, bg='white') def chercheCoul(self): "rechercher une couleur déjà inscrite au dictionnaire" nom = self.enNom.get() if nom in self.dico: self.test.config(bg =self.dico[nom], text ="") else: self.test.config(text ="%s : couleur inconnue" % nom, bg='white') def testeCoul(self): "vérifier la validité d'un code hexa. - afficher la couleur corresp." try: self.cHexa =self.enCode.get() self.test.config(bg =self.cHexa, text ="") return 1 except: self.test.config(text ="Codage de couleur incorrect", bg ='white') return 0 def enregistre(self): "enregistrer le dictionnaire dans un fichier texte" # Cette méthode utilise une boîte de dialogue standard pour la # sélection d'un fichier sur disque. Tkinter fournit toute une série # de fonctions associées à ces boîtes, dans le module filedialog. # La fonction ci-dessous renvoie un objet-fichier ouvert en écriture : ofi =asksaveasfile(filetypes=[("Texte",".txt"),("Tous","*")]) for clef, valeur in list(self.dico.items()): ofi.write("{0} {1}\n".format(clef, valeur)) ofi.close() def restaure(self): "restaurer le dictionnaire à partir d'un fichier de mémorisation" # La fonction ci-dessous renvoie un objet-fichier ouvert en lecture : ofi =askopenfile(filetypes=[("Texte",".txt"),("Tous","*")]) lignes = ofi.readlines() for li in lignes: cv = li.split() # extraction de la clé et la valeur corresp. self.dico[cv[0]] = cv[1] ofi.close()

if __name__ == '__main__': Application().mainloop()

: (3 ‫التمرين 32.31 )متنوع‬ from tkinter import * from random import randrange from math import sin, cos, pi

‫ظحلول التمارين‬

470

class FaceDom(object): def __init__(self, can, val, pos, taille =70): self.can =can x, y, c = pos[0], pos[1], taille/2 self. carre = can.create_rectangle(x -c, y-c, x+c, y+c, fill ='ivory', width =2) d = taille/3 # disposition des points sur la face, pour chacun des 6 cas : self.pDispo = [((0,0),), ((-d,d),(d,-d)), ((-d,-d), (0,0), (d,d)), ((-d,-d),(-d,d),(d,-d),(d,d)), ((-d,-d),(-d,d),(d,-d),(d,d),(0,0)), ((-d,-d),(-d,d),(d,-d),(d,d),(d,0),(-d,0))] self.x, self.y, self.dim = x, y, taille/15 self.pList =[] # liste contenant les points de cette face self.tracer_points(val) def tracer_points(self, val): # créer les dessins de points correspondant à la valeur val : disp = self.pDispo[val -1] for p in disp: self.cercle(self.x +p[0], self.y +p[1], self.dim, 'red') self.val = val def cercle(self, x, y, r, coul): self.pList.append(self.can.create_oval(x-r, y-r, x+r, y+r, fill=coul)) def effacer(self, flag =0): for p in self.pList: self.can.delete(p) if flag: self.can.delete(self.carre) class Projet(Frame):

471

‫ظحلول التمارين‬ def __init__(self, larg, haut): Frame.__init__(self) self.larg, self.haut = larg, haut self.can = Canvas(self, bg='dark green', width =larg, height =haut) self.can.pack(padx =5, pady =5) # liste des boutons à installer, avec leur gestionnaire : bList = [("A", self.boutA), ("B", self.boutB), ("C", self.boutC), ("Quitter", self.boutQuit)] bList.reverse() # inverser l'ordre de la liste for b in bList: Button(self, text =b[0], command =b[1]).pack(side =RIGHT, padx=3) self.pack() self.des =[] # liste qui contiendra les faces de dés self.actu =0 # réf. du dé actuellement sélectionné def boutA(self): if len(self.des): return # car les dessins existent déjà ! a, da = 0, 2*pi/13 for i in range(13): cx, cy = self.larg/2, self.haut/2 x = cx + cx*0.75*sin(a) # pour disposer en cercle, y = cy + cy*0.75*cos(a) # on utilise la trigono ! self.des.append(FaceDom(self.can, randrange(1,7) , (x,y), 65)) a += da def boutB(self): # incrémenter la valeur du dé sélectionné. Passer au suivant : v = self.des[self.actu].val v = v % 6 v += 1 self.des[self.actu].effacer() self.des[self.actu].tracer_points(v) self.actu += 1 self.actu = self.actu % 13 def boutC(self): for i in range(len(self.des)): self.des[i].effacer(1) self.des =[] self.actu =0 def boutQuit(self): self.master.destroy()

Projet(600, 600).mainloop()

: (‫التمرين 1.41 )ودجة كومبوبوكس كاملة‬

class ComboFull(Frame):

‫ظحلول التمارين‬
"Widget composite 'Combo box' (champ d'entrée + liste 'déroulante')" def __init__(self, boss, item='', items=[], command ='', width =10, listSize =5): Frame.__init__(self, boss) # constructeur de la classe parente self.boss =boss # référence du widget 'maître' self.items =items # items à placer dans la boîte de liste self.command =command # fonction à invoquer après clic ou self.item =item # item entré ou sélectionné self.listSize =listSize # nombre d'items visibles dans la liste self.width =width # largeur du champ d'entrée (en caract.) # Champ d'entrée : self.entree =Entry(self, width =width) self.entree.insert(END, item) self.entree.bind("", self.sortieE) self.entree.pack(side =LEFT) # largeur en caractères

472

# Bouton pour faire apparaître la liste associée : self.gif1 = PhotoImage(file ="down.gif") # ! variable persistante Button(self, image =self.gif1, width =15, height=15, command =self.popup).pack() def sortieL(self, event =None): # Extraire de la liste l'item qui a été sélectionné : index =self.bListe.curselection() # renvoie un tuple d'index ind0 =int(index[0]) # on ne garde que le premier self.item =self.items[ind0] # Actualiser le champ d'entrée avec l'item choisi : self.entree.delete(0, END) self.entree.insert(END, self.item) # Exécuter la commande indiquée, avec l'item choisi comme argument : self.command(self.item) self.pop.destroy() # supprimer la fenêtre satellite def sortieE(self, event =None): # Exécuter la commande indiquée, avec l'argument-item encodé tel quel : self.command(self.entree.get()) def get(self): # Renvoyer le dernier item sélectionné dans la boîte de liste return self.item def popup(self): # Faire apparaître la petite fenêtre satellite contenant la liste. # On commence par récupérer les coordonnées du coin supérieur gauche # du présent widget dans la fenêtre principale : xW, yW =self.winfo_x(), self.winfo_y() # ... et les coordonnées de la fenêtre principale sur l'écran, grâce à # la méthode geometry() qui renvoie une chaîne avec taille et coordo. : geo =self.boss.geometry().split("+") xF, yF =int(geo[1]), int(geo[2]) # coord. coin supérieur gauche # On peut alors positionner une petite fenêtre, modale et sans bordure, # exactement sous le champ d'entrée : xP, yP = xF +xW +10, yF +yW +45 # +45 : compenser haut champ Entry self.pop =Toplevel(self) # fenêtre secondaire ("pop up") self.pop.geometry("+{0}+{1}".format(xP, yP)) # positionnement / écran self.pop.overrideredirect(1) # => fen. sans bordure ni bandeau self.pop.transient(self.master) # => fen. 'modale' # Boîte de liste, munie d'un 'ascenseur' (scroll bar) : cadreLB =Frame(self.pop) # cadre pour l'ensemble des 2

473

‫ظحلول التمارين‬ self.bListe =Listbox(cadreLB, height=self.listSize, width=self.width-1) scrol =Scrollbar(cadreLB, command =self.bListe.yview) self.bListe.config(yscrollcommand =scrol.set) self.bListe.bind("", self.sortieL) self.bListe.pack(side =LEFT) scrol.pack(expand =YES, fill =Y) cadreLB.pack() # Remplissage de la boîte de liste avec les items fournis : for it in self.items: self.bListe.insert(END, it)

if __name__ =="__main__": # --- ‫-- اختبار البرنامج‬def changeCoul(col): fen.configure(background = col) def changeLabel(): lab.configure(text = combo.get()) couleurs = ('navy', 'royal blue', 'steelblue1', 'cadet blue', 'lawn green', 'forest green', 'yellow', 'dark red', 'grey80','grey60', 'grey40', 'grey20', 'pink') fen =Tk() combo =ComboFull(fen, item ="néant", items =couleurs, command =changeCoul, width =15, listSize =6) combo.grid(row =1, columnspan =2, padx =10, pady =10) bou = Button(fen, text ="Test", command =changeLabel) bou.grid(row =3, column =0, padx =8, pady =8) lab = Label(fen, text ="Bonjour", bg ="ivory", width =15) lab.grid(row =3, column =1, padx =8) fen.mainloop()

: ("‫التمرين 1.61 )إنشاء قاعدة البيانات "االوسيقى‬
# Création et Alimentation d'une petite base de données SQLite import sqlite3 # Établissement de la connexion - Création du curseur : connex = sqlite3.connect("musique.sq3") cur = connex.cursor() # Création des tables. L'utilisation de try/except permet de réutiliser le # script indéfiniment, même si la base de données existe déjà. try: req ="CREATE TABLE compositeurs(comp TEXT, a_naiss INTEGER, "\ "a_mort INTEGER)" cur.execute(req) req ="CREATE TABLE oeuvres(comp TEXT, titre TEXT, duree INTEGER, "\ "interpr TEXT)" cur.execute(req) except: pass # Les tables existent certainement déjà => on continue. print("Entrée des enregistrements, table des compositeurs :") while 1: nom = input("Nom du compositeur ( pour terminer) : ") if nom =='': break aNais = input("Année de naissance : ") aMort = input("Année de mort : ") req ="INSERT INTO compositeurs (comp, a_naiss, a_mort) VALUES (?, ?, ?)"

‫ظحلول التمارين‬ cur.execute(req, (nom, aNais, aMort)) print("Rappel des infos introduites :") cur.execute("select * from compositeurs") for enreg in cur: print(enreg) print("Entrée des enregistrements, table des oeuvres musicales :") while 1: nom = input("Nom du compositeur ( pour terminer) : ") if nom =='': break titre = input("Titre de l'oeuvre : ") duree = input("durée (minutes) : ") inter = input("interprète principal : ") req ="INSERT INTO oeuvres (comp, titre, duree, interpr) "\ "VALUES (?, ?, ?, ?)" cur.execute(req, (nom, titre, duree, inter)) print("Rappel des infos introduites :") cur.execute("select * from oeuvres") for enreg in cur: print(enreg) # Transfert effectif des enregistrements dans la BD : connex.commit()

474

: 18.3 ‫التمرين‬
# === Génération d'un document PDF avec gestion de fluables (paragraphes) === # Adaptations du script pour le rendre exécutable sous Python 2.6 ou 2.7 : # (Ces lignes peuvent être supprimées si Reportlab est disponible pour Python3) from __future__ import unicode_literals from __future__ import division # division "réelle" from codecs import open # décodage des fichiers texte # ----------------------------------------------------------------------------# Importer quelques éléments de la bibliothèque ReportLab : from reportlab.pdfgen.canvas import Canvas from reportlab.lib.units import cm from reportlab.lib.pagesizes import A4 from reportlab.platypus import Paragraph, Frame, Spacer from reportlab.platypus.flowables import Image as rlImage from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.enums import TA_LEFT,TA_RIGHT,TA_JUSTIFY,TA_CENTER from copy import deepcopy styles = getSampleStyleSheet() # dictionnaire de styles prédéfinis styleN =styles["Normal"] # objet de classe ParagraphStyle() styleM =deepcopy(styleN) # "vraie copie" d'un style # Modification d'un de ces styles, pour disposer de deux variantes N et M : styleN.fontName ='Helvetica-oblique' styleN.fontSize =10 styleN.leading =11 # interligne styleN.alignment =TA_JUSTIFY # ou TA_LEFT, TA_CENTER, TA_RIGHT styleN.firstLineIndent =20 # indentation de première ligne styleN.textColor ='navy' # Données à traiter :

475 fichier ="document_5.pdf" bitmap ="bateau3.jpg" dimX, dimY = 10*cm, 10*cm

‫ظحلول التمارين‬

# dimensions imposées à l'image

# Construction de la liste de paragraphes : n, story = 1, [] ofi =open("document.txt", "r", encoding="Utf8") while 1: ligne =ofi.readline() if not ligne: break # ajouter un paragraphe, dans un style différent une fois sur trois : if n %3 ==0: story.append(Paragraph(ligne, styleN)) else: story.append(Paragraph(ligne, styleM)) n +=1 ofi.close() # === Construction du document PDF : can = Canvas("%s" % (fichier), pagesize=A4) largeurP, hauteurP = A4 # largeur et hauteur de la page can.setFont("Times-Bold", 18) can.drawString(5*cm, 28*cm, "Gestion des paragraphes avec ReportLab") # Mise en place de l'image, alignée à droite et centrée verticalement : posX =largeurP -1*cm -dimX # position du coin inférieur gauche posY =(hauteurP -dimY)/2 # (on laisse une marge de 1 cm à droite) can.drawImage(bitmap, posX, posY, width =dimX, height =dimY, mask="auto") # Mise en place des trois cadres entourant l'image : cS =Frame(1*cm, (hauteurP +dimY)/2, largeurP-2*cm, (hauteurP-dimY)/2-3*cm) cM =Frame(1*cm, (hauteurP -dimY)/2, largeurP-2*cm-dimX, dimY) cI =Frame(1*cm, 2*cm, largeurP-2*cm, (hauteurP-dimY)/2-2*cm) # Mise en place des paragraphes (fluables) dans ces trois cadres : cS.addFromList(story, can) # remplir le cadre supérieur cM.addFromList(story, can) # remplir le cadre médian cI.addFromList(story, can) # remplir le cadre inférieur can.save() # finaliser le document print("Éléments restants dans : {0}.".format(len(story)))

: 18.4 ‫التمرين‬
############################################################################# # Modifications à apporter au script spectacles.py du chapitre 17 pour qu'il # puisse produire une version imprimable (PDF) de la liste des réservations. ############################################################################# # Ajouter les importations suivantes pour l’utilisation sous Python 2 : from __future__ import unicode_literals # (celle-ci avant toutes les autres!) from codecs import open # Ajouter les importations suivantes pour pouvoir générer des documents PDF : from reportlab.pdfgen.canvas import Canvas from reportlab.lib.units import cm from reportlab.lib.pagesizes import A4 # Dans la définition de la classe Glob(), modifier le nom du fichier annexe : patronsHTML ="spectacles_2.htm" # Fichier contenant les "patrons" HTML

‫ظحلول التمارين‬
# Ce fichier annexe sera une copie de "spectacles.htm", dans lequel on aura # simplement modifié la rubrique suivante : [*toutesReservations*] Les réservations ci-après ont déjà été effectuées : {0} Veuillez cliquer ici pour accéder au document PDF correspondant. ########## # Dans le corps de la méthode toutesReservations() de la classe WebSpectacles(), # supprimer la dernière ligne "return mep(Glob.html[" ... etc", # et la remplacer par le code ci-après : # ======= Construction du document PDF correspondant : ======= # D'après le fichier de configuration tutoriel.conf, les documents # "statiques" doivent se trouver dans le sous-répertoire "annexes" # pour être accessibles depuis l'application web (mesure de sécurité) : fichier ="annexes/reservations.pdf" can = Canvas("%s" % (fichier), pagesize=A4) largeurP, hauteurP = A4 # largeur et hauteur de la page # Dessin du logo (aligné par son coin inférieur gauche) : can.drawImage("annexes/python.gif", 1*cm, hauteurP-6*cm, mask="auto") can.setFont("Times-BoldItalic", 28) can.drawString(6*cm, hauteurP-6*cm, "Grand théâtre de Python city") # Tableau des réservations : posY =hauteurP-9*cm # position verticale de départ tabs =(1*cm, 7*cm, 11*cm, 16.5*cm) # tabulations head =("Titre", "Nom du client", "Courriel", "Places réservées") # En-têtes du tableau : can.setFont("Times-Bold", 14) t =0 for txt in head: can.drawString(tabs[t], posY, head[t]) t +=1 # Lignes du tableau : posY -=.5*cm can.setFont("Times-Roman", 14) for tupl in res: posY, t = posY-15, 0 for champ in tupl: can.drawString(tabs[t], posY, str(champ)) # (Les valeurs numériques doivent être converties en chaînes !) t +=1 can.save() # Finalisation du PDF return mep(Glob.html["toutesReservations"].format(tabl, fichier))

476

: 19.2 ‫التمرين‬
##################################### # Bombardement d'une cible mobile # # (C) G. Swinnen - Avril 2004 - GPL # ##################################### from tkinter import * from math import sin, cos, pi from random import randrange from threading import Thread import time

# seulement pour le variante avec sleep()

477

‫ظحلول التمارين‬

class Canon: """Petit canon graphique""" def __init__(self, boss, num, x, y, sens): self.boss = boss # référence du canevas self.num = num # n° du canon dans la liste self.x1, self.y1 = x, y # axe de rotation du canon self.sens = sens # sens de tir (-1:gauche, +1:droite) self.lbu = 30 # longueur de la buse # dessiner la buse du canon (horizontale) : self.x2, self.y2 = x + self.lbu * sens, y self.buse = boss.create_line(self.x1, self.y1, self.x2, self.y2, width =10) # dessiner le corps du canon (cercle de couleur) : self.rc = 15 # rayon du cercle self.corps = boss.create_oval(x -self.rc, y -self.rc, x +self.rc, y +self.rc, fill ='black') # prédessiner un obus (au départ c'est un simple point) : self.obus = boss.create_oval(x, y, x, y, fill='red') self.anim = 0 # retrouver la largeur et la hauteur du canevas : self.xMax = int(boss.cget('width')) self.yMax = int(boss.cget('height')) def orienter(self, angle): "régler la hausse du canon" # rem : le paramètre est reçu en tant que chaîne. # il faut donc le traduire en réel, puis le convertir en radians : self.angle = float(angle)*2*pi/360 self.x2 = self.x1 + self.lbu * cos(self.angle) * self.sens self.y2 = self.y1 - self.lbu * sin(self.angle) self.boss.coords(self.buse, self.x1, self.y1, self.x2, self.y2) def feu(self): "déclencher le tir d'un obus" # référence de l'objet cible : self.cible = self.boss.master.cible if self.anim ==0: self.anim =1 # position de départ de l'obus (c'est la bouche du canon) : self.xo, self.yo = self.x2, self.y2 v = 20 # vitesse initiale # composantes verticale et horizontale de cette vitesse : self.vy = -v *sin(self.angle) self.vx = v *cos(self.angle) *self.sens self.animer_obus() def animer_obus(self): "animer l'obus (trajectoire balistique)" # positionner l'obus, en redéfinissant ses coordonnées : self.boss.coords(self.obus, self.xo -3, self.yo -3, self.xo +3, self.yo +3) if self.anim >0: # calculer la position suivante : self.xo += self.vx self.yo += self.vy self.vy += .5 self.test_obstacle() # a-t-on atteint un obstacle ? self.boss.after(15, self.animer_obus) else: # fin de l'animation :

‫ظحلول التمارين‬ self.boss.coords(self.obus, self.x1, self.y1, self.x1, self.y1) def test_obstacle(self): "évaluer si l'obus a atteint une cible ou les limites du jeu" if self.yo >self.yMax or self.xo self.xMax: self.anim =0 return if self.yo > self.cible.y -3 and self.yo < self.cible.y +18 \ and self.xo > self.cible.x -3 and self.xo < self.cible.x +43: # dessiner l'explosion de l'obus (cercle orange) : self.explo = self.boss.create_oval(self.xo -10, self.yo -10, self.xo +10, self.yo +10, fill ='orange', width =0) self.boss.after(150, self.fin_explosion) self.anim =0 def fin_explosion(self): "effacer le cercle d'explosion - gérer le score" self.boss.delete(self.explo) # signaler le succès à la fenêtre maîtresse : self.boss.master.goal() class Pupitre(Frame): """Pupitre de pointage associé à un canon""" def __init__(self, boss, canon): Frame.__init__(self, bd =3, relief =GROOVE) self.score =0 s =Scale(self, from_ =88, to =65, troughcolor ='dark grey', command =canon.orienter) s.set(45) # angle initial de tir s.pack(side =LEFT) Label(self, text ='Hausse').pack(side =TOP, anchor =W, pady =5) Button(self, text ='Feu !', command =canon.feu).\ pack(side =BOTTOM, padx =5, pady =5) Label(self, text ="points").pack() self.points =Label(self, text=' 0 ', bg ='white') self.points.pack() # positionner à gauche ou à droite suivant le sens du canon : gd =(LEFT, RIGHT)[canon.sens == -1] self.pack(padx =3, pady =5, side =gd) def attribuerPoint(self, p): "incrémenter ou décrémenter le score" self.score += p self.points.config(text = ' %s ' % self.score) class Cible: """objet graphique servant de cible""" def __init__(self, can, x, y): self.can = can # référence du canevas self.x, self.y = x, y self.cible = can.create_oval(x, y, x+40, y+15, fill ='purple') def deplacer(self, dx, dy): "effectuer avec la cible un déplacement dx,dy" self.can.move(self.cible, dx, dy) self.x += dx self.y += dy return self.x, self.y

478

479 class Thread_cible(Thread): """objet thread gérant l'animation de la cible""" def __init__(self, app, cible): Thread.__init__(self) self.cible = cible # objet à déplacer self.app = app # réf. de la fenêtre d'application self.sx, self.sy = 6, 3 # incréments d'espace et de self.dt =300 # temps pour l'animation (ms) def run(self): "animation, tant que la fenêtre d'application existe" x, y = self.cible.deplacer(self.sx, self.sy) if x > self.app.xm -50 or x < self.app.xm /5: self.sx = -self.sx if y < self.app.ym /2 or y > self.app.ym -20: self.sy = -self.sy if self.app != None: self.app.after(int(self.dt), self.run) def stop(self): "fermer le thread si la fenêtre d'application est refermée" self.app =None def accelere(self): "accélérer le mouvement" self.dt /= 1.5 self.app.bell()

‫ظحلول التمارين‬

# beep sonore

class Application(Frame): def __init__(self): Frame.__init__(self) self.master.title('>') self.pack() self.xm, self.ym = 600, 500 self.jeu = Canvas(self, width =self.xm, height =self.ym, bg ='ivory', bd =3, relief =SUNKEN) self.jeu.pack(padx =4, pady =4, side =TOP) # Instanciation d'un canon et d'un pupitre de pointage : x, y = 30, self.ym -20 self.gun =Canon(self.jeu, 1, x, y, 1) self.pup =Pupitre(self, self.gun) # instanciation de la cible mobile : self.cible = Cible(self.jeu, self.xm/2, self.ym -25) # animation de la cible mobile, sur son propre thread : self.tc = Thread_cible(self, self.cible) self.tc.start() # arrêter tous les threads lorsque l'on ferme la fenêtre : self.bind('',self.fermer_threads) def goal(self): "la cible a été touchée" self.pup.attribuerPoint(1) self.tc.accelere() def fermer_threads(self, evt): "arrêter le thread d'animation de la cible" self.tc.stop()

‫ظحلول التمارين‬

480

if __name__ =='__main__': Application().mainloop()

: ()Variante, utilisant une temporisation de la cible à l’aide de Time.sleep class Thread_cible(Thread): """objet thread gérant l'animation de la cible""" def __init__(self, app, cible): Thread.__init__(self) self.cible = cible # objet à déplacer self.app = app # réf. de la fenêtre d'application self.sx, self.sy = 6, 3 # incréments d'espace et de -----> self.dt =.3 # temps pour l'animation def run(self): "animation, tant que la fenêtre d'application existe" -----> while self.app != None: x, y = self.cible.deplacer(self.sx, self.sy) if x > self.app.xm -50 or x < self.app.xm /5: self.sx = -self.sx if y < self.app.ym /2 or y > self.app.ym -20: self.sy = -self.sy ---------> time.sleep(self.dt)

Similar Documents