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نستطيع أن نقول أن الكائن 1tex
هو ودجة تابعة للكائن 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-1y2, 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 = 2x1, 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[ = 1t ,'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 1return "Bonjour à tous !1return "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 ل يتم إعادة إرسالها إلى المرسل # ))"8conn_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 ))"8connexion.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 )"8msgClient = 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 ))"8self.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 ))"8nouv_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)