لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 10/27/21 في كل الموقع
-
الإصدار 1.0.0
10334 تنزيل
تُعد أنظمة التشغيل موضوعًا متقدمًا في العديد من برامج علوم الحاسوب، حيث يتعرف المتعلم على كيفية البرمجة بلغة C بحلول الوقت الذي يتعرف فيه على أنظمة التشغيل، وربما يأخذ المتعلم فصلًا دراسيًا في معمارية الحاسوب Computer Architecture قبل ذلك، فيصبح الهدف من تقديم هذا الموضوع عادةً هو عرض تصميم وتنفيذ أنظمة التشغيل للطلاب مع افتراض ضمني أن بعضهم سيجري بحثًا في هذا المجال، أو يكتب جزءًا من نظام تشغيل. هذا الكتاب مترجم عن الكتاب Think OS لكاتبه آلن داوني Allen B. Downey والذي يعد مسودة أولية لم تكتمل بصورة نهائية بعد إذ طُوّر لفصلٍ دراسي في كلية أولين Olin College يدعى أنظمة البرمجيات Software Systems. لا يفترض هذا الكتاب أنك قد درست معمارية الحاسوب، فيجب أن يمنحك فهمًا أفضل أثناء قراءته عن الحاسوب ومعماريته وكيف يعمل المعالج والذاكرة فيه وكيف تُدار العمليات وتُخزَّن الملفات وما يحدث عند تشغيل البرامج، وما يمكنك القيام به لجعل البرامج تعمل بصورة أفضل وأسرع بوصفك مبرمجًا. يشرح الفصل الأول بعض الاختلافات بين اللغات المُصرَّفة compiled واللغات المُفسَّرة interpreted، مع بعض الأفكار حول كيفية عمل المصرِّفات compilers، ويشرح الفصل الثاني كيف يستخدم نظام التشغيل العمليات لحماية البرامج قيد التشغيل من التداخل مع بعضها البعض. ويشرح الفصل الثالث الذاكرة الوهمية virtual memory وترجمة العناوين، ويتحدث الفصل الرابع عن أنظمة الملفات ومجرى البيانات، ويصف الفصل الخامس كيفية تشفير الأرقام والأحرف والقيم الأخرى، ويشرح أيضًا العامِلات الثنائية bitwise operators. أما الفصل السادس، فيشرح كيفية استخدام إدارة الذاكرة الديناميكية وكيفية عملها، ويدور الفصل السابع حول التخبئة caching وهرمية الذاكرة. ويشرح الفصل الثامن تعدد المهام multitasking والجدولة scheduling. ويدور الفصل التاسع حول خيوط POSIX وكائنات المزامنة mutexes، ويشرح الفصل العاشر المتغيرات الشرطية POSIX ومشكلة المنتج / المستهلك، ويدور الفصل الحادي عشر حول استخدام متغيرات تقييد الوصول POSIX وتطبيقها في لغة C. هذا الكتاب مرخص بموجب رخصة المشاع الإبداعي Creative Commons «نسب المُصنَّف - غير تجاري - الترخيص بالمثل 4.0». يمكنك قراءة فصول الكتاب على شكل مقالات من هذه الصفحة، «مدخل إلى أنظمة التشغيل»، أو تجدها مسردة بالترتيب التالي: الفصل الأول: مفهوم التصريف Compilation في لغات البرمجة الفصل الثاني: العمليات Processes في أنظمة التشغيل الفصل الثالث: الذاكرة الوهمية Virtual memory في نظام التشغيل الفصل الرابع: فهم الملفات Files وأنظمة الملفات file systems الفصل الخامس: تمثيل الأعداد والنصوص بالبتات وإجراء العمليات على مستوى البت الفصل السادس: إدارة الذاكرة Memory management في لغة C الفصل السابع: فهم عملية التخبئة Caching في معمارية الحاسوب الفصل الثامن: تعدد المهام Multitasking في الحواسيب الفصل التاسع: مفهوم الخيوط Threads في عملية المعالجة الفصل العاشر: المتغيرات الشرطية وحلها مشاكل التزامن بين العمليات في لغة C الفصل الحادي عشر: متغيرات تقييد الوصول Semaphores في لغة البرمجة سي C3 نقاط -
لا يمكن حساب تكلفة التطبيق بشكل صريح لأن التطبيقات تختلف في المواصفات والمميزات ولا توجد طريقة واضحة أو متبعة بشكل عام لحساب تكلفة أي مشروع، فالتكلفة تتبع نظام العرض والطلب ويمكن المساومة بين المبرمج والعميل على سعر المشروع والوقت المستغرق لإنشائه أيضًا وحتى التقنيات المستخدمه فيه، وأفضل طريقة لحساب متوسط تكلفة مشروع ميعن هي من خلال فحص سوق العمل والبحث عن مشاريع مشابهة تمت بالفعل، لمعرفة متوسط تكلفة المشروع، أما إن لم تتمكن من إيجاد مشروع مشابه فيمكنك أن تقوم بتحليل المشروع ومعرفة عدد الصفحات التقريبي فيه والأقسام في أغلب الصفحات وبالتالي سيمكنك أن تقوم بحساب تكلفة المشروع التقريبية وستستطيع تحديد الوقت الذي ستستغرقه في إنشاء هذا المشروع. يعتمد الأمر في البداية على العرض الذي تقدمه، ففي الغالب لا يكون العميل على دراية بالأمور التقنية مثل لغة البرمجة المستعملة في المشروع أو إطار العمل أو حتى قد لا يعرف الفرق بين واجهة المستخدم Frontend والواجهة الخلفية Backend، وبالتالي قد يكون طلب العميل هو إنشاء موقع كامل (Frontend & Backend)، ولكن طلبه لا يوضح هذا الأمر بشكل واضح، وذلك بسبب نقص الخبرة لدى العميل، وبالتالي يكون على المبرمج هنا أن يوضح هذا الأمر من بداية المشروع ويوضح للعميل ما سيحصل عليه بشكل كامل. أيضًا قد يكون لدى العميل تصور معين للمشروع النهائي، ولكن يمكن ان يحتوي تصوره هذا على مشاكل في بنية المشروع أو تجربة المستخدم أو حتى في تكلفة المشروع ككل، ويمكن للمبرمج في هذه الحالة أن يوضح للعميل أي الطرق أفضل بشكل بيسط لأداء مهمة معينة ولمذا يجب إستخدام تقنية معينة بدلًا من أخرى، فعلى سبيل المثال قد يرغب عميل ما إنشاء مدونة بلغة PHP ويمكن للمبرمج أن يقترح عليه أن يستخدم إطار عمل Laravel لإنشاء المشروع بشكل أسرع وأكثر آمانًا .. إلخ. وسيكون قرار العميل هو الفاصل في مثل هذه القرارات، فهذا مشروعه هو في النهاية. ولكي يكون العرض الذي تقدمه مناسبًا للعميل، فيجب فهم ما يريده العميل أولًا، ومحاولة عرض المميزات التي يقدمه المنتج الخاص بك مقارنة بما يريده العميل، فعلى سبيل المثال: إن كان العميل يريد إنشاء مدونة بإطار العمل Laravel، فيمكنك ان تقترح عليه المنتج الخاص بك الذي يوفر إنشاء التدوينات وتصنيفها في أقسام مع صفحة للبحث في المدونة وتحسين السيو الخاص بالموقع كذلك، بهذا الشكل يكون المنتج الخاص بك يغطي حاجة العميل، وكذلك يوفر له مميزات إضافية. قد تبدو المميزات السابقة بديهية وموجودة في أي مدونة، ولكن كما ذكرت سابقًا، فغالبًا لا يكون لدى العميل الفكرة الكاملة عن الأمور التقنية والمميزات التي يحتاجها بشكل كامل، لذلك يجب إستغلال هذا الأمر لعرض كل ما يقدمه منتجك. أما إن كان العكس، مثل أن يكون منتجك لا يحتوي على ميزة معينة يرغب به العميل، فيمكنك أن تعرض عليه إضافة هذه الميزة إلى منتجك وبيعه إياه -وسيكون هذا أفضل حل-، أو إستبدالها بميزة أخرى تغطي حاجته للميزة الأولى، مثل أن يرغب العميل بميزة إضافة وسوم إلى التدوينات، فتقترح عليه إستخدام الأصناف بدلًا منها مع توضيح سبب لذلك مثل أن الأصناف تكون أكثر تنظيمًا ويسهل على المستخدمين البحث فيها على سبيل المثال.2 نقاط
-
كيف تتعلم البرمجة هو سؤال من أشهر الأسئلة على الإنترنت التي تدور في فلك البرمجة وعلوم الحاسوب وشهرته تأتي من كون البرمجة programming من أهم المجالات وأكثرها طلبًا في وقتنا الحالي، ولا أحد ينكر أنها جزءٌ أصيلٌ مرتبط بالتقنية التي تشكل حاضرنا ومستقبلنا، فكل شيء أصبح مرتبط بالحواسيب ويحتاج الحاسوب إلى أن نخاطبه بلغته للتواصل معه وتوجيهه وتلقينه الأوامر. وبذكر الحاسوب، فقد أصبحنا محاصرين بكم كبير من الحواسيب حولنا بدءًا من هواتفنا الذكية التي هي حواسيب مصغَّرة مرورنا بآلة الغسيل وجلي الصحون وحتى الطائرات، ولنذكر أن عالمنا الآن يتجه إلى أتمتة المعلومات وحوسبة العمليات على جميع الأصعدة بطريقة سريعة وبعيدًا عن الروتين، كما يتجه إلى الاعتماد على التطبيقات الحاسوبية اعتمادًا كبيرًا وكل ذلك لا يتحقق إلا بوجود عدد كبير من المبرمجين لبرمجتها. تعد البرمجة من المهارات الرائعة صراحة إذ تمكنك من بناء تطبيقات مفيدة تحل الكثير من المشكلات الحياتية كما قد تخترع أنظمة وتقنيات مفيدة للبشرية مثل أنظمة الاتصالات وأيضًا الأنظمة البنكية وأنظمة البيع والشراء وغيرها التي سهلت حياة البشر وزادت من إنتاجيتهم وقدراتهم، فعملك كبمرمج يكسبك دومًا خبرات متجددة تزداد مع زيادة سنوات عملك كمبرمج، ولا ننسَ أن أشهر أثرياء عالمنا اليوم هم مبرمجون في الأصل. أضف إلى أن البرمجة توسع من خبرتك باطراد دائم، وتفتح لك أبوابًا لمهن مطلوبة في يومنا الحالي وبشدة أكثر من أي مهنة أخرى، لتؤمن لك دخلًا جيدًا بل وحتى حرية ومرونة في العمل أينما كنت حتى من منزلك فلا يتطلب في بعض الحالات وجود المبرمج في موقع العمل. بناءً على ما سبق، من الطبيعي أن ترى أعداد المتوافدين على باب تعلم البرمجة كبيرًا يزداد يومًا بعد يوم، وتحتاج قبل دخوله وبدء تعلم البرمجة إلى امتلاك بوصلة تهديك طيلة الطريق فبدونها ستضيع في هذا العالم الكبير الواسع وقد تنسحب منه وتعود أدراجك لعدم سلوكك الطريق الصحيح، لذا ستحصل في نهاية هذا المقال على بوصلة كيف تتعلم البرمجة تعينك على دخول هذا الطريق من أسهل طرقه وأسرعها إلى امتلاك الخبرة ودخول سوق العمل، فهل أنت جاهز؟ لننطلق! فهرس المحتويات ماذا تعني البرمجة؟ لماذا تتعلم البرمجة؟ طرق لتعلم البرمجة تعلم البرمجة عبر الجامعة تعلم البرمجة عن بعد عبر الإنترنت كيف تتعلم البرمجة مفاهيم تعلم البرمجة: التأسيس الصحيح أدوات تعلم البرمجة: اختيار الوجهة والتخصص نصائح لتعلم البرمجة أسئلة شائعة حول كيف تتعلم البرمجة هل تعلم البرمجة صعب؟ هل يؤثر نمط شخصيتي على تعلم البرمجة؟ هل احتاج إلى إتقان اللغة الإنجليزية لتعلم البرمجة؟ هل هناك مصادر عربية لتعلم البرمجة؟ هل احتاج إلى خبرة في الرياضيات لتعلم البرمجة؟ كيف تتعلم البرمجة من الصفر؟ أنا لست منظمًا فكيف ألتزم في تعلم البرمجة بنفسي؟ هل يمكنني تعلم البرمجة عبر الجوال؟ ماذا تعني البرمجة؟ البرمجة -كما ذكرنا باختصار في المقدمة- هي الطريقة الوحيدة للتخاطب مع الحواسيب والأجهزة الإلكترونية الذكية لإخبارهم بكيفية تنفيذ الأوامر والمهام التي يجب عليهم تنفيذها، فعلى الرغم من ظننا بأن الحواسيب والأجهزة ذكية كما يقال، إلا أن تلك المقولة خطأ لأن تلك الأجهزة لا تفكر ولا تتمتع بذرة من الذكاء وإنما تتسم بالسرعة والدقة الكبيرة في تنفيذ ما يُقال لها فقط. إذًا، البرمجة هي الطريقة وأسلوب سرد الخطوات المراد تنفيذها للحاسوب بناء على خوارزمية معينة أما الأداة المستخدمة في توضيح تلك الطريقة والخطوات فهي لغة البرمجة وبما أنها أداة فالأدوات كثيرة لتناسب مختلف الاحتياجات لهذا تجد الكثير من لغات البرمجة أما المفهوم والأسلوب فهو شبه ثابت لا يتغير وهنا قد تتطرق في طريق تعلم البرمجة إلى مفهوم لخوارزميات التي يمكن تنفيذها بأكثر من لغة برمجة. لماذا تتعلم البرمجة؟ هناك طلب كبير على مطوري البرامج اليوم، إذ سيزداد الطلب عليهم بنسبة 22 بالمائة بين عامي 2022 و 2030 وفقًا لمكتب إحصاءات العمل الأمريكي وذلك موازنةً بأربعة بالمائة بالنسبة للوظائف الأخرى، إذ تُعَدّ البرمجة مجال العصر والأكثر طلبًا في الوقت الحالي بين المهن الأخرى كما ذكرنا، فامتلاكك لهذه المهارة بمثابة امتلاكك لنقطة من نقاط قوة هذا العصر وتفتح لك أبوبًا واسعة في سوق العمل وضمن قطاعات مختلفة بسبب التقدم الرهيب في التقنية. كما تتعدد الأسباب حول الهدف من تعلم البرمجة، ولكن أكثرها انتشارًا هو ما يلي: تُعَدّ البرمجة مهنة عالمية عابرة للدول والقارات، إذ يمكن تطبيقها وتوظيفها في أيّ بلد كان مهما كانت ثقافته أو لغته. تعلم البرمجة مهم كون العالم يتجه إلى أتمتة المعلومات كما ذكرنا، وبالتالي تسريع المهام الروتينية وتوفير المزيد من الوقت والجهد البشري. يتعلق تعلم البرمجة بصورة أساسية بتعلم المنطق والرياضيات، لذا فهي توجّه ممتع لمن يهتم بمثل هذه المجالات. تحقيق مكاسب مادية، إذ يتقاضى المبرمجون رواتب عالية من خلال وظائف في شركات كبرى أو من خلال مشاريع ذاتية يصممها المبرمج بذاته ويبيعها لجهة معينة. تمكّنك من العمل الحر عبر منصات عمل حر مثل مستقل دون التقيد بجهة معينة كما يمكنك العمل من أيّ مكان كان من منزلك مثلًا، وبالتالي ستوفر عليك العديد من الالتزامات مثل قوانين بيئة العمل، وبعض النفقات مثل المواصلات. ممارسة البرمجة على أساس هواية إلى جانب عمل رئيسي آخر، فكثير من الأحيان قد تصادف أشخاصًا مهتمين بتعلم البرمجة وهم أساسًا أطباء على سبيل المثال وذلك لكونها شيء مكتسب بالتعلم والقراءة والممارسة وليست موهبةً أو شيئًا موروثًا. تعلم خوارزميات من خلال البرمجة يعزز عدد من المهارات لديك مثل مهارات التواصل وحل المشكلات وحتى مهارة الصبر. تفيد البرمجة في توسيع المعرفة وتعلّم تصميم حلول لأيّ مشكلة تواجهك، إذ تُعَدّ البرمجة طريقة تفكير منظمة وطريقة لتبسيط المشكلة وتفكيكها إلى أجزاء صغيرة يمكن التعامل معها بصورة أسهل. تعزيز الإبداع والاختراع لدى المبرمج، إذ سيصبح توّاقًا لتقديم أفضل ما لديه ومنافسة ذويه والسعي نحو تقديم مشاريع جديدة غير متوفرة سابقًا. طرق لتعلم البرمجة هنالك عدة طرق لتعلم البرمجة ودخول مجال علوم الحاسوب ولكن سأصنفها ضمن مسارين عريضين، الأول عبر التعليم الجامعي والثاني عبر التعليم الحر، وسأشرح كل منهما بالتفصيل مع توضيح مزايا وتحديات كل منهما. وإن كنت مهتمًا بتعلم البرمجة والتخصص بها ولم تختر مسارك بعد، فأنصحك أن تركز على هذا القسم بعناية لتحديد مسارك التعليمي. تعلم البرمجة عبر الجامعة يمكن تعلم البرمجة عبر مسار الجامعة بدخول إحدى التخصصات المرتبطة بها مثل تخصص علوم الحاسوب computer science أو تخصص هندسة البرمجيات software engineering أو هندسة الحاسوب computer engineering وستدرس بانتظام وعبر سنوات بين 4 إلى 5 سنوات هذا التخصص لتتخرج بدرجة بكالوريوس ويمكنك أن تكمل بعدها إلى مرحلة الماجستير والدكتوراه، وهذا الخيار مناسب تمامًا لك إن كنت تفكر في تسلق هذا السلم والذي تكون نهايته المهنية غالبًا العمل في مهنة التدريس في المؤسسات التعليمية. هذا الطريق أشهر الطرق لتعلم البرمجة ويتسم بأنه الأطول ولا يمكن البدء به إلا عند الدخول بالمرحلة الجامعية، ومن خلال هذه الطريق سيتلقى الشخص شهادة جامعية رسمية ومعترف عليها في سوق العمل بغض النظر عن الخبرة العملية التي يكتسبها خلال مسيرته الدراسية والتي تكون قليلة نوعًا ما وغير كافية. ضع في بالك أمر مهم في هذا المسار وهو أنك ستتعلم الكثير من المواد -وأحيانًا بتعمق- كما ذكرنا مثل الرياضيات المتقدمة وقواعد البيانات وأنظمة التشغيل والأنظمة المتقدمة والدارات الكهربائية والمنطقية والشبكات الحاسوبية وغيرها من المواد النظرية التي أما قد لا تهمك ولا ترغب في التخصص فيها والعمل فيها وإما أنها لا تفيد بشكل مباشر في الحياة العملية التطبيقية لاحقًا (تضيف مثلًا بعض الجامعات مواد إثرائية مثل تاريخ وجغرافية وأدب) مما يعني نسيانها لاحقًا وإضاعة للوقت والجهد. العائق الوحيد للدخول في هذا الطريق هو المُعدَّل الدراسي المطلوب بالنسبة للجامعات الحكومية والذي يكون مرتفعًا، وذلك لأن المقاعد الدراسية محدودة؛ أما بالنسبة للجامعات الخاصة، فستحتاج إلى مبلغ مالي قد تجده كبيرًا لتستطيع التسجيل في الجامعة وتتمة سنواتها الدراسية، فضلًا عن التفرغ الكامل للجامعة وتأمين النفقات اليومية البسيطة ما بين مواصلات ومعيشة ووربما تحتاج إلى كتب وقرطاسية وغيرها من نفقات إضافية طارئة، ولا ننسى أنه إذا كنت من محافظة تختلف عن المحافظة التي تقع فيها الجامعة، فإنك ستحتاج إلى مصروف إضافي يخص المواصلات بالإضافة إلى مصروف مخصص للسكن إذا لم ترغب في المكوث في السكن الجامعي أو إذا اخترت التسجيل في جامعة خاصة غير موجودة في مدينتك. والأهم مما سبق كله أن مجال علوم الحاسوب عمومًا والبرمجة خصوصًا مجال سريع التغير والتطور، فقد تتعلم تقنيات قديمة في بداية دراستك الجامعية لن تُستخدم في سوق العمل عند تخرجك بعد عدة سنوات أو أنها على الأقل تغيرت تغيرًا كبيرًا عما تعلمته وكم أسمع مشكلات تواجه طلاب الجامعات اليوم من هذا القبيل، لهذا السبب تجد أن أغلب الشركات لا تقبل بالشهادة الجامعية بمفردها بل تجري للمتخرج الجامعي اختبارًا تقنيًا أو تطلب منه مشروعًا يطلع عليه فريق برمجي متخصص ليتأكد من مواكبة معلوماته لأحدث التقنيات الحالية آنذاك. ومن الجدير بالذكر أنّ تعلم البرمجة عن طريق الجامعة يجبرك على الدراسة لسنين طويلة قد تصل إلى خمس سنوات وربما أكثر إذا لم تجتاز مواد محددة خلال السنة الدراسية، كما أنّ هذا الطريق لوحده لا يكفي للدخول إلى سوق العمل على الرغم من امتلاكك شهادة جامعية قوية وامتلاكك خلفية ثقافية علمية غير متاحة في الوسائل الأخرى، إذ ينبغي عليك اكتساب الخبرة اللازمة لتدعم سيرتك الذاتية، ولكن على الرغم من ذلك فبعض الشركات تهتم بالشهادة الجامعية في الدرجة الأولى وبعدها تنظر في الخبرة التي تملكها على أساس درجة ثانوية، إذ قد تمتلك برنامجًا تدريبًا خاصًا بالخريجين الجدد. والخلاصة، قد لا يكون هذا الخيار متاحًا لك -بسبب مجموعك في المرحلة الثانوية من التعليم- وباهظًا أيضًا وقد لا تملك وقتًا له وغيرها من التحديات وهنا ننصحك بخيار آخر لتعلم البرمجة وهو التعلم الحر عبر الإنترنت. تعلم البرمجة عن بعد عبر الإنترنت هنالك طريق آخر لتعلم البرمجة يعد الأسرع من بين عدة طرق لتعلم البرمجة غير التعليم التقليدي في الجامعات وهو التعلم الموجه عن بعد عبر الإنترنت نظرًا لانتشار الإنترنت في كل الأرجاء وازدياد سرعته، فأصبح بالإمكان اليوم مشاهدة فيديوهات والتواصل مرئيًا بدقة عالية دون الاكتراث لتكلفة الإنترنت أو سرعته. ونظرًا لأن مجال البرمجة لا يتطلب أي أمور وأدوات فيزيائية فأصبح تعلمه عبر الإنترنت شائعًا جدًا وسهلًا وعزز من ذلك تطوره السريع كما أشرنا وحاجة سوق العمل الكبير للمبرمجين مما جعل الشركات الموظفة تتنازل عن شرط وجود شهادة جامعية وأصبحت تطلب بدلًا من ذلك الخبرة والمشاريع العملية مع اجتياز اختبار أو مقابلة تقنية تجريها الشركة للمتقدمين المرشحين. تنقسم عملية تعلم البرمجة عبر الإنترنت إلى عدة مسارات فرعية تكون عمومًا إما منظمة ومهيكلة أو متفرقة. الدورات التعليمية تُعَدّ الدورات التعليمية من أشهر الطرق التي يلجأ إليها مَن يرغب في تعلم البرمجة سواءً كانت على أرض الواقع أو عبر الانترنت، إذ تأخذ بيده بدءًا من الصفر وتساعده كثيرًا في تعلم أيّ شيء جديد بصورة عامة وفي تعلم البرمجة بصورة خاصة وذلك عن طريق تسلسل مدروس ينتج عنه في ختام الدورة تعلم الأساسيات والتمكن بعض الشيء في النقاط التي تقدمها الدورة ليتابع بعدها المتلقي رحلة تعلمه عن طريق مصادر أخرى أو التسجيل في دورة تعليمة جديدة بمستوى أعلى. غالبًا ما تقترن الدورات التعليمية بجانب تطبيقي عملي يبني المتعلم عبرها مشاريع عملية تحاكي المشاريع المطلوبة في سوق العمل كما تفيده في بناء معرض أعمال عملية يغنيه عن عرض الشهادات النظرية. وقد يحتاج الطالب الأكاديمي الذي يدرس في الجامعة -كما ذكرنا في المسار الأول السابق- إلى دورات برمجية تعليمية مخصصة لترميم ما ينقصه أو اكتساب خبرة أوسع والتخصص فيه وبناء مشاريع عملية. لن تعيقك الدورات التعليمية من ناحية العدد المحدود للحضور والتكلفة الباهظة، إذ توجد العديد من الدورات البرمجية منخفضة التكلفة ومقبولة بالنسبة للطلاب مقابل الفائدة التي سيتلقونها، كما أنك لن تحتاج إلى إهدار 4 أو 5 سنوات من حياتك -على الأقل- كما في المرحلة الجامعية. تحدي مسار تعلم البرمجة عبر دورات تعليمية هو التسويف والتقصير، إذ يحتاج إلى تنظيم وعزيمة وإصرار وحمل النفس على التعلم وطلب العلم ووضع مخطط صارم وخطة واضحة من بداية الطريق، وهذا عكس المسار الأكاديمي الذي يكون فيه دور الجامعة تلقين المعلومة والتخطيط نيابة عنك مثل تحديد أوقات الامتحانات. ومن الجدير بالذكر أنه تهدف أكاديمية حسوب إلى توفير دورات تعليمية باللغة العربية تساعدك في تعلم البرمجة، كما يمكنك طرح أيّ سؤال على المدرِّبين أثناء التعلم إذا صادفت أيّ صعوبة، بالإضافة إلى أنه يمكنك مشاهدة أيّ دورة اشتركت فيها متى ما شئت، وفي حال أردت الانسحاب فبإمكانك التواصل مع فريق الأكاديمية لاسترداد ثمنها. دورة علوم الحاسوب دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب اشترك الآن الورشات والمخيمات البرمجية Bootcamps تعد المخيمات البرمجية فكرة أخرى منبثقة عن الدورات التعليمية فهي عبارة عن دورة تعليمية مكثفة ومضغوطة بفترة زمنية قد تقصر أو تطور بحسب البرنامج والتخصص وعادةً ما تمتد المخيمات البرمجية المتخصصة في مجال تطوير الويب أو تطوير تطبيقات الجوال من ستة أشهر إلى سنة. وتركز المخيمات البرمجية على تعلم البرمجة وتطبيقها مباشرةً على مشاريع عملية كبيرة تختمها بمشروع تخرج شامل، فيتخرج الطالب منها بحقيبة مشاريع مشرفة يعرضها في مقابلات العمل. القنوات والفيديوهات التعليمية هذه القنوات منتشرة انتشارًا كبيرًا على اليوتيوب مثل قناة أكاديمية حسوب، كما يوجد العديد من المبرمجين المحترفين الذين لديهم قناة على اليوتيوب تحتوي على سلسلة من المحاضرات التعليمية النظرية والعملية أو حتى مواضيع متفرقة، وفي هذا الطريق لن تحتاج إلى التقيد بمكان معيّن لحضور دورة تعليمية ما ولن تضطر إلى دفع تكاليفها، إذ تكون أغلبها مجانية، ولن تضطر إلى دفع أي تكلفة إضافية مثل المواصلات والسكن، كما أنك غير مقيّد بوقت محدد بما أنها عبر الانترنت ومسجَّلة مسبقًا. القيد الوحيد في هذا المسار أنه من المسارات الموجهة وغير المنظمة أو المهيكلة إذ ستتقيد بما هو موجود وقد تجد المعلومة وقد لا تجدها وغالبًا ستكون ضمن المستويات الأساسية دون المتقدمة ولن تجد من يجيب على أسئلتك أيضًا. الكتب والمقالات يفضل العديد من الأشخاص اللجوء إلى كتب برمجية للوصول إلى فهم أكثر دقة، والعديد من هذه الكتب توفرها أكاديمية حسوب مترجمة ومدققة جيدًا، كما يلجأ العديد من الراغبين في تعلم البرمجة إلى المقالات البرمجية لأخذ لمحة عامة حول تعلم البرمجة أو لتعلم البرمجة بصورة خاصة. تمتلك كل طريقة من الطرق السابقة ميزات ومساوئ وضحنا لتتمكن من تحديد الطريق الأنسب لك والذي يخدم أهدافك، ولكن ستكون أنت الرابح مهما كان طريقك في تعلم البرمجة، لذلك لا بد من تعلم البرمجة بصورة احترافية مهما كانت الوسيلة لتحقيق رغبتك في الدخول إلى سوق العمل بقوة وتحقيق دخل ممتاز. وفي نهاية هذا القسم، أنصحك بمشاهدة الفيديو التالي الذي يناقش فكرة الشهادات مقابل الخبرة في سوق العمل: المسابقات والتدريبات البرمجية تعزز المسابقات البرمجية والتدريبات البرمجية من عملية تعلم البرمجة تعزيزًا كبيرًا وتكسب المبرمج خبرة كبيرة واسعة تميزه عن بقية المبرمجين وترفع من قدره ومنصبه خصوصًا أن سمة البرمجة عمومًا هي حل المشكلات والبعد عن النمطية والروتين، فستصادف خلال رحلة البرمجة مشكلات منها القديم ومنها الجديد وغالبًا ستجد لكل مشكلة عدة حلول. أضف إلى ذلك أن أغلب أسئلة المقابلات البرمجية تكون على شكل مشكلة تتطلب إيجاد حل لها وكتاب شيفرته وغالبًا تكون تلك المشكلة شائعة وبسيطة وبمقابلة مباشرة يعني أن الفريق التقني يكون حاضرًا أثناء حلك للمشكلة، وينصب جل تركيزهم على كيفية إيجادك الحل وأسلوب كتابتك للشيفرة، فأحيانًا تجد حلًا لمشكلة يخلق مشاكل أخرى لم تخطر على بالك أو تفكر بها والأصوب أن يكون حلك شاملًا لا يؤدي إلى مشاكل أخرى ولا يسبب تأثيرات جانبية، ولا يمكن الوصول إلى تلك الدرجة من الخبرة والإتقان دون إطلاع على حلول مشاكل سابقة والتمرن على حل مشاكل جديدة ومناقشة الحلول للوصول إلى الحل الأفضل. هنالك الكثير من منصات التدريب تختلف باختلاف المواضيع ولغة البرمجة التي تريد التدرب عليها يمكنك البحث والسؤال وتجرب عدة منصات لتختار ما يناسب وشاع منها هذه الأيام منصة HackerRank ومنصة Codewars، ولكن لا أرى اللجوء إلى هذا الخيار إلى بعد تعلم المفاهيم الأساسية وعلى الأقل أساسيات لغة برمجة وعمومًا هنالك دومًا مستويات لكل تدريب يمكنك اختيار ما يناسب مستواك آنذاك. كيف تتعلم البرمجة؟ البرمجة عالم كبير مترامي الأطراف متباين التضاريس فيه السهل وفيه الصعب وإن كان الصعب يغلب على بدايته إذ يتسم طريق بداية تعلم البرمجة بالصعوبة وشدة الانحدار فهنالك الكثير من الأساسيات والمفاهيم التي عليك تعلمها وفهمها مثل مفهوم التعابير expressions والمتغيرات variables وأنواع البيانات data types والعمليات وحلقات التكرار والتعابير الشرطية والدوال والأصناف …إلخ. ثم تعلم تطبيق تلك المفاهيم بلغة البرمجة التي تريد استخدامها والتقنيات والمكتبات المرتبطة بها وقد تصل إلى بعض الطرق المسدودة -من جملة المشاكل الكثيرة التي تواجهك- التي تتطلب أن تشق طريقًا جديدًا لحلها. لا تخشَ مما سبق فكلما كان الطريق صعبًا ذقت حلاوة الوصول! مفاهيم تعلم البرمجة: التأسيس الصحيح ابدأ أولًا بتعلم المفاهيم البرمجية الأساسية، فعندما تتقن تلك المفاهيم تصبح قادرًا على تطبيقها على الأدوات مهما اختلفت وكثرت، وهنا وجب الفصل بين المفاهيم والأدوات، لأن الأدوات كما ذكرنا كثيرة وإن بدأت بها فقد تضيع وقد تواجه صعوبة في استخدام أداة لكثرة المفاهيم البرمجية المعقدة المبنية عليها وبدلًا من ذلك يجب البدء بصب أساس متين وإتقان المفاهيم البرمجة التأسيسية التي ستمكنك من استخدام أي أداة أو تقنية برمجية موجودة أو حتى مستحدثة جديدة قد تظهر مستقبلًا. أهم المفاهيم التأسيسية البرمجية التي يمكنك البدء بها هي: التفكير المنطقي الخوارزميات وحل المشكلات التعابير المنطقية أو البوليانية العمليات الرياضية الأساسية الأصناف classes والكائنات objects الدوال functions والتوابع methods بنى التحكم مثل التكرار Loop والشروط conditions التعاود Recursion المكتبات والحزم وأطر العمل أنواع البيانات أنواع لغات البرمجة البرمجة كائنية التوجه والبرمجة الوظيفية ننصحك بإتقان تلك المفاهيم وصقلها قبل البدء في تعلم أي لغة برمجة والتعمق فيها لأنك إن فعلت، فستلجأ إلى الرجوع إلى كل مفهوم والتعرف عليه مما يصعب عملية التعلم ويطيل الطريق عليك، وبعد التعرف عليها، يمكنك الانتقال إلى تعلم لغة البرمجة التي تمثل إحدى أدوات تعلم البرمجة والتخصص في المجال الذي تريده. أدوات تعلم البرمجة: اختيار الوجهة والتخصص لا أقصد بذكري أدوات تعلم البرمجة محررات النصوص وما سيلزمك أثناء البرمجة وكتابة الشيفرة، بل أقصد بها الأدوات والوسائل التي تتعلم البرمجة بها وتطبقها وأقصد تحديدًا لغات البرمجة والتقنيات المرتبطة بها التي تتعلم البرمجة بها. هنالك الكثير من لغات البرمجة والتقنيات البرمجية وهي ليست ثابتة بل تزداد وتتوسع يومًا بعد يوم، فلا تلبث إلا أن تسمع عن نزول لغة برمجة جديدة أو تقنية أو إطار عمل Framework جديد فإن تعلمت المفاهيم وأسست نفسك بها، فستطبقها مع أي لغة برمجة أو تقنية برمجية، فلغات البرمجة تنتمي إلى عائلات وتُشتق اللغات الجديدة من لغات سابقة وتُبنى تقنيات جديدة على أخرى سابقة أو مشابهة لها فلا وقت لاختراع العجلة من جديد، وفي هذا الصدد أنصحك بالاطلاع على مقال دليلك الشامل إلى لغات البرمجة. وقد تتساءل، كيف تتعلم البرمجة دون الاهتمام بتعلم لغة برمجة والانشغال بها؟ سؤالك صحيح، فستحتاج أثناء تعلم المفاهيم إلى أداة أي لغة برمجة تطبق عليها ما تعلمته ولكن في الوقت نفسه لا تريد الانشغال بتعلم لغة البرمجة تلك وتفاصيلها وشيفراتها وهنا لحل المشكلة جاءت لغات البرمجة المرئية مثل سكراتش Scratch وما شابهها. سكراتش هي لغة برمجة مرئية مؤلفة من كتل جاهزة يمكنك عبر سحبها وتركيبها بناء برنامج كامل، وهي مناسبة جدًا للبدء بتعلم البرمجة من الصفر وتأسيس المفاهيم البرمجية التي ذكرناها أهمها الخوارزميات والتفكير المنطقي، وبناءً على ذلك، تجد أن دورة علوم الحاسوب من أكاديمية حسوب تؤسس تلك المفاهيم أولًا بلغة سكراتش. بعد أن تتعلم المفاهيم، تبدأ بتطبيقها على لغة برمجة حقيقية ويمكنك بعدها التخصص بلغة البرمجة التي تريد تعلمها ودخول مجالها، وهنا يمكن أن أنصحك بدلًا من ذلك البدء بأساسيات لغة برمجة سهلة مثل لغة جافاسكربت JavaScript أو لغة بايثون والسبب سهولة كتابة الشيفرات فيهما وتنفيذها دون الحاجة إلى أي تعقيد في ضبط البيئة البرمجية لهما، ثم بعد ذلك يمكنك الانتقال إلى لغة البرمجة التي تُستخدم في المجال الذي تريد التخصص فيه مثل مجال تطوير مواقع الويب أو تطوير تطبيقات الجوال أو برمجة أنظمة التشغيل والأنظمة المدمجة. قد تسألني عن الأدوات والبرامج المطلوبة لكتابة الشيفرات وهنا أقول لك، لا تشغل نفسك بها فستتعرف عليها متى ما احتجتها فكل لغة برمجة أو تقنية لها محرر وأدوات تدعمها أكثر من غيرها. نصائح لتعلم البرمجة توجد بعض النصائح لتعلم البرمجة التي ستحتاجها أثناء رحلتك نسردها فيما يلي. حدد هدفك من تعلم البرمجة عليك تحديد هدفك حتى يسهل عليك تحديد التخصص الذي تريد الدخول إليه وبالتالي اللغة المستعملة في ذلك التخصص الأمر، فاللغات التي تُستخدم في مجال برمجة تطبيقات الويب مثلًا تختلف عن لغات برمجة تطبيقات الهاتف المحمول والتطبيقات المكتبة، كما سيسهل عليك تحديد طبيعة الجهاز الذي سيكون موجه إليه هذا التطبيق. تعلم لغة واحدة على الرغم من تشابه لغات البرمجة من حيث المفهوم، إلا أنّ لكل لغة برمجية بنية لغوية syntax تختلف عن غيرها، لذا من الأفضل عدم إجهاد نفسك في تعلم أكثر من لغة على التوازي حتى لا تتشتت وخاصةً إذا كنت في بداية طريقك في تعلم البرمجة. وعمومًا، يمكنك تعلم المفاهيم البرمجية بدايةً بلغة سكراتش ثم الانتقال إلى اللغة التي تريد التخصص فيها فالمفاهيم متشابهة كما ذكرنا ولكن صياغة اللغة وطريقة كتابة شيفراتها وترتيبها هي التي تختلف ولن يكون الاختلاف كبيرًا عادةً. ابدأ ببرامج بسيطة البرمجة مثلها مثل أيّ مجال آخر، أي حتى تتقنها عليك البدء من مكونات صغيرة وذلك بتصميم برامج بسيطة ثم تعديلها وتطويرها على عدة مراحل للوصول إلى تطبيق متكامل، فعلى سبيل المثال تطبيق الآلة الحاسبة يبدأ بعملية واحدة وبعدها يُطوّر ليشمل كافة العمليات وبعد ذلك يمكن تطويره ليتعامل مع المعادلات الرياضية المعقدة وهكذا. تحلى بالصبر جميعنا يريد أن يكتسب الخبرة بين ليلة وضحاها، لكن الأساس مهم جدًا وهذا يحتاج لأيام وأيام، لذا خذ الطريق من بدايته وأساسياته ولا تستعجل فتندم وتفقد الشغف وربما تتعب من مواصلة التعلم وتقرر الابتعاد نهائيًا، ولا تيأس عندما تواجهك أخطاء، فكلها ستدعم مسيرتك البرمجية في المستقبل وتكسبك الخبرة، ففي النهاية إنما العلم بالتعلّم وإنما الحلم بالتحلّم. صاحب مبرمجًا بما أنك قررت دخول عالم البرمجة، فحاول مصاحبة المبرمجين بدخول مجتمعات البرمجة على وسائل التواصل الاجتماعي وإبداء اهتمامك بأي محتوى برمجي على الإنترنت والتفاعل مع أصحاب المحتوى والتواصل معهم والاستفسار أو السؤال عما يلزمك أن احتجت، فبذلك يصبح لديك شبكة من الأصدقاء تستفيد منهم وتفيدهم بتبادل الخبرات. اعتمد على نفسك في حل الأخطاء البرمجية لا شك أنه كل منا سيواجه أخطاء في مسيرته التعليمية، ولكن من الأفضل عدم الاعتماد على الغير في حلها إلا بعد البحث والتقصي عن سبب المشكلة وإيجاد حلها بأفضل طريقة ممكنة، وفي حال عدم التوصل إلى حل بعد البحث المتواصل، فلا مانع من الرجوع إلى مبرمج محترف يبيّن لك سبب المشكلة وطريقة حلها، فاللجوء فورًا إلى مبرمج محترف لن يفيدك وربما قد تكون عبئًا عليه في حال تواصلت معه على أبسط الأخطاء وباستمرار دون بذل أيّ جهد منك في البحث. لا تتوقف عن الممارسة والتدريب كل علم لا يُمارس فمصيره الزوال والنسيان وكذلك البرمجة، إذ عليك التدرب أكثر فأكثر إلى حين إتقان هذه اللغة وعدم التوقف عن ممارستها بين الحين والآخر لتجنب خسارتها. أسئلة شائعة حول كيف تتعلم البرمجة هل تعلم البرمجة صعب؟ قد يقول قائل أن البرمجة صعبة وتعلمها أصعب، ولكن هل هذا صحيح؟ أقول أنه لا شيء سهل وأي مهنة فيها مستوى متفاوت من السهولة والصعوبة، والبرمجة من المهن التي تتطلب بذل جهد ذهني وفكري كبير ولا تتطلب بذل جهد بدني بينما تجد بعض المهن تتطلب بذل جهد بدني أكثر من الجهد الذهني وهكذا، وقد لا يناسب البعض بذل هذا الجهد الذهني الكبير والجلوس لفترات طويلة أمام الشاشة بتركيز كبير وهنا يجد تلك الصعوبة التي يشير إليها. إن أردت إجابة تفصيلية على هذا السؤال، فشاهد فيديو هل البرمجة صعبة. هل يؤثر نمط شخصيتي على تعلم البرمجة؟ التعامل مع البرمجة والحاسوب يتطلب بعض الانعزال عن الناس والأنشطة الاجتماعية والتعامل مع آلة أمامك بمخاطبتها عبر شيفرة طويلة تمضي أيامًا وأسابيعًا في كتابتها على انفراد وهذا قد لا يناسب بعض الأشخاص الاجتماعيين الذين يفضلون التعامل مع الناس والاحتكاك بهم، وهنا تظهر فكرة أن غالبية المبرمجين انطوائيين وأرى أنها صحيحة بنسبة ما، ويمكنك الاطلاع على مناقشة شخصيتك كمبرمج ومناقشة هل فعلاً تخصص البرمجة يؤثر بالسلب على الحياة الاجتماعية؟ في حسوب IO. هل احتاج إلى إتقان اللغة الإنجليزية لتعلم البرمجة؟ صحيح أن شيفرات لغات البرمج كلها مكتوبة باللغة الإنجليزية ولكن الحقيقة أنك لا تحتاج إلى إتقانها لتكون مبرمجًا محترفًا، إذ أن كل لغة برمجة مكونة من كلمات مفتاحية keywords محصورة العدد يمكنك حفظها وحفظ استخداماتها وقد قابلت عدة مبرمجين من بلدان آسيا وأوربا غير ناطقين باللغة الإنجليزية ولا يعرفونها بل أتحدث معهم بالإنجليزية فلا يستطيعون الرد علي وفي الوقت نفسه أتفاجأ من أنهم بنوا الكثير من المواقع وتطبيقات الجوال، حتى أن أحدهم بنى مكتبة CSS بلغته ويستطيع أي متحدث بتلك اللغة استخدامها. هل هناك مصادر عربية لتعلم البرمجة؟ قد يقول قائل، مراجع تعلم البرمجة قليلة في اللغة العربية أو ليست بجودة عالية، وأنا أقول أن المحتوى العربي غني جدًا بمصادر تعلم البرمجة بالعربية وهنا أحيلك إلى مقال الدليل الشامل لتعلم البرمجة باستخدام المصادر العربية لتتأكد من نفسك. كما يوجد دورات برمجة عربية تأخذ بيدك من الصفر وحتى الاحتراف مثل دورات أكاديمية حسوب، فالمميز في دوراتها أن الشرح بلغة عربية فصيحة وأنها توفر بيئة عربية متكاملة بدءًا من توفير التوثيقات البرمجية العربية التي تجدها في موسوعة حسوب وحتى المقالات البرمجية والكتب البرمجية في كافة المواضيع واللغات البرمجية وأخيرًا بمنصة أسئلة وأجوبة برمجية لطلب أي مساعدة أو الإجابة عن سؤال كما تجد دعمًا أيضًا في مجتمع البرمجة العربي في منصة حسوب IO. هل أحتاج إلى خبرة في الرياضيات لتعلم البرمجة؟ لا تحتاج إلى خبرة متقدمة في الرياضيات بل كل ما تحتاج إليه في البداية هو معرفة بالعمليات الرياضية الأساسية من جمع وطرح وضرب وقسمة ورفع للأس، وهنالك الكثير من القصص عن أطفال ويافعين بأعمار صغيرة تعلموا البرمجة وبدؤوا بكتابة برامج وألعاب. كيف تتعلم البرمجة من الصفر؟ إن لم تكن تريد الالتحاق بمسار جامعي، فهنا أنصحك باتباع دورات تعليمية أو ورشات أو مخيمات برمجية منظمة ومهيكلة ولا تتطلب أي خبرة برمجة مسبقة بحيث تبدأ معك من الأساسيات وتنطلق حتى المواضيع المتقدمة يقترن ذلك ببناء مشاريع عملية. وإن سألتني عن ترشيحات في المحتوى العربي، فأرشح دورات أكاديمية حسوب فكلها لا تتطلب خبرة برمجة مسبقة وتشرح المواضيع من الصفر، كما أنك عندما تشترك بدورة ما، فإن المسارات الأساسية من كل الدورات تصبح متاحة لك وهي ميزة ممتازة تساعدك على صب أساس قوي في كل المجالات البرمجية، وأضف إلى تلك الميزة، هنالك فريق من المبرمجين جاهز للرد على استفساراتك ومساعدتك بأي شيء، فهي خيار جيد تستحق النظر. أنا لست منظمًا فكيف ألتزم في تعلم البرمجة بنفسي؟ تعلم البرمجة -خصوصًا عبر دورات- يحتاج إلى حمل النفس على ما تكره وهو التنظيم، والتنظيم يحتاج إلى روتين، لذا ألزم نفسك بروتين قاسٍ وعاقبها إن تخلَّفت وقصرت مثل عدم الخروج إلى مكان محبب لك في عطلة نهاية الأسبوع، وفي الوقت نفسه كافئها إن أنجزت وثابرت، وفي هذا الصدد أنصحك بمقال دليلك لتنظيم حياتك ففيه فوائد كبيرة تساعدك على التنظيم لا تفوتها. وتذكر دومًا أن لذة الوصول تنسيك تعب الطريق وهذا يجب أن يدفعك دومًا إلى بذل الجهد ورفع الهمّة، وصحيح أن طريق تعلم البرمجة قد يكون طويلًا لكن بدايته متعبة فقط أما بعد ذلك فيصبح سهلًا، وتذكر أن المبرمج الخبير المتمرس يملك الكثير من المزايا بدءًا من الراتب المرتفع بقدر خبرته وحتى قدرته على تأسيس شركات برمجية أو إدارتها. هل يمكنني تعلم البرمجة عبر الجوال؟ حقيقةً، لا! يتطلب تعلم البرمجة حاسوبًا لتعلم البرمجة وكتابة الشيفرات البرمجية، فمن الصعب كتابة شيفرات برمجية على الهاتف الجوال هذا لم نتحدث عن إمكانية تنفيذ الشيفرات عليه وتجريبها وتنقيحها وتصحيح الأخطاء فيها. أما إن سألتني عن مواصفات الحاسوب، فيمكن استعمال أي حاسوب بدايةً وبعدها ستجد نفسك إما مرتاحًا بمواصفاته آنذاك أو تحتاج إلى مواصفات أخرى محددة، وقد تحتاج من البداية إلى وجود بطاقة شاشة منفصلة إن أردت التخصص في مجالات برمجة تتطلب معالجة رسوميات عالية مثل تطوير الألعاب أو محاكاة تطبيقات جوال أثناء تطويرها، وقد تحتاج إلى حاسوب ماك إن أردت تطوير أي شيء يتعلق بأنظمة ماك مثل تطوير تطبيقات iOS وهو حالة خاصة ومحددة فقط بمنتجات ماك. خاتمة أرجو أن أكون قد وفقت في الإجابة على سؤال "كيف تتعلم البرمجة؟" إجابة وافية شاملة في هذا المقال وأرجو أيضًا أن يكون هذا المقال بوصلة ترشدك للسير في الطريق الصحيح نحو تعلم البرمجة. وتذكر أنه بالنسبة لبعض المبرمجين، رحلة البرمجة لا تنتهي، فهنالك دومًا أشياء جديدة يمكن تعلمها وتطبيقها! وفي نهاية المقال، أحيلك لقراءة المقالات التالية المرجعية بعده التي تدور في فلك تعلم البرمجة ولكن قبل ذلك، قم وخذ قسطًا من الراحة! ملاحظة: كُتب هذا المقال سابقًا عام 2015 وقد جرى تعديله وتحديث محتواه لاحقًا. اقرأ أيضًا المدخل الشامل لتعلم علوم الحاسوب تعلم بايثون تعلم PHP فوائد تعلم البرمجة دليلك الشامل إلى أنواع البيانات تعلم لغة HTML أسهل لغات البرمجة البرمجة باستخدام سكراتش Scratch1 نقطة
-
يمكن القول إنك لن تحتاج لأكثر من اتصال بالإنترنت لتتعلم البرمجة من هذه السلسلة، ومع أن هذا يكفي من الناحية التقنية إلا أنه غير كافٍ لتعلم البرمجة، إذ يجب التنويه إلى أسلوب التفكير الذي ستتبعه في البرمجة، فلابد أن تتمتع بفضول للتعلم مع أسلوب منطقي لتفكير، وهما أمران لازمان لأي مبرمج ناجح. تبرز أهمية الفضول في البحث عن إجابات للمشاكل، وفي قدرتك على التجربة والتنقيب في الملفات بحثًا عن الأفكار والمعلومات المطلوبة لتنفيذ مهمة معينة، كما أن التفكير المنطقي مهم لأن الحواسيب آلات غبية بطبيعتها، ولا تستطيع فعل أي شيء سوى إضافة أرقام مفردة إلى جانب بعضها البعض، وتحريك بايتات من مكان لآخر. لقد كتب كثير من المبرمجين المهرة -لحسن الحظ- برمجيات تُخفي غباء الحواسيب هذا، لكنك بصفتك مبرمجًا ستتعرض لمواقف تواجه فيها ذلك الغباء الذي لم يعالجه أو يتعامل معه أحد قبلك، وهنا يجب أن تضع نفسك مكان الحاسوب وتفكر بدلًا عنه، وأن تعرف تحديدًا ما يجب عمله ببياناتك وزمن ذلك أيضًا. قد يكون هذا سردًا فلسفيًا لأمر يبدو تقنيًا وإلكترونيًا محضًا، غير أنك تحتاج إلى مثل تلك الفلسفة لتفهم هذا الشرح فهمًا جيدًا. بعد ذلك يأتي الجزء الخاص بالتدريب العملي الذي ستحتاج فيه إلى كتابة الأمثلة بيدك، أو نسخها من الكتاب إلى المحرر النصي عندك، ثم تشغيلها ورؤية النتائج، وستحتاج هنا إلى تثبيت بايثون Python على حاسوبك، وإلى متصفح قادر على تشغيل لغتي VBScript وJScript، مع الإشارة إلى أن أي متصفح حديث قادر على تشغيل جافاسكربت. بايثون Python يُعَد أحدث إصدار من لغة بايثون وقت كتابة هذه الكلمات -بلغتها الأصلية- هو 3.9، وحجم ملف تحميله من ActiveState يقارب 29 ميجا بايت لنسخة إصدار ويندوز (لا زالت ActiveState في الإصدار 3.8)، غير أنها تشمل كامل التوثيق والكثير من الأدوات التي سننظر في بعضها لاحقًا في هذه السلسلة، لذا تأكد من اختيار النسخة الموافقة لنظام تشغيلك. أما بالنسبة لنظام لينكس أو الأنظمة الشبيهة بيونكس عمومًا، فاطلب من مدير نظامك تثبيت النسخة المصدرية لبايثون على حاسوبك، لكن قد لا تحتاج إلى ذلك لأنها تأتي مدمجةً مسبقًا، ومثبتةً تلقائيًا في أغلب توزيعات لينكس، كما ستجدها في الإصدارات بتحزيمات موجهة للتوزيعات المشهورة مثل ريدهات Red Hat وديبيان Debian وأوبنتو Ubuntu وغيرها، بل قد تجد أن أغلب أدوات إدارة النظام في لينكس مكتوبة بلغة بايثون، ولا تقلق إذا كان إصدارك أقل من 3.6، فأي إصدار بعد 3.4 سيكون مناسبًا. تستطيع النظر في نسخ التحميل المختلفة لاختيار ما يناسبك من موقع التحميل الرئيسي لبايثون، أما مستخدمو ويندوز وماك فقد يفضلون نسخة ActiveState.com التي تأتي غالبًا مع بعض الأدوات الإضافية المدمجة في البرنامج نفسه، وقد تكون ActiveState متأخرةً قليلًا في إصدار نسخها الجديدة بسبب برنامجهم الخاص في التحزيم والاختبار، غير أنها تستحق الانتظار. دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن VBScript وجافاسكربت لقد سبق وأن قلنا إن أغلب المتصفحات تستطيع تشغيل جافاسكربت دون مشاكل، لكن VBScript عكس ذلك، فهي لن تعمل إلا في متصفح إنترنت إكسبلورر من مايكروسوفت، ولن تحتاج إلى تثبيت أي شيء إضافي لهاتين اللغتين، فإما أن تكونا لديك معًا إذا كنت تستخدم ويندوز، أو لن تكون لديك VBScript إذا كنت تستخدم ماك أو لينكس، والأمر الوحيد الذي عليك الانتباه إليه هنا هو أن بعض مديري الأنظمة القلقين بشأن الأمان قد يغلقون خاصية تشغيل السكربتات scripts في المتصفح لدواع أمنية، لكن هذا نادر الآن لأن أغلب المتصفحات تشغّل جافاسكربت. برمجة الحواسيب هي فن نجعل فيه الحاسوب ينفذ ما نرغب فيه بالضبط، وهي تتكون في أبسط صورها من سلسلة أوامر نعطيها للحاسوب لينفذها من أجل تحقيق هدف ما، وقد كان المستخدمون قديمًا أيام نظام دوس الخاص بويندوز، ينشئون ملفات نصيةً تحوي قوائم من تلك الأوامر، تُسمى ملفات الرُّقع أو باتش batch files (تدعى غالبًا سكربتات أو سكربت باتش)، وسبب تسميتها بذلك هو أنها تنفذ الأوامر مثل مجموعة أو رقعة واحدة، وكان امتدادها هو .BAT، لذا أُطلق عليها اسم ملفات بات BAT، ولا يزال بإمكاننا كتابة مثل تلك الملفات في بيئات ويندوز هذه الأيام رغم ندرة استخدامها، فمثلًا إذا كنت تكتب مستند HTML مكوَّن من ملفات كثيرة مثل الدليل الذي تقرؤه الآن، فسينشئ برنامج معالجة النصوص الذي تستخدمه نسخًا احتياطيةً من كل ملف كلما حفظ نسخةً جديدةً منه. فإذا رغبت في أن تضع النسخة الحالية من المستند -وهي الإصدارات الأخيرة من جميع ملفاته- في مجلد نسخ احتياطي backup في آخر كل يوم ثم حذف النسخ الاحتياطية التي لدى معالج النصوص؛ فيمكن كتابة ملف BAT بسيط لتنفيذ لك، وسيكون كما يلي: COPY *.HTM BACKUP DEL *.BAK إذا كان اسم الملف هو SAVE.BAT فسنكتب SAVE في محث DOS (يطلق على المحث أيضًا موجه أوامر) في نهاية اليوم بعد انتهاء العمل، وستُحفظ الملفات وتُحذف النسخ الاحتياطية تلقائيًا، وهكذا تكون قد رأيت مثالًا عمليًا لبرنامج بسيط. لاحظ أن مستخدمي نظام لينكس وغيره، بل حتى مستخدمي الإصدارات الحديثة من ويندوز، لديهم نسختهم الخاصة بهم من أمثلة تلك الملفات، والتي تُعرف عادةً باسم سكربتات الصدفة shell scripts، وهي أقوى بكثير من ملفات BAT الخاصة بنظام دوس، وتدعم أغلب التقنيات البرمجية التي سنتحدث عنها في هذا المقال. دورة تطوير التطبيقات باستخدام لغة JavaScript تعلم البرمجة بلغة جافا سكريبت انطلاقًا من أبسط المفاهيم وحتى بناء تطبيقات حقيقية. اشترك الآن تعريف البرنامج مرة أخرى لقد ذكرنا أعلاه مثالًا عن برنامج، لنبين بساطة مفهوم البرمجة في حد ذاته، لكن إذا خشيت عدم فهم البرمجة، فاعلم أن البرنامج ما هو إلا مجموعةً من التعليمات التي تخبر الحاسوب كيف ينفذ مهمةً ما، وهو يشبه وصفة الطعام التي تتكون من مجموعة من التعليمات التي تخبر الطاهي كيف يصنع طبقًا ما، فهي تصف مقادير المكونات (البيانات) وترتيب خطوات التنفيذ (العملية) المطلوبة لتحويل تلك المكونات إلى كعكة أو غيرها، فالبرنامج يشبهها كثيرًا في هذا. نظرة تاريخية نحن نستخدم لغةً للحديث مع الحواسيب، كما نستخدم لغات بيننا نحن البشر، غير أن اللغة الوحيدة التي يتحدثها الحاسوب تسمى اللغة الثنائية binary والتي توجد عدة نسخ منها، لهذا لا يعمل برنامج موجه لنظام ماك على ويندوز والعكس. ويُعَد تعلّم هذه اللغة صعبًا جدًا بالنسبة للبشر، سواءً قراءتها أو كتابة برامج بها، لذلك يجب أن نستخدم لغةً وسيطةً ثم نترجمها إلى اللغة الثنائية، تمامًا مثل شخصين من دولتين مختلفتين يتحدثان معًا وبينهما مترجم وسيط يفسر كلام كل منهما للآخر، فقد يتحدث أحدهما العربية والآخر الإنجليزية، فيترجم المترجم الكلام العربي إلى الإنجليزية وينقله إلى متحدث الإنجليزية، ثم يعكس العملية إذا تحدث الإنجليزي مخاطبًا الشخص العربي، وما سنستخدمه ليترجم لغتنا البرمجية إلى الحاسوب يسمى مترجمًا أو مفسرًا interpreter. وكما نحتاج مفسرًا لكل لغة من لغات البشر، فإننا نحتاج مفسرًا لكل لغة برمجية ليترجمها إلى لغة الحاسوب، فنحتاج مفسرًا من بايثون إلى لغة الآلة الثنائية binary، وآخر من VBScript إلى لغة الآلة كذلك، غير أن المبرمجين الأوائل كانوا مضطرين إلى كتابة الشيفرات الثنائية تلك بأنفسهم، أي بلغة الآلة التي ذكرناها قبل قليل وهي صعبة الكتابة والتعلم. بعد ذلك أتت المرحلة التالية التي أُنشئ فيها مفسر يحول كلمات مكتوبةً بأحرف بشرية إلى ما يقابلها من اللغة الثنائية، فبدلًا من تذكر أن الرمز 001273 05 04 يعني جمع 4 إلى 5، نستطيع الآن أن نكتب شيئًا مثل ADD 5 4، وقد سهلت تلك النقلة البسيطة الكثير من عمل البرمجة والتطوير، حيث كانت تلك الأنظمة البسيطة من الشيفرات هي لغات البرمجة الأولى التي كانت تختلف باختلاف نوع الحاسوب، وتسمى باسم اللغات المجمِّعة Assembler Languages، ولا زالت البرمجة بلغة التجميع مستخدَمةً هذه الأيام في بعض المهام المتخصصة، لكن هذا التطور كان بدائيًا في أسلوب إخبار الحاسوب بما يجب فعله، مثل نقل البيانات من هذا الموضع من الذاكرة إلى ذلك الموضع، وإضافة هذا البايت إلى ذلك البايت وغيرها من العمليات. البايت Byte هو وحدة بيانات تتكون من ثمانية بتّات bits أصغر منه ومجموعة فيه، وتلك البتات تكون إما 1 أو 0، وقد استُخدم البايت في البداية لتمثيل محارف النصوص، بحيث يمثل كل بايت حرفًا واحدًا. وبما أن هذا النمط من البرمجة لا زال صعبًا في تعلمه والعمل به لإنجاز أبسط المهام، فقد طور علماء الحوسبة مع الوقت لغات تسهل عملية البرمجة، وكأن ذلك جاء في وقته إذ تطورت المشاكل التي يواجهها المستخدمون في ذلك الوقت بسبب تطور المهام في أعمالهم اليومية، وهم يريدون للحواسيب أن تحل لهم تلك المشاكل. ولا زال هذا التنافس قائمًا، كما لا زالت لغات البرمجة الجديدة تظهر على الساحة. هذا ومع جعل البرمجة أمرًا مثيرًا يتغير كل يوم، إلا أنه يجعلك كونك مبرمجًا في حاجة إلى استيعاب المفاهيم البرمجية وطرق تنفيذها وتطبيقها في لغة واحدة بعينها، وسنناقش بعض تلك المفاهيم فيما يلي، لكن يجب أن تجعلها حاضرةً عندك تعود إليها دائمًا أثناء قراءتك للسلسلة. المزايا المشتركة لجميع البرامج خرج إدزجر ديكسترا Edsger Dijkstra قبل زمن بمفهوم اسمه البرمجة الهيكلية Structured Programming، يتحدث فيه عن إمكانية هيكلة جميع البرامج بأربعة طرق، هي الآتية: سلاسل من التعليمات: يتحرك فيها البرنامج من خطوة لأخرى في تسلسل صارم. الفروع Branches: هنا يصل البرنامج إلى نقطة اتخاذ قرار، فإذا تحققت نتيجة الاختبار -أي كانت القيمة true-، فإن البرنامج سينفذ التعليمات التي في المسار 1، وإذا كانت false فسينفذ الإجراءات التي في المسار 2، ويُعرف هذا بالبنية الشرطية لأن سير البرنامج يتوقف على نتيجة اختبار شرطي. الحلقات التكرارية Loops: تُكرَّر خطوات البرنامج في هذه الطريقة إلى أن نصل إلى اختبار شرطي ما، ينتقل تحكم البرنامج بعدها من الحلقة التكرارية إلى الجزء التالي من منطق البرنامج. الوحدات Modules: هنا ينفذ البرنامج تسلسلًا متطابقًا من الخطوات عدة مرات، فتُجمع تلك الإجراءات في وحدة واحدة، وهي برنامج صغير الحجم يمكن تنفيذه من داخل البرنامج الرئيسي، وقد تُسمى الوحدات بأسماء أخرى مثل الدوال functions أو الإجراءات procedures أو البرامج الفرعية sub-routines. احتاجت البرامج إلى بعض المزايا الأخرى، إضافةً إلى ما سبق كي تكون مفيدة: البيانات العمليات: مثل الجمع والطرح والموازنة وغيرها. إمكانية الإدخال والإخراج: مثل عرض النتائج على شاشة مثلًا. وبمجرد أن تستطيع استيعاب المفاهيم أعلاه، والتعرُّف على كيفة تنفيذ اللغة البرمجية التي تستخدمها لها، فستكون قادرًا على كتابة برامج بتلك اللغة. توضيح بعض المصطلحات إذا قلنا إن البرمجة هي الفن الذي نجعل فيه الحواسيب تنفذ ما نريده منها، فما هو البرنامج إذًا؟ في الواقع لدينا مفهومان مختلفان عن البرنامج، أولهما من منظور المستخدم، وهو ملف تنفيذي يثبَّت على الحاسوب ثم يمكن تشغيله لتنفيذ مهمة ما، فمثلًا يقول المستخدم أنه "يشغِّل" برنامج معالجة النصوص؛ أما المفهوم الثاني فهو من منظور المبرمج، وهو هنا مجموعة من التعليمات النصية الموجهة إلى الحاسوب المكتوبة بلغة برمجة ما، ويمكن ترجمتها إلى ملف تنفيذي. لهذا يجب أن تكون مدركًا عن أي المفهومين تتحدث حين تستخدم كلمة برنامج. يكتب المبرمجون برامجهم عادةً بلغة برمجة عالية المستوى تفسَّر إلى بايتات يفهمها الحاسوب، أي يكتب المبرمج شيفرةً مصدريةً source code؛ أما المفسر فيولد تعليمات مُصرَّفة object code، وقد يطلق على هذه التعليمات الناتجة عن التصريف أسماء أخرى مثل ملف تنفيذي أو شيفرة تنفيذية أو محمولة P-Code أو بايت كود Byte Code أو شيفرة ثنائية binary code، أو شيفرة الآلة machine code. كما يطلق على المترجم الذي يترجم لغة البرمجة العالية إلى لغة الآلة عدة أسماء، فقد يسمى بالمفسر interpreter أحيانًا، وبالمصرِّف compiler أحيانًا أخرى، وتشير هذه المصطلحات إلى نوعين من التقنيات المستخدمة في توليد الشيفرات الكائنية من الشيفرة المصدرية، فالمصرِّفات تنتج شيفرةً كائنيةً يمكن تشغيلها مستقلةً بذاتها دون الحاجة إلى المصرِّف في كل مرة يعمل فيها البرنامج، ويكون البرنامج في صورة ملف تنفيذي executable file؛ أما المفسِّرات فيجب أن تكون حاضرةً لتشغيل برامجها أثناء تنفيذها. لكن الفرق بين هذين المصطلحين صار ضبابيًا هذه الأيام بما أن بعض المصرفات تحتاج إلى مفسرات تكون حاضرةً لتنفيذ التحويل النهائي، كما تصرِّف بعض المفسرات شيفرتها المصدرية إلى شيفرة كائنية مؤقتة وتنفذها؛ أما من منظور المبرمجين فليس هناك فرق حقيقي، إذ تُكتب الشيفرة المصدرية وتُستخدَم أداة تسمح للحاسوب بقراءة الشيفرة وترجمتها وتنفيذها. هيكل البرنامج يعتمد الهيكل الدقيق للبرنامج على لغة البرمجة والبيئة التي يعمل فيها، لكن توجد بعض المبادئ الأساسية عمومًا: المحمِّل Loader: يحتاج كل برنامج أن يُحمّله نظام التشغيل إلى الذاكرة، وهذه وظيفة المحمل الذي يُنشأ عادةً بواسطة المفسر. تعريفات البيانات: تعمل أغلب البرامج بناءً على بيانات، وسنحتاج في مرحلة ما في شيفرتنا المصدرية إلى تعريف نوع البيانات الذي نعمل معه تعريفًا دقيقًا، وهذا يختلف من لغة برمجة لأخرى. التعليمات statements: وهي صلب البرامج، وهي تعدّل البيانات التي نعرّفها وتنفذ الحسابات وتطبع الخرج لنا.. تتبع أغلب البرامج إحدى الهيكلين التاليين: برامج باتش Batch Programs تُبدأ تلك البرامج عادةً من سطر الأوامر أو بواسطة أداة جدولة، وتتبع النمط التالي في الغالب. يبدأ البرنامج بتعيين حالته الداخلية كأن يعين الإجماليات totals إلى صفر، ويفتح الملفات المطلوبة، وبمجرد أن يكون جاهزًا للعمل، فإنه يقرأ البيانات من المستخدم بعرض موجهات الأوامر أو المحثات على الشاشة أو من ملف بيانات، أو بالطريقتين معًا، حيث يعطي المستخدم اسم ملف البيانات ثم تُقرأ البيانات الفعلية من الملف، بعد ذلك يعالج البرنامج البيانات معالجةً تتضمن عمليات رياضيةً أو تحويلات للبيانات أو غير ذلك، أخيرًا، تُخرج النتائج إلى شاشة عرض أو تُكتب إلى ملف، وستكون جميع البرامج التي نكتبها في الأجزاء الأولى من السلسلة من هذا النوع، أي برامج باتش أو رُقع. البرامج الحدثية Event driven programs تُعَد أغلب الأنظمة ذات الواجهة الرسومية مثل ويندوز أو أندرويد، وأنظمة التحكم المدمجة Embedded control systems مثل جهاز المايكروويف لديك أو الكاميرا أو غيرهما، من البرامج الحدَثية، أي يتوقف سيرها على وقوع أحداث معينة، بحيث يرسِل نظام التشغيل أحداثًا إلى البرنامج فيستجيب لها وفقًا لوصولها إليه، وقد تكون تلك الأحداث أمورًا يفعلها المستخدم مثل نقر زر الفأرة أو ضغط زر ما، أو أمورًا يفعلها النظام نفسه مثل تعديل الساعة أو تحديث الشاشة، وتبدو البرامج الحدثية في الغالب كما يلي: يبدأ البرنامج هنا بتعيين حالته الداخلية، ثم ينتقل التحكم إلى بيئة التشغيل (تسمى أحيانًا وقت التشغيل runtime)، ويوفر نظام التشغيل تلك البيئة في الغالب، كما ينتظر البرنامج حلقة الحدث لتلتقط تفاعل المستخدم الذي يترجَم إلى أحداث بعدها، ثم ترسَل تلك الأحداث إلى البرنامج كي يتعامل معها حدثًا حدثًا، وينفذ المستخدِم الإجراء النهائي الذي ينهي البرنامج، فيُنشَأ حدث خروج ويُرسَل إلى البرنامج. خاتمة ذكرنا في هذا المقال أنك تحتاج إلى التفكير المنطقي والفضول من أجل تعلم البرمجة، ويمكن الرجوع في هذا إلى مقال الدليل الشامل في تعلم البرمجة من أكاديمية حسوب، ومقال حل المشكلات وأهميتها في احتراف البرمجة من الأكاديمية أيضًا، كما يجب أن نذكر أن كل لغات البرمجة المذكورة أعلاه متاحة للتحميل مجانًا، وبهذا لا يبقى سوى أن تأتي بذهن حاضر، مع قليل من حس الدعابة والمرح لنبدأ البرمجة، إذ تسمح لنا لغات البرمجة بالتحدث مع الحواسيب بلغة قريبة من لغات البشر المنطوقة، لكنها تختلف عن الطريقة التي تتحدث الحواسيب أو تفكر بها، وقد قلنا إن البرامج تعمل وفقًا للبيانات، وأنها إما برامج رُقع batch programs أو برامج حدثية Event driven تتصرف وفقًا للأحداث التي تُرسل إليها. ترجمة -بتصرف- للفصلين ?What do I need و?What is Programming من كتاب Learning to Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: بداية رحلة تعلم البرمجة تعلم البرمجة أسهل لغات البرمجة ما هي البرمجة ولماذا تصبح مبرمجا1 نقطة
-
استخدام بايثون سنفترض أنك قد ثبّتّ إحدى إصدارات بايثون على حاسوبك، فإذا لم تفعل فاذهب إلى موقع بايثون واجلب النسخة الأحدث منها واتبع إرشادات التثبيت على حاسوبك، لاحظ أن بايثون متاحة لأغلب أنواع الحواسيب المتوفرة في السوق، وستجد ملفات تثبيت لنسختي 64 بت و 32 بت من ويندوز، وكذلك نظام MacOS؛ أما لينكس فستجدها من خلال مدير الحزم في توزيعتك، فإذا لم تكن تعلم معمارية حاسوبك فاختر نسخة 32 بت، وانتبه عند التثبيت إلى خيار إضافة بايثون إلى Path، وهو متغير بيئة سنحتاج أن نضيف بايثون إليه كي يراها ويندوز في سطر الأوامر، بالشكل التالي: أما إذا لم تفعل ذلك أو نسيته أو لم تكن نسخة التثبيت تحتوي على ذلك الخيار، فاتبع الإرشادات التي نذكرها في الفقرة التالية. سطر أوامر ويندوز لقد بدا منذ كتابة هذه السلسلة -بنسخته الأجنبية لأصلية- أن العديد من مستخدمي ويندوز ليسوا معتادين على التعامل مع سطر أوامر MS Dos، لذا سنشرح كيف يمكن الوصول إلى تلك الأداة دون الاستغراق في التفاصيل غير الضرورية. توجد عدة طرق للوصول إلى سطر الأوامر أبسطها الضغط باستمرار على زر ويندوز وحرف R من أجل فتح نافذة Run، ثم كتابة cmd في مربع الحوار الذي سيظهر لك ثم الضغط على OK، وهنا يجب أن ترى نافذةً سوداء فيها نص أبيض مثل هذا: C:\WINDOWS> يشير السطر أعلاه إلى المجلد الذي نحن فيه، فإذا كتبنا DIR وضغطنا على زر الإدخال Enter؛ فستعرَض لنا قائمة بجميع الملفات التي في ذلك المجلد؛ أما إذا كتبنا python فيجب أن نرى المحث >>> الخاص ببايثون. قد لا تستطيع CMD العثور على بايثون بسبب بعض إصداراته الأخيرة التي لم تأتي بتلك الإعدادات، ولهذا فإنا لم تستطع إيجادها فستحتاج إلى ضبط متغير بيئة اسمه Path، وذلك بفتح مدير الملفات في ويندوز إما بالطريقة العادية، أو بضغط زر ويندوز مع حرف E (لفتح المتصفح)، ثم الذهاب إلى قسم This PC، والنقر بالزر الأيمن لاختيار Properties التي ستفتح نافذة About الخاصة بحاسوبك، والتي تحوي المعلومات الأساسية عنه. ستجد في تلك الصفحة خيار Advaned System Settings، اضغط عليه لتفتح لك نافذة أخرى ثم اختر تبويب Advanced. سترى زر Environment Variables في أسفل النافذة، اضغط عليه لتذهب إلى نافذة جديدة، وسترى أن Path معرَّف بالفعل كمتغير للنظام. اختره ثم انقر على زر Edit في يمين النافذة. انتبه في هذه الخطوة لئلا تحذف المسار الموجود بالخطأ، فإذا مسحت شيئًا من غير قصد فاضغط زر Esc في لوحة المفاتيح، أو استخدم زر Cancel في النافذة المفتوحة لتخرج منها وتعيد المحاولة. اذهب إلى نهاية الحقل Variable Value وأضف فاصلةً منقوطة ;، ثم المسار الكامل لمجلد بايثون التنفيذي لديك، بعد ذلك اضغط زر الإدخال Enter لتكتمل العملية، فإذا لم تعرف المسار الكامل إلى بايثون فابحث في مدير الملفات عن الملف python3.exe، وستكون محتويات العمود In Folder الذي في شاشة البحث هي المسار الكامل، وقد تضطر إلى إعادة التشغيل كي يعتمد نظام التشغيل الإعدادات الجديدة. اكتب python في سطر الأوامر لنظام تشغيلك من أي مجلد شئت وسترى المحث الثلاثي لبايثون، ونستطيع من هنا كتابة CD إلى المجلد الحامل للسكربت الخاص بنا لننتقل إليه -حيث تشير CD إلى Change Directory-، كما ستجد قائمةً من الأوامر المتاحة التي يمكن كتابتها في سطر الأوامر في نظام المساعدة المدمج في CMD نفسها، من خلال كتابة help في سطر الأوامر؛ أما إذا أردت معرفة المزيد من العلومات عن أحد الأوامر، فاكتب اسم الأمر متبوعًا بـ /?، فإذا أردنا مثلًا عرض صفحة المساعدة الخاصة بالأمر DIR فسنكتب ما يلي: C:\WINDOWS> DIR /? أخيرًا يمكن إنشاء اختصار على سطح المكتب بالنقر بالزر الأيمن على سطح المكتب، ثم اختيار جديد New، ثم اختصار Short-cut، واكتب cmd في صندوق الموقع location داخل صندوق الحوار الذي يظهر لك، ثم انقر على التالي Next، ثم غير الاسم إلى شيء مثل Command Prompt أو نحوها. حين تنتهي انقر على Finish لتظهر أيقونة جديدة على سطح المكتب مثل اختصار إلى سطر الأوامر. خذ وقتك في استعراض هذه الأداة، فرغم أنها قد تبدو بدائيةً إلا أنها أقوى مما تتخيل، وخاصةً في إنجاز المهام المتكررة، على عكس الأدوات ذات الواجهة الرسومية مثل مدير الملفات، حيث يمكنك قراءة المزيد عنها في Computer Hope للبدء في تعلمها. عودة إلى بايثون بما أن مستخدمي ويندوز قد ثبتوا بايثون باتباع الخطوات السابقة، فسنفترض أن مستخدمي لينكس متعودون على استخدام الطرفية، أما مستخدمي نظام ماك فيمكنهم تشغيل برنامج الطرفية بالنقر على الأيقونة كالمعتاد، وهنا يجب أن يظهر محث بايثون كما يلي: Python 3.6.2 (default, Jul 29 2017, 00:00:00) [GCC 4.8.4] on linux Type "copyright", "credits" or "license()" for more information. >>> وفي خيار بديل لسطر الأوامر ذاك؛ قد تجد اختصارًا إلى شيء اسمه IDLE، أو Python GUI في قائمة ابدأ لديك، وهو بيئة برمجة مخصصة لبايثون، وتوفر كثيرًا من الأدوات والأوامر المفيدة للمبرمجين، فإذا شغلته بدلًا من سطر الأوامر فستحصل على نافذة مستقلة لسطر الأوامر مع بعض الألوان المميزة للخطوط، وقد كتب Danny Yoo دليلًا مفصلًا لهذه البيئة يمكنك قراءته والاطلاع عليه إذا أردت استخدامه بدلًا من سطر الأوامر العادي، وهو يكرر بعض المعلومات التي ذكرناها من قبل، لكن تكرار التعليم لا يضر، كما تستطيع الاطلاع على التوثيق الرسمي لبيئة IDLE كذلك إن شئت. أما إذا كنت تفضل التدريب المرئي بالفيديو، فهناك الكثير من الفيديوهات المتعلقة بالبرمجة على يوتيوب، ويُرى أن تعلم المفاهيم واستخدام الأدوات من الفيديو أمر ممكن، شرط أن توقِف الفيديو مع كل سطر أوامر يُكتَب كي تتابع الشرح جيدًا، كما يوصى بكتابة الشيفرة وتشغيلها بنفسك لتتذكر ما تتعلمه، لذا فإن أردت مشاهدة الفيديو لفهم المبدأ فلا بأس، لكن عد إلى هنا مرةً أخرى واقرأ حول ذلك المفهوم واكتب الشيفرة وجربها بنفسك، ثم عدل فيها وجرب إلى أن تصل إلى توقع التغييرات التي ستحدث، وتلك هي الطريقة الوحيدة لتعلم البرمجة في رأيي. المثير في بيئة IDLE أنها برنامج مكتوب ببايثون، فهي تبين لك قوة اللغة بمثال حي، وتوضح ما يمكن تنفيذه بها؛ أما إذا حصلت على بايثون من ActiveState أو كنت قد حمّلت نسخًا مخصصةً لويندوز -مثل حزمة PyWin32-؛ فيمكنك الوصول إلى بيئة برمجة رسومية أخرى تشبه IDLE لكنها أكثر أناقةً منها تسمى Pythonwin. لا شك أن كلا البيئتين تسهلان البرمجة أكثر من سطر الأوامر العادي، لكننا نفضل استخدام الأدوات البسيطة في بداية التعلم لإدراك المفاهيم التي نشرحها إدراكًا أعمق. كلمة حول رسائل الخطأ سترى أثناء كتابة التعليمات البرمجية ببايثون رسائل خطأ لا محالةً، وستبدو مثل هذه: >>> print( 'fred' + 7 ) Traceback (most recent call last): File "<input>", line 1, in ? TypeError: cannot concatenate 'str' and 'int' objects لا تشغل بالك بالمعنى الدقيق لهذه الرسالة الآن، وإنما نريدك أن تنظر إلى هيكلها، فسطر '>>> print ...' مثلًا هو السطر الخاطئ، أما السطران التاليان فيصفان مكان الخطأ، وقد تتكون رسالة الخطأ من عدة أسطر في البرامج المعقدة، فقد تقترح كلمة Traceback مثلًا أن الرسالة تتضمّن أثرًا أو سجلًا لكل ما كان البرنامج يفعله عند وقوع الخطأ، وقد يكون هذا مربكًا للمبتدئين، لكن ثق أنك مع الخبرة ستسعد بوجود رسالة الخطأ تلك، وستعلم أن الأسلوب الأمثل لقراءتها حينئذ سيكون من الأسفل، وتصعد لأعلى بقدر حاجتك من الرسالة. نعود إلى رسالة الخطأ السابقة حيث يشير 'line 1 in ?' إلى السطر رقم 1 في التعليمة التي نكتبها، فلو كان برنامجًا أطول وكان مخزّنًا في ملف مصدري فسيحل اسم الملف الحقيقي محل <input>، بينما يخبرنا السطر 'TypeError...' بالخطأ الذي يراه المفسر، وقد يوجد أحيانًا محرف إقحام ^ يشير إلى الجزء الذي تراه بايثون خطأً، لكن هذا التقرير يكون غير صحيح في العادة، فقد يكون الخطأ الحقيقي في مكان سابق للموضع الذي أشارت إليه بايثون، أو حتى قبله بسطر أو سطرين، فالحواسيب آلات غبية بأي حال كما قلنا من قبل. تُستخدم بيانات الأخطاء تلك لمعرفة ما يحدث في الشيفرة التي بين أيدينا، وقد يكون سبب الخطأ البرمجي بشريًا في الغالب، فرغم أن الحواسيب آلات غبية، إلا أنها آلات غاية في الدقة، فلعلنا أخطأنا في كتابة كلمة أو تعليمة أو نسينا علامة اقتباس أو فاصلةً منقوطةً مثلًا، ولدينا عمومًا ثلاثة أنواع من الخطأ التي سنواجهها: الخطأ اللغوي syntax error، وهو يعني أن بايثون لا ترى أن ما أُدخل إليها صالح، وقد يكون سببه نسيان علامة ترقيم أو خطأً في هجاء كلمة. خطأ وقت التشغيل runtime error، وذلك حين يكون البرنامج صالحًا لكن لا يمكن تنفيذه لسبب ما، كما في محاولة تنفيذ عملية غير مسموح بها أو غير صالحة، مثل طلب قراءة ملف غير موجود. خطأ دلالي semantic، حيث يعمل البرنامج ولا تظهر أي رسالة خطأ، لكنه يخرج لنا مخرجات خاطئةً غير التي يفترض به إخراجها، فإذا كتبنا مثلًا برنامجًا ليخبرنا بعدد كلمات الملف الذي تقرؤه الآن، وأخرج لنا أنه يحوي خمس كلمات فقط، فستكون هذه النتيجة خاطئةً قولًا واحدًا، فهنا يكون خطأ البرنامج دلاليًا. ستكون أغلب الأخطاء التي تتعرض لها في البداية أخطاءً لغويةً أو أخطاء وقت تشغيل إلى أن تبدأ بتصميم برامجك الخاصة، فحينها سترتكب أخطاء دلالية، وتسمى تلك العملية حينئذ بالتنقيح debugging، وتُسمى الأخطاء التي سترتكبها آنذاك بالزلات البرمجية bugs، لكن الترجمة الحرفية لاسمها الأجنبي bug هي عثة، وهي حشرة صغيرة سميت الأخطاء البرمجية باسمها لأسباب تاريخية، فقد كانت أولى الأخطاء التي حدثت في الحواسيب الأولى بسبب عثة علقت داخل الحاسوب وتسببت في حرق بعض داراته الكهربائية، وعلى الرغم أن الكلمة نفسها قد استُخدمت للدلالة على الأخطاء البرمجية قبل هذا بعدة عقود، لكنها لم تثبت إلا مع تلك الحادثة، لكننا سنستخدم اصطلاح الزلات البرمجية لقربها من المفهوم العربي للفعل ذاته. وبالعودة إلى الخطأ الذي ارتكبناه في المثال السابق والذي تسبب في إخراج رسالة الخطأ لنا، فقد كان محاولة إضافة عدد إلى سلسلة محارف، وهو خطأ دلالي، لكنه ينتج لنا خطأ وقت تشغيل أيضًا، فليس هذا مسموحًا لك في بايثون، لذا كانت رسالة الخطأ تمثل اعتراضًا من اللغة على ما فعلناه، فأخبرتنا أن هناك TypeError، وسنتحدث عن هذه الأنواع في مقال لاحق من هذه السلسلة. وبغض النظر عن الأداة التي تريد استخدامها سواء كانت سطر الأوامر أو بيئة IDLE أو Pythonwin، فنحن الآن جمعنا عدتنا وجاهزون للبدء في إنشاء بعض البرامج البسيطة باستخدام بايثون. جافاسكربت إذا أردنا إنشاء برامج جافاسكربت في متصفح، فسنحتاج إلى مزيد من الإجراءات التي علينا تنفيذها، حيث سنحتاج مثلًا إلى إنشاء ملف HTML نستطيع تحميله إلى متصفح، وهذا الملف لا يحوي إلا نصًا مجردًا نستطيع إنشاءه في محرر نصي بسيط مثل Notepad أو أي محرر نصي آخر، ثم حفظه بالامتداد .htm أو .html، وسيبدو بالشكل الآتي: <html> <body> <script type="text/javascript"> document.write('Hello World\n'); </script> </body> </html> سيكون الجزء الواقع بين بداية الوسم <script> ونهايته هو برنامجنا، ولن تعرض جميع وسوم HTML في كل مرة أثناء شرحنا في هذه السلسلة، لذا عليك أن تنسخ هذا الملف في كل مرة مثل قالب ثم تستبدل الشيفرة التي تريد تجربتها بما هو موجود بين الوسمين <script> و</script>، ثم افتح ملف HTML ذاك في متصفح ويب عن طريق النقر عليه في مدير ملفاتك، يجب أن يشغّل نظامك عندئذ برنامج المتصفح ويحمّل الملف الذي سيتسبب بالتبعية في تنفيذ برنامجنا. VBScript يمكن القول أن VBScript هي نفسها جافاسكربت لكن مع استبدال الاسم "vbscript" الذي في type= بالنص القديم الموجود "javascript"، كما يلي: <html> <body> <script type="text/vbscript"> MsgBox "Hello World" </script> </body> </html> لاحظ أن متصفح إنترنت إكسبلورر الخاص بمايكروسوفت هو الوحيد القادر على تشغيل VBScript، أما المتصفحات الأخرى فلا تدعم إلا جافاسكربت بما في ذلك متصفح Edge الخاص بويندوز، والذي استبدلت إنترنت إكسبلورر به، لذا يبدو أن أيام VBScript صارت معدودةً. أخطاء VBScript وجافاسكربت سنحصل على صندوق حوار في كل من جافاسكربت وVBScript يخبرنا برقم السطر الذي فيه الخطأ، كما سيكون لدينا عدة أخطاء غامضة غير معروفة، ويجب معاملة رقم السطر المذكور بأنه قد لا يكون دقيقًا في الغالب كما فعلنا مع بايثون، وسنحتاج بعد إصلاح الخطأ إلى إعادة تحميل الصفحة التي هو فيها. توجد في المتصفحات أدوات تنقيح متقدمة وموجهة للمطورين المحترفين، لكنها مخبأة داخل المتصفحات ولا تناسب احتياجاتنا الحالية بعد. خاتمة بغض النظر عن اللغة التي ستستخدمها في متابعة الشرح في هذه السلسلة، فنرجو أن تخرج من هذا المقال وأنت تعلم أنك تستطيع بدء بايثون بكتابة python في سطر الأوامر، وألا تخشى رسائل الخطأ، بل اقرأها بعناية، فهي تعطينا عادة المفاتيح التي نحتاجها لإصلاح الخطأ الواقع في البرنامج، غير أنها لا زالت مجرد مفاتيح، فإذا شككت في دقتها فانظر إلى الأسطر السابقة للسطر الذي تخبرك أن الخطأ فيه. ترجمة -بتصرف- للفصل الثالث من كتاب Learning To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: التسلسلات البسيطة في البرمجة المقال السابق: ما هي البرمجة؟ تعلم البرمجة ما هي البرمجة ولماذا تصبح مبرمجًا1 نقطة
-
نقصد بمعالجة الأخطاء عملية التقاط الأخطاء التي تولدها برامجنا وإخفائها عن المستخدم، فرسائل الأخطاء لا تخيف المبرمجين بل يمكن توقعها أحيانًا، إلا أن المستخدم لا يتوقع رؤيتها، وهي تربكه وتسبب له حيرةً، فإن كان سيرى رسالة خطأ للضرورة، فلتكن رسالةً سهلة الفهم، وحتى في هذه الحالة سيرغب المستخدم في أن يحل المبرمج المشكلة، وهنا يأتي دور التعامل مع الأخطاء ومعالجتها، حيث توفر كل لغة تقريبًا آليةً لالتقاط الأخطاء عند حدوثها لمعرفة الأجزاء التي تعطلت، واتخاذ الإجراء المناسب لإصلاح المشكلة، وقد تطورت عدة طرق لمعالجة هذه الأخطاء، والتي سننظر فيها هنا متبعين تطورها التاريخي مع تطور التقنية لنعرف الأسباب التي أدت إلى ظهور منظور جديد رغم وجودها سابقًا، ونرجو أن تكون قادرًا في نهاية المقال على كتابة برامج لا تسمح بظهور رسائل خطأ للمستخدم. تجدر الإشارة إلى أن لغة VBScript هي أكثر لغة غريبة من اللغات الثلاثة التي ندرسها في معالجة الأخطاء، لأنها بُنيت على لغة BASIC، التي إحدى أوائل لغات البرمجة التي خرجت في عام 1963، وسنرى كيف ألقى تراثها بظلاله على VBScript فيما يتعلق بمعالجة الأخطاء، لكن هذا لا يؤثر على سياق شرحنا، بل سيعطينا الفرصة لشرح سبب سلوك VBScript بتعقب تاريخ معالجة الأخطاء، بدءًا من لغة BASIC، مرورًا بلغة Visual Basic حتى VBSCript، ثم ننظر بعدها إلى منظور أحدث، ونرى أمثلةً له في بايثون وجافاسكربت. لقد كُتبَت البرامج في لغة BASIC مع أرقام للأسطر لتمييزها، حيث يُنقل التحكم بالقفز إلى سطر بعينه باستخدام تعليمة GOTO التي رأينا مثالًا لها في مقال مقدمة في البرمجة الشرطية، وقد كانت هذه صورة التحكم الوحيدة المتاحة وقتها، حيث كان الأسلوب الشائع لمعالجة الأخطاء حينئذ هو التصريح عن متغير errorcode الذي يخزن قيمةً عدديةً، وكلما حدث خطأ في البرنامج، سيُضبط المتغير errorcode ليعكس المشكلة. فإما أن يخبرنا أنه لم يستطع فتح الملف، أو أن النوع غير متطابق، أو حدث طفح للعوامل operator overflow، أو غير ذلك، وقد أدى هذا إلى شيفرة تشبه المثال التالي من برنامج وهمي: 1010 LET DATA = INPUT FILE 1020 CALL DATA_PROCESSING_FUNCTION 1030 IF NOT ERRORCODE = 0 GOTO 5000 1040 CALL ANOTHER_FUNCTION 1050 IF NOT ERRORCODE = 0 GOTO 5000 1060 REM CONTINUE PROCESSING LIKE THIS ... 5000 IF ERRORCODE = 1 GOTO 5100 5010 IF ERRORCODE = 2 GOTO 5200 5020 REM MORE IF STATEMENTS ... 5100 REM HANDLE ERROR CODE 1 HERE ... 5200 REM HANDLE ERROR CODE 2 HERE يفحص نصف البرنامج الرئيسي وجود خطأ، لكن ظهرت مع الوقت آلية أفضل، حيث تولى مفسر اللغة عملية التقاط الأخطاء ومعالجتها؛ ولو جزئيًا، كما يلي: 1010 LET DATA = INPUTFILE 1020 ON ERROR GOTO 5000 1030 CALL DATA_PROCESSING_FUNCTION 1040 CALL ANOTHER_FUNCTION ... 5000 IF ERRORCODE = 1 GOTO 5100 5010 IF ERRORCODE = 2 GOTO 5200 سمح هذا بالإشارة إلى المكان الذي توجد فيه شيفرة الخطأ بواسطة سطر واحد، ورغم أننا لا زلنا بحاجة إلى الدوال التي اكتشفت الخطأ لضبط قيمة ERRORCODE، إلا أنها جعلت كتابة الشيفرة وقراءتها أسهل بكثير، لكن كيف يتأثر المبرمجون بهذا الأمر؟ توفر Viusal Basic إلى الآن هذا النوع من معالجة الأخطاء -على الرغم من استخدامنا حاليًا طريقةً أفضل من أرقام الأسطر-، وبما أن VBScript تنحدر من Visual Basic، فإنها توفر نسخةً مختصرةً للغاية من هذه الطريقة، وهي تخيّرنا بين معالجة الأخطاء محليًا أو تجاهلها تمامًا، ونستخدم الشيفرة التالية لتجاهل الأخطاء: On Error Goto 0 ' 0 implies go nowhere SomeFunction() SomeOtherFunction() .... أما لمعالجتها محليًا فنستخدم ما يلي: On Error Resume Next SomeFunction() If Err.Number = 42 Then ' handle the error here SomeOtherFunction() ... يبدو هذا المنطق معكوسًا، لكنه يوضح العملية تاريخيًا كما أوضحنا أعلاه، فالسلوك الافتراضي للمفسر هو توليد رسالة إلى المستخدم، وإيقاف تنفيذ البرنامج إذا اكتشف خطأً ما، وهذا ما يحدث مع معالجة خطأ GoTo 0، فما هي إلا طريقة لإيقاف التحكم المحلي والسماح للمفسر بالعمل كالمعتاد. تسمح لنا تعليمة Resume Next بالتظاهر وكأن الخطأ لم يحدث، أو أن التحقق من كائن الخطأ -الذي يسمى Err-، وسمة العدد -مثل تقنية errorcode الأولى-، كما أن للكائن Err أجزاء معلومات أخرى قد تفيدنا في التعامل مع الموقف بطريقة أفضل من مجرد إيقاف البرنامج، بحيث نستطيع معرفة مصدر الخطأ مثلًا، سواءً كان كائنًا أم دالةً أم غير ذلك، كما نستطيع الحصول على وصف نصي نستخدمه في تعبئة رسالة تخبر المستخدم بما يحدث، أو كتابة ملاحظة في ملف السجل. كما يمكن تغيير نوع الخطأ باستخدام التابع Raise للكائن Err، إلى جانب استخدامنا له لتوليد أخطائنا من داخل دوالنا، لننظر في مثال حالة القسمة على الصفر؛ وهي حالة شائعة، لنرى معالجة الأخطاء في VBScript: <script type="text/vbscript"> Dim x,y,Result x = Cint(InputBox("Enter the number to be divided")) y = CINt(InputBox("Enter the number to divide by")) On Error Resume Next Result = x/y If Err.Number = 11 Then ' Divide by zero Result = Null End If On Error GoTo 0 ' turn error handling off again If VarType(Result) = vbNull Then MsgBox "ERROR: Could not perform operation" Else MsgBox CStr(x) & " divided by " & CStr(y) & " is " & CStr(Result) End If </script> هذا الأسلوب غير مثالي، ورغم أن تقدير التراث البرمجي هنا جميل ولطيف، إلا أن لغات البرمجة الحديثة -بما فيها بايثون وجافاسكربت- لديها طرق أفضل لمعالجة الأخطاء، كما سنشرح في الجزئية الموالية من المقال، لكن قبل ذلك، ننصحك بالاطلاع على الفيديو الآتي لفهم الأخطاء البرمجية والتعرف على كيفية التعامل معها مهما اختلف نوعها ولغتها: معالجة الأخطاء في بايثون سنعرض فيما يلي آليات التعامل مع الأخطاء والاستثناءات التي تحصل أثناء تنفيذ شيفرة البرنامج وكيفية معالجتها في بايثون. التعامل مع الاستثناءات تتعامل لغات البرمجة الحديثة مع الاستثناءات exceptions وتعالجها بجعل الدوال ترفع الاستثناء raise أو تلقيه throw، ثم يفرض النظام قفزةً إلى خارج كتلة التعليمات البرمجية الحالية إلى أقرب كتلة معالجة استثناءات، ويوفر النظام معالجًا افتراضيًا يلتقط جميع الاستثناءات التي لم تعالَج في مكان آخر، كما يطبع رسالة خطأ ثم يخرج. انظر إلى مقال بداية رحلة تعلم البرمجة لمراجعة كيفية قراءة رسائل الخطأ في بايثون وتفسيرها، حيث تتمثل إحدى مزايا هذا النمط من معالجة الأخطاء في سهولة رؤية الوظيفة الأساسية للبرنامج، لأنها غير مختلطة بشيفرة معالجة الأخطاء، إذ نستطيع قراءة الكتلة الرئيسية دون الحاجة إلى النظر إلى شيفرة الخطأ مطلقًا. لننظر في كيفية عمل هذا النمط عمليًا: استثناءات Try/Except تُكتب كتلة معالجة الاستثناءات على شكل كتلة if ...then...else: try: # منطق البرنامج هنا except ExceptionType: # معالجة الاستثناءات للاستثناء المسمى هنا except AnotherType: # معالجة الاستثناءات لاستثناءات أخرى هنا else: # هنا نقوم بالترتيب إذا لم تُرفع استثناءات تحاول بايثون أن تنفذ التعليمات بين try وأول تعليمة except، فإذا واجهت خطأً ما، فستوقف تنفيذ شيفرة block وتقفز إلى تعليمات except حتى تجد واحدةً تطابق نوع الخطأ أو الاستثناء، فإذا وجدت مطابقةً، فستنفذ الشيفرة التي في الكتلة التي بعد هذا الاستثناء مباشرةً؛ أما إذا لم توجد تعليمة except مطابِقة، فسيُنشر الخطأ إلى المستوى التالي للبرنامج، إلى أن توجد مطابقة، أو أن يكتشف مفسر المستوى الأعلى في بايثون هذا الخطأ ويعرض رسالة خطأ ويوقف تنفيذ البرنامج، وهو ما رأيناه في برامجنا إلى الآن. أما إذا لم يوجد خطأ في كتلة try، فستنفَّذ كتلة else الأخيرة، رغم أن هذه الخاصية لا تُستخدم إلا نادرًا. لاحظ أن تعليمة except التي ليس فيها نوع خطأ محدد، إذ ستلتقط كل أنواع الأخطاء التي لم تعالَج بعد، وهذا سيئ إلا في حالة المستوى الأعلى في برنامجك حين تريد تجنب عرض رسائل بايثون التقنية إلى المستخدمين، حيث يمكن استخدام تعليمة استثناء عامة لالتقاط أي أخطاء غير ملتقطة، وعرض رسالة "إغلاق" مناسبة للمستخدم، ويجب الانتباه إلى تسجيل بيانات الخطأ في ملف السجل للتحليل في المستقبل. توفر لغة بايثون وحدة traceback التي تمكنك من استخراج أجزاء من المعلومات من مصدر الخطأ، وقد يكون هذا مفيدًا في إنشاء ملفات السجلات وما شابهها، لكننا لن نشرح هذه الوحدة، فإذا احتجت إليها فسيوفر توثيق الوحدات القياسي قائمةً كاملةً من المزايا والخصائص المتوفرة لها. لننظر الآن في مثال حقيقي لتوضيح الشرح: value = input("Type a divisor: ") try: value = int(value) print( "42 / %d = %d" % (value, 42/value) ) except ValueError: print( "I can't convert the value to an integer" ) except ZeroDivisionError: print( "Your value should not be zero" ) except: print( "Something unexpected happened" ) else: print( "Program completed successfully" ) إذا شغلنا هذا البرنامج وأدخلنا قيمةً ليست برقم مثل إدخال سلسلة نصية في المحث، فسنحصل على رسالة ValueError؛ أما إذا أدخلنا 0 فنحصل على رسالة ZeroDivisionError، وإذا ضغطنا Ctrl+C فسنرفع استثناء KeyboardInterrupt ونرى رسالةً تقول "Something unexpected happened"؛ أما إذا كتبنا عددًا صالحًا فسنحصل على النتيجة مع رسالة "Program Completed successfully". استثناءات Try/Finally ثمة نوع آخر من كتل الاستثناءات التي تسمح لنا بالترتيب بعد حدوث خطأ ما، وتسمى try...finally، كما تُستخدم لإغلاق الملفات واتصالات الشبكات أو قواعد البيانات، وتنفَّذ كتلة finally في النهاية بغض النظر عما يحدث في قسم try: try: # المنطق المعتاد للبرنامج finally: # try هنا نرتب بغض النظر عن نجاح كتلة # أو فشلها تصبح الكتلة قويةً للغاية إذا جمعناها مع try/except: print( "Program starting" ) try: data = open("data.dat") print( "data file opened" ) value = int(data.readline().split()[2]) print( "The calculated value is %s" % (value/(42-value)) ) except ZeroDivisionError: print( "Value read was 42" ) finally: data.close() print( "data file closed" ) print( "Program completed" ) لاحظ أن ملف البيانات يجب أن يحتوي على سطر مع رقم في الحقل الثالث، كما يلي: Foo bar 42 هنا يُغلق ملف البيانات دومًا بغض النظر عن رفع الاستثناء في كتلة try/except أو لا. لاحظ أن هذا السلوك مختلف عن شرط else لكتلة try/except، لأنه يُستدعى فقط عند عدم رفع استثناءات، كما يعني وضع الشيفرة خارج كتلة try/except أن الملف لم يغلَق إذا كان الاستثناء شيئًا غير ZeroDivisionError، ولا نضمن أن الملف مغلق إلا بإضافة كتلة finally. كذلك وضعنا تعليمة open() داخل كتلة try/except، فإذا أردنا التقاط خطأ فتح ملف، فسنحتاج إلى إضافة كتلة except أخرى لـ IOError. جرب هذا بنفسك ثم افتح ملفًا غير موجود لترى ذلك عمليًا. توليد الأخطاء إذا أردنا توليد استثناءات ليلتقطها غيرنا في وحدة ما، فنستخدم الكلمة المفتاحية raise في بايثون: numerator = 42 denominator = int( input("What value will I divide 42 by?") ) if denominator == 0: raise ZeroDivisionError يرفع هذا استثناء ZeroDivisionError الذي يمكن التقاطه بواسطة كتلة try/except، أما بالنسبة لبقية البرنامج فسيبدو كما لو أن بايثون ولّدت هذا الخطأ داخليًا. يمكن استخدام كلمة raise في توليد خطأ لمستوى أعلى في البرنامج من داخل كتلة الاستثناء، فقد نرغب في أخذ إجراء محلي، مثل تسجيل خطأ في ملف، ثم نسمح للمستوى الأعلى من البرنامج أن يقرر الإجراء النهائي، كما يلي: def div127by(datum): try: return 127/(42-datum) except ZeroDivisionError: logfile = open("errorlog.txt","a") logfile.write("datum was 42\n") logfile.close() raise try: div127by(42) except ZeroDivisionError: print( "You can't divide by zero, try another value" ) لاحظ كيف تلتقط الدالة div127by() الخطأ، وتسجل رسالةً في ملف الخطأ، ثم تمرر الاستثناء مرةً أخرى إلى كتلة try/except الخارجية لتتعامل معه باستدعاء raise دون كائن خطأ محدد. لنجمع هذين الجزأين معًا في برنامج واحد يوضح معالجة الأخطاء عمليًا: def div127by(datum): try: return 127/(42-datum) except ZeroDivisionError: logfile = open("errorlog.txt","a") logfile.write("datum was 42\n") logfile.close() raise try: divisor = int( input("What value will I divide by?") ) if divisor == 0: raise ZeroDivisionError print( "The result is: ", div127by(divisor) ) except ZeroDivisionError: print( "You can't divide by zero, try another value" ) فإذا أدخل المستخدم 42 أو 0 فسينتِج ZeroDivisionError، مع أن 0 قيمة آمنة في هذه الحالة؛ أما غير ذلك فنطبع نتيجة القسمة ونسجل قيمة الدخل في الملف errorlog.txt. الاستثناءات المعرفة من قبل المستخدم توفر بايثون نطاقًا واسعًا من أنواع الأخطاء القياسية، ويجب أن نعيد استخدام هذه الأخطاء ما أمكن، لكن قد لا نجد خطأً يناسب احتياجنا، عندئذ نستطيع تعريف أنواع الاستثناءات الخاصة بنا للتحكم في برامجنا تحكمًا دقيقًا، وقد مررنا على تعريف الأصناف في مقال البيانات وأنواعها مرورًا سريعًا، وسنعود إليها مرةً أخرى في جزئية لاحقة من هذه السلسلة. لا يحتوي صنف الاستثناء عادةً على محتوىً خاص به، وإنما نعرف صنفًا فرعيًا من Exception، ونستخدمه مثل نوع من الملصقات الذكية التي يمكن التقاطها بواسطة تعليمات except. لننظر في هذا المثال القصير: >>> class BrokenError(Exception): pass ... >>> try: ... raise BrokenError ... except BrokenError: ... print( "We found a Broken Error" ) ... لاحظ أننا نستخدم اصطلاح تسمية نضيف فيه Error إلى نهاية اسم الصنف، وأننا نكتسب سلوك صنف Exception العام بإدراجه في أقواس بعد الاسم، كما سنتعلم الاكتساب أو الوراثة inheritance في البرمجة كائنية التوجه. يجب ملاحظة نقطة أخيرة في رفع الأخطاء، وهي أننا كنا ننهي برامجنا باستيراد sys واستدعاء الدالة exit()، لكن يمكن استخدام أسلوب آخر يحقق نفس النتيجة، عن طريق رفع خطأ SystemExit() كما يلي: >>> raise SystemExit وميزة هذا الأسلوب أننا لا نحتاج إلى import sys في البداية. جافاسكربت تعالج جافاسكربت الأخطاء بطريقة تشبه طريقة بايثون، باستخدام الكلمات المفتاحية try وcatch وthrow مقابل كلمات بايثون try وexcept وraise، وسننظر الآن في بعض الأمثلة، كما سنرى استخدام المبادئ نفسها التي كانت في بايثون، وقد أدخلت الإصدارات الأخيرة من جافاسكربت بنية finally، كما يمكن استخدام شرط finally في جافاسكربت مع كتلة try/catch في بنية واحدة. انظر توثيق جافاسكربت لمزيد من التفاصيل. التقاط الأخطاء تُلتقَط الأخطاء باستخدام كتلة try مع مجموعة من تعليمات catch تكاد تكون مطابقةً لما رأيناه في بايثون: <script type="text/javascript"> try{ var x = NonExistentFunction(); document.write(x); } catch(err){ document.write("We got an error in the code"); } </script> يكمن الاختلاف الأساسي في أننا نستخدم تعليمة catch واحدةً فقط لكل بنية try، وعلينا أن نفحص الخطأ الممرَّر داخل كتلة catch لنرى نوعه، وهذا فوضوي موازنةً بأسلوب except المتعدد في بايثون والمبني على نوع الاستثناء، وسنرى مثالًا بسيطًا لاختبار قيم الأخطاء في الشيفرة التالية. رفع الأخطاء يمكن رفع الأخطاء باستخدام الكلمة throw كما استخدمنا كلمة raise في بايثون، كما نستطيع إنشاء أنواع الخطأ الخاصة بنا في جافاسكربت كما فعلنا في بايثون، لكن الأسهل هو استخدام سلسلة نصية: <script type="text/javascript"> try{ throw("New Error"); } catch(e){ if (e == "New Error") document.write("We caught a new error"); else document.write("An unexpected error found"); } </script> هذا كل ما سنشرحه حول معالجة الأخطاء، وسنرى أمثلةً عمليةً لها في المقالات التالية، كما سنرى بعض المفاهيم الأساسية التي تحدثنا عنها من قبل، مثل التسلسلات والحلقات التكرارية والفروع، مما يعني أن لديك جميع الأدوات اللازمة لإنشاء برامج قوية. يفضل الآن أن تأخذ وقتًا تحاول فيه إنشاء بعض البرامج بنفسك -ربما بضعة برامج فقط-، لتثبت تلك المفاهيم في رأسك قبل الانتقال إلى مجموعة المقالات التالية، وتستطيع البدء بالبرامج التالية: لعبة بسيطة مثل OXO. قاعدة بيانات بسيطة، ربما مبنية على دليل جهات الاتصال الخاص بنا، ولكن لتخزين مجموعة أقراصك أو مقاطع الفيديو. أداة تسجيل يوميات تتيح لك إمكانية تخزين الأحداث أو التواريخ المهمة، وربما تخرج لك إشعارًا تذكيريًا. ستحتاج إلى استخدام جميع الخصائص التي شرحناها من قبل، وربما بعض وحدات اللغات كذلك، وهنا تذكر أن تعود إلى التوثيق كل فترة، إذ ستجد أدوات أخرى تعينك على إنشاء مثل هذه البرامج، ولا تنسى أيضًا قوة محث بايثون. جرب برامجك هناك إلى أن تفهم كيفية عملها، ثم انقل ذلك إلى البرنامج الخاص بك. خاتمة نرجو في نهاية المقال أن تكون تعلمت ما يلي: التحقق من شيفرات أخطاء VBScript باستخدام تعليمة if. التقاط الاستثناءات بشرط except في بايثون أو catch في جافاسكربت. توليد الاستثناءات باستخدام كلمة raise المفتاحية في بايثون أو throw في جافاسكربت. أنه يمكن أن تكون أنواع الأخطاء أصنافًا في بايثون أو سلسلةً بسيطةً في جافاسكربت. ترجمة -بتصرف- للفصل الرابع عشر: Handling Errors من كتاب Learning To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: فضاءات الأسماء Namespaces في البرمجة المقال السابق: كيفية التعامل مع النصوص في البرمجة التعامل مع الملفات في البرمجة تعلم البرمجة الزلات البرمجية والأخطاء في جافاسكريبت1 نقطة
-
في أي حالات يتطلب عمل فهرسة لأكثر من عمود؟ أي تطبيق Multi-column Indexes1 نقطة
-
أنفذ بعض المهام في Matplotlib وأحتاج إلى طريقة تمكنني من عرض الصورة باستخدام الدالة imshow بالصيغة الرمادية؟1 نقطة
-
على أي أساس أقوم بجعل حقلٍ ما index بدلاً من حقلٍ أخر او بمعنى اخر على اي اساس اقوم باختيار الindexes1 نقطة
-
أريد عمل نسخ احتياطي لمكان التخزين في Docker1 نقطة
-
أريد عمل نسخة احتياطية لصورة الحاوية بعد التعديلات، كيف؟1 نقطة
-
ليست خدمة إنشاء ملفات لمشتريين عند الطلب بل بيع ملفات WORD جاهزة للمشتريين عند الرغبة في الحصول عليه وذلك على موقع خمسات1 نقطة
-
كيف أعمل نسخ احتياطي في Docker لصورة التطبيق1 نقطة
-
1 نقطة
-
أحتاج إلى عرض ثلاث صور، إحداها بقناة حمراء كصورة حمراء ، وأخرى باللون الأزرق ، والأخيرة باللون الأخضر؟ كيف نقوم بذلك؟1 نقطة
-
هل هناك دوال جاهزة في OpenCV لإضافة ضجيج مثل الضجيج الغاوصي أو ضجيج الملح والفلفل salt and pepper إلى الصورة كما في الماتلاب؟1 نقطة
-
شكرا اخي الفاضل تمت بنجاح لكن تظهر رسالة خطأ ربما الامر بسيط1 نقطة
-
لاحظ عدم تماثل مخروجي المصفوفتين . فإما هذا : أو العكس : أن يكون مخروج مصفوفة المخزن تحوي اسم المجلد . فنتائج المصفوفة الأولى ممثلة للصور المخزنة stored_imgs لا تماثل نتائج المصفوفة الثانية db_imgs. و لحل المشكلة سنقوم بإضافة السابقة uploads/profile/ إلى كل عناصر مصفوفة عناوين الصور في قواعد البيانات . يمكن ذلك عن طريق الوظيفة preg_filter كالتالي : $prefixedArray = preg_filter('/^/', 'prefix', $targetArray); كما أننا سنحتاج فلترة نتائج كل من المصفوفتين للتخلص من وجود العناصر الفارغة لتجنب التحذيرات و الأخطاء التي تظهر , يمكن ذلك عن طريق الوظيفة array_filter كالتالي : $filteredArray = array_filter($nonFilteredArray); لتصبح الشيفرة كاملة : // تحديد كامل مسارات الصور من قواعد البيانات من الجدول المستهدف و تخزينها في مصفوفة . $res = mysql_query('SELECT img_profile_path from users'); $db_imgs = []; while($row = mysql_fetch_array($res)) { $db_imgs[] = $row['img_profile_path']; } // إضافة سابقة $db_imgs = preg_filter('/^/', 'uploads/profile/', $db_imgs); // تحديد كامل مسارات الصور داخل المجلد المستهدف و تخزينها في مصفوفة . $stored_imgs = glob($targetDirectory . "*.jpg"); // تحديد العناصر الغير متوفرة في كلتا المصفوفتين . $targetImages = array_merge(array_diff($db_imgs, $stored_imgs), array_diff($stored_imgs, $db_imgs)); // فلترة العناصر الفارغة $targetImages = array_filter($targetImages); // حذفها هاته العناصر foreach($targetImages as $image) { unlink($image); } يفترض أن يقوم هذا بحل المشكل . يمكنك دوما تتبع مخروج المصفوفتين عن طريق طباعة كل منهما كل مرة . توثيق الوظيفتين : array_filter preg_filter1 نقطة
-
لا يتم حذف اي من الصور من مجلد التخزين والنتيجة كالتالي1 نقطة
-
count تقوم بجمع وحساب القيم التي تقوم بتجميعها سويا اما في نفس الجدول أو من جداول مختلفة، لأجل ذلك عادة ما تستخدم مع groupby وذلك لتجميع مانريد عده سويا في مكان واحد، المثال التالي يوضح ذلك. لنفرض أن عندنا جدولين كالتالي: Table 1: id, category id, colour Table 2: category id, category name ونريد أن نقوم بجمعهم سويا ثم عد قيم كل فئة category، الكود التالي يوضح كيفية القيام بذلك: SELECT COUNT(*) TotalCount, b.category_id, b.category_name FROM table1 a INNER JOIN table2 b ON a.category_id = b.category_id GROUP BY b.category_id, b.category_name لاحظ أنه قام بتجميع الجدولين سويا باستخدام INNER JOIN وبعد ذلك تقسيمهم بناء علي category id ثم عدهم.1 نقطة
-
هلا قمت بتنفيذ الشيفرة التالية و إرفاق النتيجة ؟ // تحديد كامل مسارات الصور من قواعد البيانات من الجدول المستهدف و تخزينها في مصفوفة . $res = mysql_query('SELECT img_profile_path from users'); $db_imgs = []; while($row = mysql_fetch_array($res)) { $db_imgs[] = $row['img_profile_path']; } // تحديد كامل مسارات الصور داخل المجلد المستهدف و تخزينها في مصفوفة . $stored_imgs = glob($targetDirectory . "*.jpg"); // تحديد العناصر الغير متوفرة في كلتا المصفوفتين . $targetImages = array_diff($stored_imgs, $db_imgs); echo '<pre>'; print_r($targetImages); echo '</pre>'; echo '<br><br><br><pre>'; print_r($db_imgs); echo '</pre>'; die(); // حذفها هاته العناصر foreach($targetImages as $image) { unlink($image); } سيمكن بهذا تتبع مخروج كل من المصفوفتين قبل تطبيق أية عمليات عليها .1 نقطة
-
1 نقطة
-
أولاً نوقف تشغيل الحاوية: sudo systemctl stop docker ثم نتوجه لملف الإعدادات: /usr/lib/systemd/system/docker.service ثم نعدل السطر التالي: لتمرير argument أو وسيط وقت تشغيل الحاوية storage-opt وتحديد الحجم dm.basesize ExecStart=/usr/bin/dockerd نعدل السطر السابق كما يلي ExecStart=/usr/bin/dockerd --storage-opt dm.basesize=20G ثم نعيد تشغيل Docker sudo systemctl start docker نفس الشيئ يمكن تعديل ملف daemon.json في المسار etc/docker/daemon.json/ بإضافة: "storage-opt": [ "dm.basesize=20G" ] ولجعل الحاوية تأخذ مساحة حسب الحاجة يمكن تحديد نوع سواقة التخزين إلى overlay /etc/docker/daemon.json {"storage-driver": "overlay"}1 نقطة
-
أولاً لكي يعمل Bash على ويندوز يمكنك تنصيب أداة git وهي تضيف صدفة Bash خلال التنصيب. ثم عليك إعداد NPM لتنفيذ السكربت في صدفة حسب مسار يمكن تمريره لها، حيث علينا تمرير مسار الصدفة إلى script-shell x64 npm config set script-shell "C:\\Program Files\\git\\bin\\bash.exe" x32 npm config set script-shell "C:\\Program Files (x86)\\git\\bin\\bash.exe" ^^^^^^ وبطريقة أخرى يمكن استخدام الملف npmrc. ونضيف له السطر: script-shell = bash ويكون السكربت افتراضياً في pacjages.json "scripts": { "test": "node ./node_modules/my_package/index.js" } حيث إن تم استعمال cmd في ويندوز سيحدث خطأ بسبب /. لذلك نضطر لتغيير الصدفة.. أو لميزات أخرى1 نقطة
-
عند ضم جدولين أو أكثر تكون القيم التي تقوم بضمها في بعض الأحيان غير متتطابقة تمامًا بين الجداول. وهناك العديد من الطرق لحل هذا الأمر، ومن ضمن هذه الطرق يمكن إستخدام جملة CASE عند ربط الجداول معًا، وذلك عند تحديد قيمة الحقل مكان ON. بفرض أن لدينا جدول orders يحتوي على معلومات عن طلبات العملاء وهو على الشكل التالي: لاحظي كيف أن لنفس العميل أكثر من قيمة cust_num متشابهة. وأيضًا لدينا الجدول cust_table والذي يحتوي على معلومات حول العملاء أنفسهم: الآن عندما نقوم بعمل ربط بين الجدولين عن طريقة cust_num نجد أن النتيجة كالتالي: لاحظي وجود قيم NULL في حقل residence وذلك لعدم تشابهة قيمة الحقل cust_num بين الجدولين. لحل هذه المشكلة، يمكن الإستعانة بجملة CASE عند الربط بين الجدولين كالتالي: SELECT a.*, b.residence FROM orders AS a LEFT JOIN cust_table AS b ON CASE -- إزالة الرمز -EC من نهاية رقم العميل cust_num إن وجد WHEN a.cust_num LIKE '%-EC' THEN SUBSTRING(a.cust_num, 1, LEN(a.cust_num) - 3) -- في حالة لم يتم العثور على الرمز -EC في رقم العميل فلا حاجة لإستخدام الدالة SUBSTRING ELSE a.cust_num END = b.cust_num ORDER BY order_year عند تنفيذ الإستعلام السابق سوف تكون النتيجة كالتالي: بهذا الشكل لن يحتوي الجدول على قيم NULL وسيتم تعويضها بالبيانات بشكل سليم. لمعرفة المزيد حول CASE في SQL يمكن الإطلاع على هذه المقالة: أو من خلال موسوعة حسوب حول لغة SQL من هنا1 نقطة
-
يمكنك أن تستخدم حزمة next-sitemap والتي تسمح لك بتوليد ملف sitemap.xml وكذلك ملف robots.txt، كما أنها تقوم بإنشاء ملف sitemap.xml بناءًا على الملفات من نوع Static وكذلك pre-rendered وصفحات SSR بشكل تلقائي. لتثبيت الحزمة نفذ الأمر التالي: # إن كنت تستخدم yarn كمدير للحزم yarn add next-sitemap -D # أو من خلال NPM npm i next-sitemap لتعمل هذه الحزمة تحتاج إلى ملف يحتوي على الإعدادات الرئيسية وهو ملف next-sitemap.js، لذلك قم بإنشاء هذا الملف في مجلد المشروع الرئيسي الخاص بك وأكتب محتواه كالتالي: module.exports = { siteUrl: process.env.SITE_URL || 'https://example.com', generateRobotsTxt: true, // سطر إختيار لتوليد ملف robots.txt تلقائيًا // ... } لاحظ أننا قمنا بالحصول على عنوان الموقع من خلال ملف .env مباشرة، حيث تدعم الحزمة على الحصول على المتغيرات من ملف .env بشكل تلقائي. الآن لتشغيل الحزمة ولتوليد ملف sitemap.xml (و ملف robots.txt) قم بإضافة أمر next-sitemap إلى ملف package.json، على النحو التالي: { "build": "next build", "postbuild": "next-sitemap --config next-sitemap.js" } إن كان لديك عدد كبير من المسارات والملفات في المشروع يمكنك أن تقوم بتقسيم ملف sitemap.xml لعمل ملفات sitemap فرعية، وذلك من خلال تعديل ملف next-sitemap.js وإضافة الخاصية sitemapSize، كالتالي: module.exports = { siteUrl: 'https://example.com', generateRobotsTxt: true, sitemapSize: 1000, } من خلال عمل التعديل السابق على ملف الإعدادات، ستقوم الحزمة بتخزين المسارات والملفات وعندما يزيد هذه المسارات عن 1000 سوف يتم تقسيهم إلى ملفات فرعية مثل sitemap-1.xml و sitemap-2.xml بالإضافة إلى عمل ملف sitemap.xml رئيسي كفهرس للملفات الأخرى (وهذا الأمر تدعمه كل محركات البحث المعروفة وتنصح به أيضًا). يمكنك الإطلاع على مزيد من الخيارات والإعدادات التي تقدمها هذه الحزمة من خلال صفحتها على GitHub.1 نقطة
-
أشرنا في المقال السابق إلى عدة أنواع أساسية من البيانات البرمجية، وفي هذا المقال سنتابع مع ذكر نوع هام جدًا منها، وهو البيانات التجميعية collections. التجميعات Collections لقد شكلت علوم الحاسوب نظامًا كاملًا يدرس التجميعات وسلوكياتها المختلفة، والتي تسمى بالحاويات أحيانًا أو التسلسلات، وسننظر أولًا في التجميعات المدعومة في بايثون وجافاسكربت وVBScript، ثم نختم بملخص موجز لبعض أنواع التجميعات الأخرى التي قد نراها في لغات أخرى. القوائم Lists لا شك في أن القوائم غنية عن تعريفها، إذ نستخدمها في حياتنا كل يوم، فهي مجرد سلسلة من العناصر، حيث نستطيع إضافة عناصر إلى تلك السلسلة أو حذفها، وعادةً ما نضيف العناصر في نهاية القائمة إذا كانت مكتوبةً على الورق، فلا نستطيع إدخال عنصر في المنتصف مثلًا، على عكس القوائم الإلكترونية في برنامج معالج النصوص مثلًا، إذ نستطيع وضع العنصر الجديد في أي مكان، كما نستطيع البحث في القائمة لنتحقق من وجود شيء بعينه فيها، لكن يجب التنقل في القائمة من أعلاها لأسفلها عنصرًا عنصرًا متحققين من كل عنصر لنرى إذا كان ما نريده موجودًا أم لا، وتُعَد القوائم أحد أنواع التجميعات التي لا غنى عنها في أغلب لغات البرمجة الحديثة. لا تحتوي جافاسكربت ولا VBScript على قوائم مضمّنة فيها، لكن نستطيع محاكاة مزايا القوائم بواسطة المصفوفات في جافاسكربت، وبتجميعات بيانات أخرى في VBScript كما سنشرح لاحقًا؛ أما لغة بايثون فالقوائم مضمّنة تلقائيًا فيها، وتستطيع تنفيذ العمليات الأساسية التي تحدثنا عنها جميعًا، إضافةً إلى القدرة على فهرسة العناصر فيها، والفهرسة هي الإشارة إلى عنصر في القائمة برقم تسلسله، على فرض أن العنصر الأول يبدأ من الصفر، كما توفر بايثون عدة عمليات أخرى على التجميعات، وتنطبق كلها تقريبًا على القوائم، كما تنطبق مجموعة فرعية منها على أنواع أخرى من التجميعات بما في ذلك السلاسل النصية التي هي مجرد نوع خاص من القوائم، إذ هي قوائم من المحارف. تُستخدم الأقواس المربعة لإنشاء القوائم والوصول إليها في بايثون، ويمكن إنشاء قائمة فارغة باستخدام زوج من تلك الأقواس ليس بينهما شيء، أو إنشاء قائمة تحتوي على قيم تفصل بينها فاصلة إنجليزية ",": >>> aList = [] >>> another = [1,2,3] >>> print( another ) [1, 2, 3] نستطيع الوصول إلى العناصر المنفردة باستخدام رقم الفهرس، حيث يحمل العنصر الأول رقم 0 داخل الأقواس المربعة، فإذا أردنا الوصول إلى العنصر الثالث مثلًا -والذي سيحمل الترتيب 2 داخل الأقواس بما أننا نبدأ من الصفر-، فإننا نصل إليه كما يلي: >>> print( another[2] ) 3 كما نستطيع تغيير قيم العناصر في القائمة بطريقة مماثلة: >>> another[2] = 7 >>> print( another ) [1, 2, 7] لاحظ كيف تغير العنصر الثالث -الذي فهرسه 2- من 3 إلى 7. يمكن استخدام أرقام الفهرس السالبة للوصول إلى عناصر القائمة من نهايتها، فإذا أردنا العنصر الأخير من القائمة نستخدم -1: >>> print( another[-1] ) 7 وتضاف العناصر الجديدة ملحقةً إلى نهاية القائمة باستخدام العملية append(): >>> aList.append(42) >>> print( aList ) [42] كما يمكن الاحتفاظ بقائمة داخل قائمة أخرى، فإذا ألحقنا القائمة الثانية بالقائمة الأولى فستكون على النحو التالي: >>> aList.append(another) >>> print( aList ) [42, [1, 2, 7]] لاحظ كيف تكون النتيجة قائمةً من عنصرين، لكن العنصر الثاني عبارة عن قائمة بحد ذاته كما نرى من القوسين المحيطين به، ونستطيع الآن الوصول إلى العنصر 7 باستخدام فهرس مزدوج: >>> print( aList[1][2] ) 7 حيث يستخرج الفهرس 1 -الفهرس الأول- العنصر الثاني من القائمة الأولى -الذي هو نفسه القائمة الثانية-، ثم يستخرج الفهرس 2 -الفهرس الثاني- العنصر الثالث في القائمة الثانية، وهو العنصر 7. هذا التداخل وإن بدا معقدًا إلا أنه مفيد للغاية، حيث يسمح ببناء جداول من البيانات بفعالية، كما يلي: >>> row1 = [1,2,3] >>> row2 = ['a','b','c'] >>> table = [row1, row2] >>> print( table ) [ [1,2,3], ['a','b','c'] ] >>> element2 = table[0][1] >>> print( element2 ) 2 يمكن استخدام هذه الطريقة في إنشاء دفتر عناوين يكون كل مدخل فيه عبارةً عن قائمة من الاسم والعنوان، ويوضح المثال التالي دفتر عناوين فيه مدخلان: >>> addressBook = [ ... ['Samy', '9 Some St',' Anytown', '0123456789'], ... ['Warda', '11 Nother St', 'SomePlace', '0987654321'] ... ] >>> لاحظ كيف أنه رغم إدخالنا لأربعة أسطر من النص، إلا أن بايثون تعاملت معها على أنها سطر واحد، كما نستنتج من محثات ...، وهذا لأن بايثون ترى أن عدد الأقواس الافتتاحية لا يطابق عدد أقواس الإغلاق، ولهذا تستمر في قراءة المدخلات إلى أن يحدث ذلك التطابق. قد تكون هذه طريقةً فعالةً للغاية في بناء هياكل بيانات معقدة بسرعة مع جعل الهيكل العام -أي قائمة القوائم- واضحًا للقارئ. تدريب استخرج رقم هاتف سامي -العنصر 3 من الصف الأول-، وتذكر أن الفهارس تبدأ من الصفر وليس الواحد، ثم أضف بعض المدخلات من عندك باستخدام عملية append(). لاحظ أننا نفقد بياناتنا عند الخروج من بايثون، لكن سنرى كيفية الاحتفاظ بها عند شرح الملفات في هذا الكتاب. يُستخدم الأمر del لحذف العناصر من القائمة: >>> del aList[1] >>> print( aList ) [42] لاحظ أن del لا يحتاج إلى أقواس حول القيمة، على عكس دالة الطباعة، لأنه أمر وليس دالةً، قد يكون هذا الفرق طفيفًا، لكن إذا وضعت أقواسًا حول القيمة فلا بأس إذ ستظل صالحةً. إذا أردنا ضم قائمتين معًا لجعلهما قائمةً واحدةً، فسنتخدم عامل الضم + الذي رأيناه في ضم السلاسل النصية من قبل: >>> newList = aList + another >>> print( newList ) [42, 1, 2, 7] لاحظ اختلاف هذا المثال عن سابقه الذي ألحقنا فيها القائمتين معًا، فقد كان لدينا عنصران، وكان العنصر الثاني منهما عبارةً عن قائمة؛ أما هنا فلدينا أربعة عناصر لأن عناصر القائمة الثانية أضيفت عنصرًا عنصرًا إلى newList، فإذا أردنا الوصول إلى العنصر 1 هذه المرة فسنحصل على 1، وهو العنصر الثاني هنا، بدلًا من الحصول على قائمة فرعية. >>> print( newList[1] ) 1 يمكن تطبيق إشارة عملية الضرب هنا مثل عامل تكرار لملء القائمة بمضاعفات نفس القيمة: >>> zeroList = [0] * 5 >>> print( zeroList ) [0, 0, 0, 0, 0] كما يمكن إيجاد فهرس عنصر ما في قائمة باستخدام العملية index() كما يلي: >>> print( [1,3,5,7].index(5) ) 2 >>> print( [1,3,5,7].index(9) ) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: list.index(x): x not in list لاحظ أن محاولة العثور على فهرس لشيء غير موجود في القائمة ينتج خطأً، فإذا أردنا التحقق من وجود شيء في تجميعة ما فسنستخدم العامل in كما يلي: >>> print( 5 in [1,3,5,7] ) True >>> print( 9 in [1,3,5,7] ) False النتائج قيم بوليانية كما نرى، إما True أو False، وسنرى كيف نستخدم تلك النتائج في فصل لاحق. أخيرًا، يمكن معرفة طول القائمة باستخدام الدالة المضمَّنة len(): >>> print( len(aList) ) 1 >>> print( len(newList) ) 4 >>> print( len(zeroList) ) 5 لا تدعم جافاسكربت ولا VBScript نوع القائمة مباشرةً، وسنرى أن لديهما نوع بيانات يحاكي وظيفة القائمة هنا، وهو نوع المصفوفات arrays. الصف Tuple توفر بعض لغات البرمجة بنية بيانات اسمها صف tuple، وما هي إلا تجميعة عشوائية من القيم لكنها تعامَل مثل وحدة واحدة، وهي تشبه القوائم في نواحٍ كثيرة، لكن مع فرق أن وحدات tuple غير قابلة للتغيير، مما يعني أننا لا نستطيع التعديل عليها أو إلحاق شيء إليها بعد إنشائها أول مرة، تمثَّل وحدات tuple في بايثون بقائمة من القيم المفصول بينها بفواصل: >>> aTuple = 1,3,5 >>> print( aTuple[1] ) # استخدم الفهرسة مثل القوائم 3 >> aTuple[2] = 7 # tuple خطأ، لا يمكن تعديل Traceback (innermost last): File "<pyshell#20>", line 1, in ? aTuple[2] = 7 TypeError: object doesn't support item assignment من المعتاد إحاطة التسلسل بأقواس، وهذا يضمن عدم إخراج القيم من السياق، إضافةً إلى التذكير المرئي بأنها وحدة واحدة، أي وحدة صف، توضح البيانات التالية هذا الأمر: >>> t1 = 1,2,3 * 3 >>> t2 = (1,2,3) * 3 >>> print(t1) (1, 2, 9) >>> print( t2 ) (1, 2, 3, 1, 2, 3, 1, 2, 3) يطبَّق الضرب في الحالة الأولى على العنصر الأخير فقط في وحدة Tuple، أما في الحالة الثانية فتضاعَف المجموعة بالكامل، ولتجنب مثل هذا الغموض، سنستخدم الأقواس في كل مرة نصف فيها وحدات tuple. لعل أحد أهم الأمور التي يجب تذكرها هو أن الأقواس المربعة تستخدم لفهرسة وحدات tuple، بينما تُستخدم الأقواس العادية لتعريفها، ولا يمكن تغييرها بعد إنشائها؛ أما في سوى هذه الأمور فما ينطبق من العمليات على القوائم ينطبق أيضًا على الصفوف، ورغم أننا لا نستطيع تعديل وحدة الصف بعد إنشائها؛ إلا أننا نستطيع إضافة أعضاء جديدة إليها باستخدام عامل الإضافة، فهذا سينشئ صفًا جديدًا، كما يلي: >>> tup1 = (1,2,3) >>> tup2 = tup1 + (4,) # وليس عددًا صحيحًا tuple الفاصلة تجعل هذا وحدة >>> print( tup2 ) (1,2,3,4) إذا لم نستخدم الفاصلة اللاحقة بعد العدد 4 فستفسره بايثون على أنه العدد الصحيح 4 داخل أقواس وليس على أنه صف، لكن سنحصل على خطأ بأي حال بما أنه لا يمكن إضافة أعداد صحيحة إلى الصفوف، لذا سنضيف الفاصلة لنخبر بايثون بأن تعامل الأقواس على أنها صف، فبإضافة الفاصلة الزائدة نقنع بايثون بأن وحدة الصف التي فيها مدخل واحد هي صف فعلًا؛ أما بالنسبة للغتي جافاسكربت وVBScript فليس لديهما أي مفهوم للصف tuple. القاموس Dictionary أو Hash يحتوي هذا النوع من البيانات على قيمة ترتبط بمفتاح، كما يربط القاموس اللغوي المعنى بكلمة، وقد تكون تلك القيمة سلسلةً نصيةً أو لا، وتُجلب تلك القيمة بفهرسة القاموس بالمفتاح، ولا يلزم أن يكون المفتاح سلسلةً من الأحرف -رغم أنه غالبًا كذلك-، وهذا على خلاف القاموس اللغوي، فقد يكون أي نوع غير قابل للتغير، بما في ذلك الأعداد والصفوف، كما قد تحتوي القيم المرتبطة بالمفاتيح على أي نوع من البيانات. تُستخدم القواميس داخليًا بواسطة تقنية برمجة متقدمة تسمى بجداول Hash، لهذا يشار أحيانًا إلى القاموس باسم Hash، ونظرًا لأننا نتوصَّل إلى قيم القاموس عبر المفتاح، فلا توضع إلا عناصر ذات مفاتيح فريدة، رغم أن المفتاح قد يشير إلى قائمة من القيم. تُعَد القواميس مفيدةً للغاية في هيئة هياكل للبيانات، ونجدها في بايثون مثل نوع بيانات مضمَّن في اللغة نفسها، لكن قد نحتاج في بعض اللغات الأخرى إلى استخدام وحدة module، أو بناء واحدة بأنفسنا إذا أردنا استخدام القواميس، وتُستخدم القواميس بعدة طرق سنراها كثيرًا في الأمثلة التالية من الكتاب؛ أما الآن فسنرى أولًا كيف ننشئ قاموسًا في بايثون، ثم نملؤه ببعض المدخلات ونقرؤها. >>> dct = {} >>> dct['boolean'] = "A value which is either true or false" >>> dct['integer'] = "A whole number" >>> print( dct['boolean'] ) A value which is either true or false لاحظ أننا نبدأ القاموس بأقواس معقوصة ثم نستخدم الأقواس المربعة لإسناد القيم وقراءتها، كما تُستخدم دالة النوع dict() لإعادة قاموس فارغ، ويمكن بدء القاموس أثناء إنشائه كما فعلنا في حالة القوائم، باستخدام الصيغة التالية: >>> addressBook = { ... 'Samy' : ['Samy', '9 Some St',' Anytown', '0123456789'], ... 'Warda' : ['Warda', '11 Nother St', 'SomePlace', '0987654321'] ... } >>> يُفصل المفتاح والقيمة بنقطتين رأسيتين، وتُفصل الأزواج بفواصل إنجليزية ,، كما يمكن تخصيص القاموس باستخدام صيغة مختلفة -انظر أدناه-، ويمكنك اختيار إحدى الطريقتين لاستخدامها. >>> book = dict(Samy=['Samy', '9 Some St',' Anytown', '0123456789'], ... Warda=['Warda', '11 Nother St', 'SomePlace', '0987654321']) >>> print( book['Samy'][3] ) 0123456789 لاحظ أننا لا نحتاج إلى علامات اقتباس حول المفتاح في التعريف، لأن بايثون تفترض أنها سلسلة نصية، لكننا نحتاج إليها بأي حال من أجل استخراج القيم، وهذا الأسلوب يَحُد من عملية الطريقة الثانية، لهذا يفضِّل المبرمجون استخدام الطريقة الأولى التي يستخدمون الأقواس المعقوصة فيها، وبهذا نكون قد أنشأنا دفتر عناوين من قاموس مفاتيحه هي الأسماء، ويخزن قوائمنا مثل قيم، ونريد أن نستخدم الاسم وحده لجلب كل المعلومات بدلًا من حساب الفهرس العددي، كما يلي: >>> print( addressBook['Warda'] ) ['Warda', '11 Nother St', 'SomePlace', '0987654321'] >>> print( addressBook['Samy'][3] ) 0123456789 في الحالة الثانية فهرسنا القيم المعادة من أجل الحصول على رقم هاتف فقط، لكن يمكن جعل هذا أسهل عبر إنشاء بعض المتغيرات وإسناد قيم الفهرسة المناسبة، كما يلي: >>> name = 0 >>> street = 1 >>> town = 2 >>> tel = 3 نستطيع الآن استخدام تلك المتغيرات لنعرف اسم مدينة Warda: >>> print( addressBook['Warda'][town] ) SomePlace لاحظ أن town ليست داخل علامات اقتباس لأنها اسم متغير، وستحوله بايثون إلى قيمة الفهرس التي أسندناها -وهي 2-، على عكس 'Warda' المحاطة بعلامات اقتباس لأن المفتاح هو سلسلة نصية، وهنا بدأ دفتر العناوين يتحول إلى ما يشبه التطبيق القابل للاستخدام بسبب مزايا القواميس، حيث لن نحتاج إلى كثير من العمل الإضافي لحفظ البيانات واستعادتها وإضافة محث استعلام ليسمح لنا بتحديد البيانات التي نريدها. يمكن استخدام قاموس لتخزين البيانات، وسيكون دفتر العناوين حينها قاموسًا مفاتيحه الأسماء، وستكون القيم قواميس مفاتيحها هي حقول الأسماء، كما يلي: addressBook = { ... 'Samy' : {'name': 'Samy', ... 'street': '9 Some St', ... 'town': 'Anytown', ... 'tel': '0123456789'}, ... 'Warda' : {'name': 'Warda', ... 'street': '11 Nother St', ... 'town': 'SomePlace', ... 'tel': '0987654321'} ... } لاحظ أن هذا التنسيق سهل القراءة رغم أنه يحتاج إلى الكثير من الكتابة، ويُشار إلى مثل هذه البيانات التي تخزَّن بتنسيق يجمع بين المعنى والمحتوى في تنسيق مقروء للبشر باسم البيانات الموثقة ذاتيًا. حين ندخِل هيكل بيانات داخل هيكل آخر مطابق له، كما في حالة إدخال قاموس داخل قاموس آخر هنا، فإنه يُسمى بالتداخل أو التشعب nesting، حيث يكون القاموس الداخلي قاموسًا متشعبًا من الخارجي، ويمكن الوصول إلى تلك البيانات بطريقة تشبه أسلوب القوائم ذات الفهارس المسماة: >>> print( addressBook['Warda']['town'] ) SomePlace وليس ثمة اختلاف إلا في الاقتباس الإضافي حول كلمة town التي هي ليست موجودةً في حالة القوائم، وميزة هذا الأسلوب أننا نستطيع إدخال حقول جديدة دون تعطيل الشيفرة الحالية، بينما نضطر في حالة الفهارس المسماة إلى العودة لتغيير جميع قيم الفهارس، وتبرز أهمية هذا الأسلوب عند استخدام نفس البيانات في عدة برامج، فيكون بذل قليل من الجهد هنا موفرًا لكثير من العمل لاحقًا في المستقبل. لا تدعم القواميس كثيرًا من عوامل التجميعات التي رأيناها من قبل، فلا تدعم عامل الضم ولا التكرار ولا الإلحاق، رغم إمكانية إسناد أزواج من المفاتيح والقيم مباشرةً كما رأينا في بداية هذا القسم. وتُستخدم العملية keys() لتسهيل الوصول إلى مفاتيح القاموس، إذ تسمح لنا بالحصول على قائمة من جميع المفاتيح الموجودة في قاموس ما، فإذا أردنا الحصول على كل الأسماء الموجودة في دفتر العناوين الذي أنشأناه من قبل؛ فسيكون ذلك كما يلي: >>> print( list(addressBook.keys()) ) ['Samy','Warda'] لاحظ أننا استخدمنا list() للحصول على قيم المفاتيح الحقيقية، أما إذا حذفنا list() فسنحصل على نتيجة غريبة بعض الشيء لن نذكرها الآن. لاحظ أن القواميس لا تخزِّن مفاتيحها بنفس ترتيب إدخالها، فقد نرى أن المفاتيح تظهر بترتيب غريب عن ترتيبها الأول، بل قد يتغير الترتيب بتغير الوقت، لكن هذا لا يهم بما أننا نستطيع استخدام المفاتيح للوصول إلى البيانات المرتبطة بها، إذ سنحصل على القيم الصحيحة في كل مرة. يمكن الحصول على قائمة بجميع القيم أيضًا باستخدام العملية values()، فجرب ذلك على دفتر العناوين وانظر إن استطعت تنفيذها بنجاح، استخدم مثال keys() السابق للاسترشاد به، ويمكن بصورة مماثلة استخدام العامل in على القاموس ليخبرنا هل توجد قيمة ما في صورة مفتاح للقاموس أم لا. قواميس VBScript توفر VBScript كائن قاموس يقدم تسهيلات تماثل قاموس بايثون، لكن استخدامه مختلف قليلًا عن حالة بايثون، حيث ننشئ القاموس هنا بالتصريح عن متغير يحمل الكائن، ثم ننشئ ذلك الكائن، وبعد ذلك نضيف المدخلات إلى القاموس الجديد كما يلي: Dim dict ' Create a variable. Set dict = CreateObject("Scripting.Dictionary") dict.Add "a", "Athens" ' Add some keys and items. dict.Add "b", "Belgrade" dict.Add "c", "Cairo" لاحظ أن دالة CreateObject توضح أننا ننشئ كائن "Scripting.Dictionary"، وهو كائن Dictionary من وحدة Scripting الخاصة بلغة VBScript، وسندرس ذلك بالتفصيل حين نأتي على الكائنات، لكننا نأمل بذكرها هنا أن تتذكر مفهوم استخدام كائن من وحدة ما كما ذكرنا في فصل التسلسلات البسيطة. يجب كذلك استخدام كلمة Set المفتاحية عند إسناد كائن إلى متغير في VBScript. نستطيع الآن أن نصل إلى البيانات كما يلي: item = dict.Item("c") ' Get the item. dict.Item("c") = "Casablanca" ' Change the item توجد عمليات أخرى لإزالة عنصر ما، والتحقق من وجود مفتاح ما، والحصول على قائمة بجميع المفاتيح وغير ذلك. كما يمكن تخزين أي نوع من الكائنات في القاموس إذ أن الأمر ليس مقصورًا على السلاسل النصية فقط، وهذا يعني أننا نستطيع إنشاء قواميس متشعبة بما أن القاموس نفسه ما هو إلا كائن. فيما يلي نسخة كاملة مبسطة عن مثال دفتر العناوين السابق، ولكن في VBScript: <script type="text/VBScript"> Dim addressBook Set addressBook = CreateObject("Scripting.Dictionary") addressBook.Add "Samy", "Samy, 9 Some St, Anytown, 0123456789" addressBook.Add "Warda", "Warda, 11 Nother St, SomePlace, 0987654321" MsgBox addressBook.Item("Warda") </script> ما فعلناه هنا هو تخزين جميع البيانات مثل سلسلة نصية واحدة بدلًا من استخدام قائمة -وهذا يصعّب استخراج الحقول المنفردة على عكس القائمة والقاموس-، ثم نستطيع الوصول إلى تفاصيل Warda ونطبعها في صندوق رسالة. قواميس جافاسكربت لا تحتوي جافاسكربت على كائن قاموس فيها، رغم أننا نستطيع الوصول إلى كائن Scripting.Dictionary الذي ذكرناه في VBScript باستخدام إنترنت إكسبلورر، لنتمكن حينئذ من استغلال جميع مزاياه، لكن لن نشرح ذلك هنا مرةً أخرى بما أنه نفس الكائن. تستطيع هنا الانتقال إلى الفصل التالي إذا كنت قد شعرت بالملل من طول هذا الفصل وتريد كتابة شيفرات وتجربتها، لكن تذكر أن تعود وتنهي هذا الفصل حين تتعرض لأنواع بيانات لم نذكرها حتى الآن. المصفوفات أو المتجهات Arrays المصفوفة هي أحد أنواع التجميعات التي يمتد تاريخها موازيًا لتاريخ الحوسبة، وما هي إلا مجموعة من العناصر المفهرسة بحيث يسهل جلبها بسرعة، والغالب أننا يجب أن نحدد عدد العناصر التي نريد تخزينها في المصفوفة مسبقًا، إذ يُخزَّن نوع واحد أيضًا من البيانات في المصفوفة عادةً، وهاتان الخاصيتان للمصفوفة هما اللتان تميزانها عن القوائم مثلًا. لاحظ أننا قد قلنا "عادة"، و"الغالب" للدلالة على غالب الحالات، ذلك أن لغات البرمجة المختلفة لها أساليبها الخاصة التي تصف المصفوفات، لذا يصعب وضع وصف يغطي جميع الحالات. تدعم لغة بايثون المصفوفات من خلال وحدة تسمى array، لكننا لا نحتاج إليها إلا نادرًا مع استثناء حالات الحساب الرياضي عالي الأداء؛ أما غير ذلك فنستخدم القوائم، وفي لغتي جافاسكربت وVBScript؛ تتكون المصفوفات مثل نوع بيانات، لذا سننظر في كيفية استخدامها فيهما. مصفوفات VBScript تكون المصفوفة في VBScript تجميعة بيانات ذات طول ثابت، حيث يمكن التوصَل إليها بواسطة فهرس عددي، ويصرَّح عنها ويوصَل إليها كما يلي: Dim AnArray(42) ' A 43! element array AnArray(0) = 27 ' index starts at 0 AnArray(1) = 49 AnArray(42) = 66 ' assign to last element myVariable = AnArray(1) ' read the value تُستخدم الكلمة المفتاحية Dim لتحديد أبعاد المتغير، وهي الطريقة التي نخبر بها VBScript عن المتغير، فهي تتوقع إذا بدأنا الشيفرة بـ OPTION EXPLICIT؛ أن نحدد أبعاد أي متغير نستخدمه من خلال Dim، وهذا سلوك محمود يؤدي إلى برامج ثابتة قوية الأداء، كما أننا حددنا آخر فهرس صالح 42، وهذا يعني أن المصفوفة فيها 43 عنصرًا بما أنها تبدأ من الصفر. تُستخدم الأقواس في VBScript لحساب أبعاد المصفوفة وفهرستها، وهذا على خلاف الأقواس المربعة المستخدمة في بايثون وجافاسكربت، حيث لا يوجد في VBScript نوع بيانات إلا النوع Variant، والذي يخزِّن أي نوع من أنواع القيم، وبناءً عليه فلا تخزِّن المصفوفات في هذه اللغة إلا المتغيرات بما أن عناصر المصفوفة تكون من نوع واحد، لكن في نفس الوقت، فإن المتغير هنا قد يحمل أي نوع من أنواع القيم، مما يعني مرةً أخرى أن المصفوفات في VBScript تخزن أي شيء، وهذا أمر مربك عند التفكير فيه. نستطيع أيضًا الإسناد إلى أي موضع في المصفوفة بما في ذلك الموضع الأخير، من غير أن نملأ المواضع التي قبله، وسيُضبط أي عنصر غير مهيأ إلى القيمة الخاصة Null. كما يمكن التصريح عن عدة مصفوفات متعددة الأبعاد لنمذجة جداول بيانات كما في قوائم بايثون إذا استخدمنا تدريب دفتر العناوين مثلًا. Dim MyTable(2,3) ' 3 rows, 4 columns MyTable(0,0) = "Samy" ' Populate Samy's entry MyTable(0,1) = "9 Some Street" MyTable(0,2) = "Anytown" MyTable(0,3) = "0123456789" MyTable(1,0) = "Warda" ' And now Warda... ...and so on... لكن لا توجد طريقة سهلة لملء البيانات دفعةً واحدةً كما فعلنا في قوائم بايثون، بل يجب أن نملأ كل حقل على حدة، وعلى الرغم من وجود الدالة Arrayفي VBScript والتي تستطيع ملء مصفوفة دفعةً واحدةً -مما يعني الحاجة إلى جعلها متشعبةً-؛ فستصبح معقدةً وصعبة القراءة. إذا دمجنا قواميس VBScript مع هذه الخاصية لمصفوفاتها، فسنحصل على نفس النتيجة التي حصلنا عليها في بايثون، كما يلي: <script type="text/VBScript"> Dim addressBook Set addressBook = CreateObject("Scripting.Dictionary") Dim Samy(3) Samy(0) = "Samy" Samy(1) = "9 Some St" Samy(2) = "Anytown" Samy(3) = "0123456789" addressBook.Add "Samy", Samy MsgBox addressBook.Item("Samy")(3) ' Print the Phone Number </script> وآخر ملاحظة متعلق بمصفوفات VBScript هو أنها لا تحتاج إلى أن تكون ثابتة الحجم، على أن هذا لا يعني استمرار إضافة العناصر إليها كما في القوائم، بل يجب أن نغير حجم المصفوفة صراحةً، بالتصريح عن مصفوفة ديناميكية، وذلك بإهمال ذكر الحجم ببساطة، كما يلي: Dim DynArray() ' no size specified ثم إذا أردنا تغيير حجمها نفعل ذلك كما يلي: <script type="text/vbscript"> Dim DynArray() ReDim DynArray(5) ' Initial size = 5 DynArray(0) = 42 DynArray(4) = 26 MsgBox "Before: " & DynArray(4) ' prove that it worked ' Resize to 21 elements keeping the data we already stored ReDim Preserve DynArray(20) DynArray(15) = 73 MsgBox "After Preserve: " & DynArray(4) & " " & DynArray(15)' Old and new still there ' Resize to 51 items but lose all data Redim DynArray(50) MsgBox "Without Preserve: " & DynArray(4) & " Oops, Where did it go?" </script> لاحظ أن السلوك الافتراضي هو حذف كل محتويات المصفوفة عند تغيير حجمها، فإذا أردنا الحفاظ على محتوياتها؛ فيجب أن نخبر VBScript أن تحفظ المحتويات باستخدام Preserve. هذا الأسلوب غير مريح موازنةً بالقوائم التي تغير حجمها تلقائيًا، لكنه يعطي المبرمج تحكمًا أفضل في كيفية تصرف البرنامج، مما يحسن الأمان -ضمن أمور أخرى- نظرًا لأن بعض الفيروسات قد تستغل مخازن البيانات القابلة لتغيير حجمها ديناميكيًا. مصفوفات جافاسكربت رغم أنه يطلَق على هذا النوع من البيانات في جافاسكربت مصفوفة؛ إلا أنها تسمية خاطئة، فهو مزيج غريب يجمع بين مزايا القوائم والقواميس والمصفوفات العادية، حيث نستطيع مثلًا التصريح عن مصفوفة من عشرة عناصر من نوع ما كما يلي: var items = new Array(10); لاحظ استخدام كلمة new المفتاحية، إذ تشبه دالة CreateObject() التي استخدمناها في VBScript لإنشاء قاموس، كذلك فقد استخدمنا الأقواس لتحديد حجم المصفوفة، نستطيع الآن أن نملأ المصفوفة ونصل إليها كما يلي: items[4] = 42; items[7] = 21; var aValue = items[4]; وهنا نستخدم الأقواس المربعة للوصول إلى عناصر المصفوفة، وتبدأ الفهارس فيها من الصفر، لكن رغم هذا كله فمصفوفات جافاسكربت ليست مقيدة بتخزين نوع واحد من البيانات، بل يمكن إسناد أي شيء إلى عناصرها: items[9] = "A short string"; var msg = items[9]; كما يمكن إنشاء مصفوفات من خلال توفير قائمة بالعناصر: var moreItems = new Array("one","two","three",4,5,6); aValue = moreItems[3]; // -> 4 msg = moreItems[0]; // -> "one" كذلك يمكن تحديد طول المصفوفة باستخدام خاصية تدعى length، التي تستخدَم كما يلي: var size = items.length; وعلى غرار أسلوب بايثون في استدعاء الدوال في وحداتها، فإن الصياغة name.property هنا هي نفسها، لكن دون أقواس لاحقة. ورغم أن مصفوفات جافاسكربت تبدأ بالصفر كما ذكرنا؛ إلا أن فهارسها ليست مقصورةً على الأرقام وحدها، ولهذا يمكن استخدام السلاسل النصية أيضًا -والتي تكون هنا أشبه بالقواميس-، كما يمكن توسيع مصفوفة بإسناد قيمة إلى فهرس تكون أكثر من الحد الأقصى الحالي، مما يعني أننا لا نحتاج إلى تحديد الحجم عند إنشاء المصفوفة، رغم كون ذلك سلوكًا مستحسنًا في البرمجة، ويوضح المثال التالي خصائص مصفوفات جافاسكربت التي ذكرناها: <script type="text/javascript"> var items = new Array(10); var moreItems = new Array(1); items[42] = 7; moreItems["foo"] = 42; msg = moreItems["foo"]; document.write("msg = " + msg + " and items[42] = " + items[42] ); </script> إذا شغّلنا تلك الشيفرة في المتصفح فسنرى القيم مكتوبةً على الشاشة. تحقق إن كنت تستطيع متابعة الإسنادات في الشيفرة لتتأكد من سبب ظهور القيم التي تراها على الشاشة. لننظر أخيرًا في مثال دفتر العناوين مرةً أخرى، باستخدام مصفوفات جافاسكربت هذه المرة: <script type="text/javascript"> var addressBook = new Array(); addressBook["Samy"] = new Array("Samy", "9 Some St", "Anytown", "0123456789"); addressBook["Warda"] = new Array("Warda", "11 Nother St", "SomePlace", "0987654321"); document.write(addressBook.Warda); </script> يمكن الوصول إلى المفتاح كما لو كان خاصيةً مثل length، ويتبين مما سبق أن مصفوفات جافاسكربت ما هي إلا هياكل بيانات مرنة للغاية. المكدس Stack يكدِّس العاملون في المطاعم الأطباق النظيفة فوق بعضها، ثم تؤخَذ واحدًا تلو الآخرللعملاء بدءًا من الأعلى، فيكون الطبق الأخير هو آخر طبق يُستخدم، وفي نفس الوقت أقل طبق يُستخدم، يشبه هذا المثال مكدسات البيانات بالضبط، إذ نضع العنصر في قمة المكدس أو نأخذ عنصرًا منه، ويكون العنصر المأخوذ هو آخر عنصر مضاف إلى المكدس، ويطلَق على هذه الخاصية للمكدسات "آخرها دخولًا أولها خروجًا" أو LIFO - Last In First Out. من الخصائص المفيدة في المكدسات أننا نستطيع عكس قائمة العناصر عن طريق دفع القائمة في المكدس ثم إخراجها مرةً أخرى، فتكون النتيجة عكس القائمة الأولى. لا تأتي المكدسات مدمجةً في بايثون ولا VBScript ولا جافاسكربت، بل يجب كتابة بعض التعليمات البرمجية في البرنامج من أجل الحصول على سلوك المكدس، والقوائم هي أفضل نقطة بداية في الغالب للمكدسات بما أنه يمكن زيادة حجمها عند الحاجة. تدريب اكتب مكدسًا باستخدام قائمة في بايثون، وتذكر أننا نلحق العناصر في نهاية القائمة باستخدام append()، ونحذفها باستخدام فهارسها عن طريق del()، كما تستطيع استخدام -1 مثل فهرس يشير إلى آخر عنصر في القائمة. يجب أن تكون قادرًا على كتابة برنامج -مستفيدًا من هذه الإرشادات- يدفع 4 محارف إلى قائمة ثم يخرجها مرةً أخرى، ثم اطبعها بعد ذلك. راقب الترتيب الذي تستدعي به print و del، وإذا نجحت في هذا، فجرب طباعتها بعكس الترتيب الذي أدخلتها به، استخدم العملية pop() الخاصة بقوائم بايثون والتي تعيد العنصر الأخير وتحذفه في خطوة واحدة، من أجل تسهيل التدريب. الحقيبة Bag في سياق الحديث عن البيانات؛ تُعَد الحقيبة تجميعةً من العناصر التي ليس لها ترتيب محدد، ويمكن أن تحتوي على عناصر مكررة، وتكون لها عادةً عوامل تمكننا من إضافة تلك العناصر وحذفها وإيجادها، فما هي إلا قوائم في اللغات الثلاث التي نستخدمها في الكتاب. المجموعات Sets تخزن المجموعة نوعًا واحدًا من العناصر، ونستطيع التحقق مما إذا كان العنصر موجودًا في المجموعة أم لا -أي عضوًا فيها-، إلى جانب إضافة تلك العناصر وحذفها، بالإضافة إلى دمج مجموعتين معًا بطرق شتى تتوافق مع نظرية المجموعات في الرياضيات، مثل الاتحاد والتقاطع وغيرها، لكن على هذا فالمجموعات لا تكون مرتبةً ولا تهتم للترتيب. لا تستخدم جافاسكربت ولا VBScript المجموعات مباشرةً، لكن يمكن تنفيذ سلوك قريب باستخدام القواميس التي لا تحتوي إلا على مفاتيح بقيم فارغة؛ أما بايثون فتدعم المجموعات مثل نوع من أنواع البيانات فيها، وأحد الاستخدامات البسيطة لها ما يلي: >>> A = set() # أنشئ مجموعة فارغة >>> B = set([1,2,3]) # مجموعة من قائمة >>> C = {3,4,5} # تهيئة مثل [] في القوائم >>> D = {6,7,8} >>> # جرب الآن بعض عمليات القوائم >>> print( B.union(C) ) {1, 2, 3, 4, 5} >>> print( B.intersection(C) ) {3} >>> print( B.issuperset({2}) ) True >>> print( {3}.issubset(C) ) True >>> print( C.intersection(D) == A ) True لاحظ أننا نستطيع تهيئة المجموعة باستخدام الأقواس المعقوصة، لكن هذا قد يتشابه مع القواميس، لذا نفضل استخدام الصيغة set([...]]) رغم أنها تتطلب كتابةً أكثر، فيما يلي اختصارات لعمليات الاتحاد والتقاطع: >>> print( B & C ) # B.intersection(C) كما في >>> print( B | C ) # B.union(C) كما في نستطيع أخيرًا التحقق من وجود عنصر ما في مجموعة باستخدام العامل in: >>> print( 2 in B ) True هذه العمليات كافية إلى الآن لما نشرحه، رغم وجود عمليات أخرى على المجموعات. الطابور Queue يشبه الطابور أو قائمة الانتظار؛ المكدس، باستثناء أن العنصر الأول فيه الذي يخرج أولًا أيضًا، ويسمى هذا السلوك "الأول دخولًا الأول خروجًا" أو FIFO - First In First Out، ويُنشَأ الطابور باستخدام قائمة أو مصفوفة. تدريب جرب كتابة طابور باستخدام قائمة، وتذكر أنك تستطيع الإضافة إلى القائمة باستخدام append()، وأن تحذف من موضع ما باستخدام del(). أضف أربعة محارف إلى الطابور ثم استخرجها واطبعها، غذ يجب أن تُطبع المحارف بنفس الترتيب الذي دخلت به. توجد أنواع أخرى من تجميعات البيانات، لكن ما ذكرناه هنا يغطي أغلب الحالات التي ستراها أثناء البرمجة، بل لن نستخدم إلا قليلًا مما ذكرناه هنا في الشرح، لكن قد ترى بقية الأنواع في المقالات أو مجموعات النقاشات البرمجية. الملفات Files ينبغي أن يكون مستخدم الحاسوب معتادًا على التعامل مع الملفات بما أنها تمثل أساس كل شيء نفعله على الحواسيب، ولا غرو إذًا أن نكتشف أن أغلب لغات البرمجة توفر نوع file خاص من البيانات، لكن أهمية الملفات ومعالجتها ستجعلنا نرجئ الحديث عنها وشرحها إلى فصل لاحق خاص بها. وبهذا تكون قد تعرفت على أبرز البيانات البرمجية التي قد تحتاج إليها. ترجمة -بتصرف- للفصل الخامس: The Raw Materials من كتاب Learning To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: بعض التسلسلات النصية المهمة لتعلم البرمجة المقال السابق: مدخل إلى البيانات وأنواعها: أنواع البيانات الأساسية مدخل إلى البيانات الوصفية microdata في HTML5 هياكل البيانات: الكائنات والمصفوفات في جافاسكريبت1 نقطة
-
من الضروري أن تكون البرامج التي نكتبها سهلة القراءة بمجرد النظر إليها، لأن أخلاط الرموز الغريبة المتجاورة والأقواس المتتالية والكلمات المبتورة من اللغة الإنجليزية؛ تكفي ليظن الناظر إلى الشيفرة أن طفلًا صغيرًا عبث بيده على لوحة المفاتيح، فإذا اخترنا أسماءً مفهومةً للمتغيرات تدل على وظائفها، ورتبنا الأسطر فجعلنا كل مجموعة منها تنفذ مهمةً ما بإزاحة خاصة بها، وكتبنا تعليقات توضح سبب اختيار الأرقام أو الرموز التي لا يبدو لها سبب منطقي، وقبل كل ذلك افتتحنا الملف ببيانات تعريفية له نعرف بها من كتبه وإصدار البرنامج وغير ذلك، وإذا اتبعنا مثل هذه السلوكيات -وهي المتبعة في البرمجة بالفعل-؛ فسنوفر كثيرًا من الجهد والوقت اللذين سيهدرَان في معرفة غرض كل سطر من البرنامج ومشاكله المستقبلية، ويسهل تحديثه لاحقًا وإضافة ميزات جديدة للبرنامج. التعليقات تحدثنا عن التعليقات في مقال بعض التسلسلات النصية المهمة لتعلم البرمجة، وسنلقي في هذا المقال الضوء على بعض تطبيقاتها واستخداماتها. سجل الإصدارات يجب على المبرمج أن يسهّل على من يقرأ برامجه معرفة التفاصيل الأساسية لكل ملف، مثل تاريخ إنشائه واسم مؤلفه وبيانات آخر تعديل فيه وإصداره ووصف عام لمحتوياته، وبقية المعلومات التي تدخل في سجل تغييراته، وهذه الكتلة النصية تُكتب في تعليق، بالشكل التالي: ############################# # Module: Spam.py # Author: A.J.Gauld # Version: Draft 0.4 ''' This module provides a Spam class which can be combined with any other type of Food object to create interesting meal combinations. ''' ############################### # Log: # 2015/09/01 AJG - File created # 2015/09/02 AJG - Fixed bug in pricing strategy # 2015/09/02 AJG - Did it right this time! # 2016/01/03 AJG - Added broiling method(cf Change Req #1234) ################################ import sys, string, food ... نرى في هذا المثال ملخصًا بسيطًا لما يحتويه الملف بمجرد فتحه، فنعرف ما الذي تغير فيه من ما قبله، ومن الذي نفذ هذه التغييرات ووقت إجرائها، وتبرز أهمية هذه المعلومات عند العمل على المشروع ضمن فريق، وذلك حين نحتاج إلى معرفة المسؤول عن التغيير الذي بين أيدينا أو تصميم البرنامج الذي تعمل عليه، وقد وضعنا الوصف بين زوج من علامات الاقتباس الثلاثية، وهذا أسلوب تتبعه بايثون يسمى سلسلة التوثيق، ويُستخدم لإضافة هذا التوثيق والوصف إلى الدالة help() المضمَّنة فيها، كما سنرى بعد قليل. من المهم ملاحظة وجود أدوات تعمل مثل مستودعات للشيفرات البرمجية، مثل Git وSubversion وCVS وRCS، إذ تستطيع الاحتفاظ بمعلومات تلقائيًا، مثل اسم المؤلف واسم الملف وتفاصيل سجل الإصدار وننصح بالنظر في خصائص التوثيق في تلك المستودعات وتعلمها، لأنها توفر الكثير من الوقت الضائع في التسجيل اليدوي لهذه التعليقات. تعطيل الشيفرات الفاسدة تُستخدم التعليقات لعزل جزء فاسد أو غير صالح من الشيفرة عن باقي البرنامج، كأن يكون لدينا برنامج يقرأ بعض البيانات ويعالجها، ويطبع الخرج ثم يحفظ النتائج في ملف البيانات مرةً أخرى، ويجب منع حفظ البيانات الخاطئة أو الفاسدة في الملف وإفساده؛ إذا كانت النتائج على غير ما نريد أو نتوقع. وقد يقال أن الحل الأبسط هو حذف الشيفرة الفاسدة، وهذا صحيح؛ لكننا نستطيع عزلها وتعطيل تنفيذها بتحويلها إلى تعليق، لإصلاحها فيما بعد، وذلك كما يلي: data = readData(datafile) for item in data: results.append(calculateResult(item)) printResults(results) ###################### # تُعزل الشيفرة أدناه إلى حين إصلاح # calculateResult الزلة التي في # for item in results: # dataFile.save(item) ###################### print 'Program terminated' ثم نحذف علامات التعليق إذا أصلحنا ذلك الخلل، لجعل الشيفرة نشطةً مرةً أخرى. تحتوي العديد من المحررات البرمجية مثل IDLE، خاصيةً نستطيع فيها اختيار جزء من الشيفرة وتحويله إلى تعليق تلقائيًا، ثم إلغاء ذلك التحديد عند الحاجة، وسنجد هذه الخاصية في IDLE في القائمة Format ثم الخيار Comment Out Region. سلاسل التوثيق تسمح جميع اللغات البرمجية بإنشاء تعليقات لتسجيل ما تفعله الدالة أو الوحدة التي نكتبها، لكن قليلًا منها يزيد على ذلك بأن يسمح لنا بتوثيق الدالة بطريقة تستطيع اللغة أو البيئة نفسها أن تستفيد منها لتوفر لنا مساعدةً تفاعليةً أثناء البرمجة، ومن تلك اللغات: جافا وبايثون وSmalltalk، نستخدم هذه الخاصية في بايثون من خلال علامات الاقتباس الثلاثية التي على نمط """documentation""": class Spam: """A meat for combining with other foods It can be used with other foods to make interesting meals. It comes with lots of nutrients and can be cooked using many different techniques""" def __init__(self): pass # ie. it does nothing! help(Spam) لاحظ أننا نستطيع الوصول إلى سلسلة التوثيق باستخدام الدالة help()، وأن سلاسل التوثيق تصلح للوحدات والدوال والأصناف والتوابع، لننظر إلى الشيفرة التالية: >>> import sys >>> help (sys.exit) Help on built-in function exit: exit(...) exit([status]) Exit the interpreter by raising SystemExit(status). If the status is omitted or None, it defaults to zero (i.e., success). If the status is numeric, it will be used as the system exit status. If it is another kind of object, it will be printed and the system exit status will be one (i.e., failure). (END) إذا أردنا الخروج من وضع المساعدة الذي في المثال السابق عند رؤية END؛ التي تشير إلى نهاية التوثيق، فسنضغط على مفتاح Q في لوحة المفاتيح، وهو اختصار كلمة Quit؛ أما إذا كان التوثيق أكثر من صفحة، فسنضغط على مفتاح المسافة لتصفحه، ومن الجدير بالذكر أن كلمة END التي في نهاية التوثيق قد لا تظهر في بعض الطرفيات. توجد دالة مساعِدة أخرى هي dir()، والتي تعرض جميع المزايا التي تعرفها بايثون عن كائن ما، فإذا أردنا معرفة الدوال أو المتغيرات الموجودة في وحدة sys مثلًا، فسنكتب ما يلي: >>> import sys >>> dir(sys) [..... 'argv', 'builtin_module_names', 'byteorder', .... 'copyright', .... 'exit', ..... 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_info', 'warnoptions', 'winver'] بعد ذلك سنختار ما نريد منها، ونستخدم دالة help() للحصول على مزيد من المعلومات، وقد أهملنا العديد من المدخلات في المثال أعلاه لتوفير المساحة، كما نستفيد من وظيفة الدالة dir() عند استخدام وحدة ليس لها توثيق جيد أو كافٍ، فقد نتعامل مع وحدات ليس لها توثيق خارجي أصلًا. إزاحة الكتل ذكرنا عدة مرات أن إزاحة الأسطر مهمة في بايثون، وتتوقف عليها الإجراءات التالية للأسطر المزاحة، مع أن أكثر لغات البرمجة لا تهتم بإزاحة الأسطر، لذا يزيح المبرمجون الأسطر في برامجهم وشيفراتهم لتسهيل قراءتها وتمييز أجزائها لا أكثر، فقد صار لكل مبرمج تقريبًا أسلوبه الخاص في الإزاحة وفق ما يراه مناسبًا، وقد ولّدت كثرة الأهواء والآراء في هذا الشأن جدالات حامية الوطيس في البرمجة منذ زمن، بلغت حد إجراء بدراسات للوقوف على الجوانب التي تؤثر فيها إزاحة الأسطر سوى المظهر الجمالي، كأن تساعد في فهم الشيفرة البرمجية بطريقة أسرع وأسهل، لننظر في المثال التالي من VBScript مثلًا: < script type="text/vbscript"> For I = 1 TO 10 MsgBox I Next </script> ثم لننظر إلى النسخة التالية منه، والتي لا تحوي إزاحات للأسطر: < script type="text/vbscript"> For I = 1 TO 10 MsgBox I Next </script> يكاد المثالان يتطابقان في نظرنا نحن البشر، والفرق بينهما هو أن النسخة الأولى أسهل في القراءة في نظرنا، أما في نظر مفسر VBScript فهما متطابقتان تمامًا ولا فرق بينهما، والشرط الحاكم للإزاحة هنا هو أن تعكس الهيكل المنطقي للشيفرة، فتتبع تدفق البرنامج في هيئتها المرئية، وقد أظهرت الدراسات التي أجريت على الشيفرات المزاحة أن الشيفرات المقسَّمة بصريًا إلى كتل تعكس البنية الكتلية المنطقية للبرنامج؛ أسهل في الفهم، وعلى ذلك تكون البنية التالية: XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX أسهل في فهم مرادها ووظيفتها من هذه البنية: XXXXXXXXXXXXXXXXXXXXX XXXXX XXXXXXXXXXXX XXXXXXXXXXXX XXXXXXXXXXXX XXXXX قد لا تظهر أهمية الإزاحة في الأمثلة البسيطة التي أوردناها إلى الآن، لكن الفرق يتضح عند التعامل مع برامج تحتوي على مئات الآلاف من الأسطر البرمجية. يتبقى الآن أن ننظر في مقدار تلك الإزاحة، وهو أمر طال الخلاف حوله في مجال البرمجة، ويكمن الاختلاف بين استخدام المسافات spacebar للإزاحة أو استخدام زر الجدول tab. ومع أن استخدام زر الجدول أسهل لأنه يؤدي الغرض بنقرة واحدة؛ غير أن هذه النقرة الواحدة تساوي 8 مسافات، وهي إزاحة كبيرة، كما يصعب تحديد آلية الإزاحة الموجودة في شيفرة ما، فهل نتجت عن استخدام زر المسافة أم زر الجدول، لأننا لا نستطيع استخدامهما معًا، فإما هذا أو ذاك، وتظهر هذه المشكلة لمن يتعامل مع برنامج كتبه مبرمج غيره، ولتجنب هذه المعضلة من بداية تعلمنا للبرمجة، يُفضّل تجنب استخدام زر الجدول في الإزاحة، لأن بعض الدراسات أظهرت أن أفضل صورة للشيفرة -من حيث سهولة القراءة- تتحقق إذا كانت الإزاحة محصورةً بين مسافتين وخمس مسافات؛ أما مستخدمو بايثون فقد اصطلحوا على استخدام أربع مسافات في الإزاحة، على الرغم من صلاحية الأمثلة التي استخدمناها إلى الآن، والتي كانت إزاحاتها أقل من ذلك، لأنها توفر بعض المساحة على الشاشة. أسماء المتغيرات لم نستخدم أسماءً لها معانٍ للمتغيرات في الأمثلة التي أوردناها في ما سبق، لأننا لم نقصد إلا شرح بعض التقنيات البرمجية، لكن يُفضل أن تعكس أسماء المتغيرات ما تمثله في الشيفرة، من حيث الوظيفة التي تنفذها، فقد استخدمنا المتغير multiplier في تدريب جدول الضرب مثلًا؛ والذي سبق أن عرضناه مثل متغير يوضح الجدول الذي نريد طباعته. علمًا أن هذه التسمية أفضل من اختيار اسم عشوائي أو رمزي مثل m الذي لن يسبب مشاكل في تنفيذ الشيفرة، بل سيريحنا في الكتابة بما أنه حرف واحد، لكنه بلا معنىً، وسيتسبب في مشاكل مستقبلية إذا أردنا معرفة وظيفة هذا المتغير، أو أراد مبرمج آخر ذلك. يُفضل في تسمية المتغيرات أن تكون مفهومةً على أن تكون سهلة الكتابة، وأفضل حل لأسماء المتغيرات هو أن تكون قصيرةً وذات معنىً في نفس الوقت، فالأسماء الطويلة مربكة وصعبة الكتابة، فمثلًا: نستطيع استخدام the_table_we_are_printing عوضًا عن multiplier، غير أن هذا الاسم طويل ويتجاوز المعقول في الكتابة البرمجية. حفظ البرامج ذكرنا سابقًا أننا نخسر كل شيء كتبناه في محث بايثون >>> بمجرد الخروج منه، فهو وإن كان ممتازًا في تجربة الأفكار بسرعة؛ إلا أنه غير مفيد على المدى البعيد، إذ نريد أن نكتب البرامج ونشغلها مرةً بعد مرة وقتما نشاء، فهذا هو المنطق، ولفعل ذلك في بايثون؛ ننشئ ملفًا نصيًا للبرنامج ونجعله بالامتداد .py، وهو اصطلاح متبع، رغم أننا نستطيع استخدام أي امتداد نريده هنا، لكن يُفضل اتباع هذا الاصطلاح، ثم نستطيع تشغيل البرنامج من محث سطر أوامر النظام بكتابة ما يلي: C:\WINDOWS> python spam.py فيكون اسم برنامج بايثون هنا هو spam.py، ومحث نظام التشغيل هو C:\WINDOWS>. إحدى مزايا استخدام هذه الطريقة في برامج بايثون أننا نستطيع تشغيل البرنامج بمجرد النقر عليه في مدير الملفات، مثل أي ملف تنفيذي يمثل برنامجًا بما أن ويندوز يربط امتداد .py بمفسر بايثون، كما أن استخدام الملفات لتخزين البرامج يسمح بتصحيح أخطائها دون الحاجة إلى إعادة كتابة الجزء الخاطئ من البرنامج مرةً أخرى في محث بايثون، أو التحرك بالمؤشر في IDLE حتى نتجاوز الخطأ كي نعيد تحديد الشيفرة، لأن IDLE تدعم فتح الملف لتعديله وتشغيله من القائمة Run، ثم خيار Run module، أو باستخدام مفتاح F5 على لوحة المفاتيح. لن نعرض محث بايثون >>> مرةً أخرى في الأمثلة البرمجية التي نشرحها، إذ سنفترض أنك تنشئ البرامج في ملف منفصل وتشغلها إما داخل IDLE أو من محث سطر الأوامر. ملاحظة لمستخدمي ويندوز يمكن إعداد ربط الملفات التي تنتهي بامتداد .py داخل مدير الملفات، مما يسمح بتشغيل برامج بايثون بالنقر المزدوج على أيقونة الملف، والمفترض أن مثبت بايثون قد نفذ هذا الإجراء بالفعل، وللتحقق من ذلك؛ ابحث عن ملف بامتداد بايثون وجرب تشغيله، فإذا نجحت يكون الربط جاهزًا على حاسوبك، حتى لو أخرج لك رسالة خطأ. المشكلة التي قد تواجهها هنا هي أن الملفات التي أيقونتها شعار بايثون نفسه؛ إذ ستشَغل في صندوق DOS ثم تغلَق بسرعة بحيث لا تكاد تراها، ويمكن حل هذا بكتابة السطر التالي في نهاية البرنامج: input("Hit ENTER to quit") سيعرض هذا السطر رسالةً تخبرك أن تضغط زر ENTER للخروج، وينتظر حتى يحدث ذلك؛ أما في إصدارات بايثون الأخيرة فهناك أداة إضافية في ويندوز ستساعدك على تشغيل بايثون دون مشاكل، وهي py.exe، فإذا كتبنا: C:\WINDOWS> py spam.py فستبحث هذه الأداة عن بايثون، وتشغل الشيفرة تشغيلًا صحيحًا، كما تستفيد من أي سطر كامل المسار shebang line داخل الملف لتعرف أي إصدار تستخدمه من بايثون -إذا وُجد أكثر من إصدار مثبت على حاسوبك-. ملاحظة لمستخدمي يونكس يجب أن يحتوي أول سطر في ملف سكربت بايثون على التسلسل #! متبوعًا بالمسار الكامل لبايثون على حاسوبك، ويُعرف سطر المسار الكامل هذا أحيانًا باسم شيبانك shebang باللغة الإنجليزية، وهو السطر الذي يجعل شيفرة بايثون قابلةً للتنفيذ عبر مفسر بايثون المحدد بالمسار، والذي نعثر عليه بكتابة السطر التالي في محث الصدفة shell prompt: $ which python وقد يبدو ذلك المسار كما يلي: #!/usr/local/bin/python مما يسمح لنا بتشغيل الملف دون استدعاء بايثون، بعد إعدادها لتكون قابلةً للتشغيل من خلال chmod كما تعلم: $ spam.py يمكن استخدام /usr/bin/env python بدل معلومات المسار، مثل أسلوب أفضل يمكن تنفيذه على أغلب أنظمة يونكس، بما فيها جميع توزيعات لينكس: #!/usr/bin/env python سيبحث هذا الأمر عن بايثون في مسارك تلقائيًا، غير أن عيبه يظهر عندما توجد عدة إصدارات من بايثون، ولا يعمل السكربت إلا مع إصدار واحد منها فقط عند استخدام ميزة جديدة في بايثون مثلًا، وهنا يُفضَّل استخدام أسلوب المسار الكامل، أو على الأقل تحديد إصدار بايثون المناسب، سواء كان python2 أو python3. أما سطر #! فلا يسبب مشاكل في نظامي ويندوز أو ماك لأنه سيبدو تعليقًا، لذا لا بأس بكتابته عند استخدام هذين النظامين، وذلك تحسبًا لاحتمال تشغيل الشيفرة على حاسوب يونكس يومًا ما، أو استخدام مطلِق py.exe الذي لا يتجاهل سطر المسار الكامل shebang. جافاسكربت وVBScript لا يحتاج من يبرمج مستخدمًا جافاسكربت وVBScript إلى الملاحظات التي ذكرناها أعلاه، لأن هذه البرامج تُحفظ في ملفات. خاتمة تعلمنا في هذا المقال ما يلي: استخدام التعليقات لعزل جزء من الشيفرة مؤقتًا عند الاختبارات أو تنقيح الشيفرة debugging، وكذلك استخدامها لتوفير ترويسة توضيحية يُذكر فيها سجل إصدارات الملف. كيفية استخدام سلاسل التوثيق في توفير معلومات فورية runtime-information عن وحدة ما، والكائنات التي داخلها. فائدة إزاحة كتل الشيفرات في توضيح الترتيب المنطقي لهيكل الشيفرة البرمجية، وتسهيل تتبع عين القارئ لذلك التسلسل المنطقي. حفظ برامج بايثون في ملفات لإعادة تشغيلها في أي وقت، بدلًا من كتابتها في محث بايثون >>> ثم ضياعها عند الخروج منه، وذلك بكتابة $ python progname.py في سطر الأوامر، أو بتشغيل الملف في مدير الملفات بالنقر عليه. ترجمة -بتصرف- للفصل الثامن: Coding Style من كتاب Learning To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: كيفية قراءة البرامج لمدخلات المستخدم المقال السابق: الحلقات التكرارية في البرمجة دليلك الشامل لتعلم البرمجة الوضع الصارم: النمط الحديث لكتابة شيفرات جافاسكربت تحسين الشيفرات المكتوبة بلغة Cpp وتشخيصها دليل Airbnb لتنسيق الشيفرة البرمجية للغة روبي Ruby1 نقطة
-
إذا قرأت المقالات السابقة من هذه السلسلة فأنت على دراية بأننا تعلمنا فيها كيف نكتب أوامر بسيطةً وحيدة المدخلات في بايثون، وعرفنا أهمية البيانات وما نفعله بها، ثم كتبنا تسلسلات أطول قليلًا (5-10 أسطر). وها نحن نقترب من كتابة برامج مفيدة، لكن لا زالت لدينا عقبة هنا، وهي خسارة البيانات والبرامج كلما خرجنا من بايثون على الحاسوب، وإذا كنت تستخدم جافاسكربت أو VBScript فسترى أنك قد خزنت تلك الأمثلة في ملفات تستطيع تشغيلها وقتما أردت، ونريد أن نفعل ذلك مع بايثون أيضًا، وقد ذكرنا من قبل أن هذا ممكن باستخدام أي محرر نصي مثل notepad أو pico ، وذلك بحفظ ملف بامتداد .py ثم تشغيل الملف من محث أوامر نظام التشغيل مع كتابة اسم السكربت مسبوقًا بكلمة python، يستخدم المثال التالي تسلسلًا من أوامر بايثون، فيه كل النقاط التي شرحناها من قبل: # File: firstprogram.py print( "hello world" ) print( "Here are the ten numbers from 0 to 9\n0 1 2 3 4 5 6 7 8 9" ) print( "I'm done!" ) # نهاية الملف لاحظ أن السطرين الأول والأخير ليسا ضروريين، وهما تعليقان سنشرحها في هذا المقال، وقد أضفناهما لنوضح ما يحدث في الملف. يمكن استخدام notepad أو أي محرر نصي لإنشاء الملف طالما سنحفظه بصيغة نصية مجردة، ولا نستخدم معالج نصوص متقدمًا مثل MS Word، لأنه يحفظ الملفات بصيغة ثنائية خاصة لا تستطيع بايثون فهمها، ولا نستخدم صيغة html التي تحوي كثيرًا من النصوص المنسقة التي لا تعني شيئًا لبايثون كذلك. لتشغيل هذا البرنامج افتح سطر أوامر نظام التشغيل الآن، يمكنك مراجعة مقال البداية في تعلم البرمجة لمعرفة سطر أوامر النظام، وانتقل إلى المجلد الذي حفظت فيه ملف بايثون لديك، ثم نفّذه بكتابة python قبله كما ذكرنا: D:\PROJECTS\Python> python firstprogram.py hello world Here are the ten numbers from 0 to 9 0 1 2 3 4 5 6 7 8 9 I'm done! D:\PROJECTS\Python> في السطر الأول محث أوامر ويندوز إضافةً إلى الأمر الذي كتبناه، ثم خرج البرنامج معروضًا قبل أن يظهر محث ويندوز مرةً أخرى، لكن توجد طريقة أسهل، فقد يكون لدينا أكثر من إصدار لبايثون على نفس الحاسوب إذا كان النظام نفسه يستخدم الإصدار الثاني منها لبعض المهام مثلًا، وإذا كتبنا python في تلك الحالة فقد نحصل على أخطاء لم نتوقعها، ولتجنب مثل تلك الحالة نلحق رقم إصدار بايثون الذي نريد استخدامه إلى الاسم، فإذا كنا نريد الإصدار الثالث نكتب: D:\PROJECTS\Python> python3 firstprogram.py لاحظ أنها صارت الآن python3 بدلًا من python فقط، وبذلك سنتجنب كثيرًا من الأخطاء على أغلب نظم التشغيل. مزايا استخدام البيئة المتكاملة يثبَّت مع بايثون تلقائيًا عند تثبيتها على الحاسوب تطبيق مفيد، وهو برنامج مكتوب بلغة بايثون أيضًا، ويسمى IDLE اختصارًا لبيئة التطوير المتكاملة Integrated Development Environment، وهو يعني أن فيه أدوات عديدةً مدمجةً فيه لمساعدة المبرمجين، ولن نتعمق فيه هنا، لكن نريد تسليط الضوء على مزيتين فيه، أولاهما أنه يوفر نسخةً محسنةً من محث بايثون >>> فيها تظليل للكلمات، حيث تُعرَض خصائص اللغة بألوان مختلفة لإبرازها، إضافةً إلى محرر نصي خاص ببايثون، يسمح لك بتشغيل ملفات برنامجك مباشرةً من داخل IDLE، وننصحك بتجربة IDLE إذا لم تكن قد فعلت، وإذا أردت شرحًا للبرنامج فانظر دليل داني يو Danny Yoo عنه. أما في حالة استخدام ويندوز فثمة خيار آخر هو PythonWin الذي يمكن تحميله ضمن حزمة PyWin32، والذي يسمح لنا بالوصول إلى جميع دوال البرمجة الدنيا لـمكتبة MFC الخاصة بويندوز، وهو بديل جيدًا جدًا لبيئة IDLE، لكنه لا يعمل إلا على ويندوز، وستحصل عليه تلقائيًا إذا حمّلت بايثون من ActiveState، فنسختهم فيها جميع مزايا PyWin32 بما فيها Pythonwin افتراضيًا. لكن من الناحية الأخرى فإن IDLE يأتي افتراضيًا في حزمة بايثون القياسية، وهو يعمل على أغلب أنظمة التشغيل، لذا يُستخدم أكثر، ولا تهم الأداة التي تستخدمها بأي حال طالما ليست notepad من ويندوز إذ الخيارات المتقدمة أفضل من مجرد محرر نصي بسيط. أخيرًا، إذا كنت تفضل الأسلوب البسيط في كتابة البرامج فستجد محررات عدةً تدعم البرمجة ببايثون، حيث يوفر محرر ViM مثلًا تظليلًا للكلمات المفتاحية، ويوفر emacs وضع تعديل كامل خاص ببايثون، كما يوفر محرر Scite الخفيف تظليل الكلمات المفتاحية لبايثون إضافةً إلى مزايا أخرى. وإذا اخترت طريق المحررات النصية فستجد نفسك مع الوقت تعمل أمام ثلاث نوافذ في نفس الوقت، هي نافذة المحرر التي تكتب فيها شيفرتك المصدرية وتحفظها، وجلسة بايثون التي تجرب فيها ما تكتب من خلال محث بايثون قبل إضافتها إلى برنامجك في المحرر، وسطر أوامر نظام التشغيل الذي تستخدمه لتشغيل البرنامج من أجل اختباره. أما أغلب المبتدئين فيفضلون أسلوب بيئات التطوير المتكاملة التي تأتي كلها في نافذة واحدة مثل IDLE، والأمر كله اختياري فيه سعة ولهذا اختر ما يناسبك، وإذا كنت تستخدم جافاسكربت أو VBScript؛ فنقترح استخدام أحد المحررات النصية المذكورة أعلاه، ومتصفح ويب حديث لجافاسكربت مثل كروم أو فاير فوكس؛ أما بالنسبة للغة VBScript فهذا يعني إنترنت إكسبلورر حصرًا، وليس متصفح Edge حتى، ويكون المتصفح مفتوحًا على الملف الذي تعمل عليه، فإذا أردت تجربة تغيير أو تعديل ما، فاضغط زر إعادة تحميل الصفحة. التعليقات السريعة إحدى أهم الأدوات البرمجية التي لا يشعر المبتدئون بأهميتها هي التعليقات، وهي أسطر داخل البرنامج تصف ما يحدث فيه، وليس لها أي تأثير على أداء البرنامج أو سير عملياته، فهي أسطر وصفية لما يحدث فقط، إلا أن دورها في غاية الأهمية، إذ تخبر المبرمج ما يفعله البرنامج في كل كتلة برمجية أو كل سطر، ولماذا يتصرف على هذا النحو، وتظهر أهمية التعليقات هنا إذا كان البرنامج الذي يقرؤه المبرمج قد كتبه شخص غيره، أو قد كتبه هو بنفسه لكن منذ مدة طويلة فنسي سبب اختياره لخاصية أو دالة بعينها. وسيشعر المبرمج بأهمية التعليقات حسنة الوصف مع الوقت، وقد أضفنا تعليقات إلى بعض الشيفرات التي استخدمناها في شرح هذه السلسلة إلى الآن، فهي تلك الأسطر المسبوقة بعلامة # في بايثون، أو بعلامة ' في VBScript، وسنبدأ تدريجيًا من الآن بكتابة شرح الشيفرة في التعليقات، إلى أن يقل ما نكتبه من الشرح خارج الشيفرة ثم يختفي. لكل لغة طريقة في ترميز التعليقات، ففي VBScript مثلًا تكون REM مثل اختصار إلى كلمة Remark أو ملاحظة، لكن يشيع استخدام العلامة ' لتؤدي نفس الوظيفة بحيث يتجاهل البرنامج أي شيء مكتوب بعدها. REM لن يُعرض هذا السطر ' ولا هذا msgBox "أما هذا السطر فسيُعرض" لاحظ أن استخدام علامة اقتباس مفردةً ' مثل محدد للتعليقات في VBScript هو سبب منع بدء السلسلة النصية بها، لئلا تظن اللغة أنها تعليق، أما بايثون فتستخدم رمز # مثل حدد للتعليقات فيها، وتتجاهل أي شيء يتبعه: v = 12 # القيمة 12 v أعط x = v*v # v تساوي مربع x غير أن هذا الأسلوب في التعليقات سيء للغاية، إذ لا يجب أن تصف التعليقات ما تفعله الشيفرة فحسب، فنحن نستطيع رؤية ذلك بأنفسنا، لكنها يجب أن تصف سبب اختيار المبرمج لهذه الدالة أو تلك القيمة: v = 3600 # 3600 عدد الثواني في الساعة الواحدة s = t*3600 # تحتوي الوقت المار بالساعة t # لذا نحولها إلى ثوانٍ. هذه النسخة من التعليقات أكثر فائدةً إذ تشرح سبب ضرب t في 3600. تستخدم جافاسكربت شرطتين مائلتين // مثل محدد للتعليقات، ثم تتجاهل أي شيء بعدهما، كما تسمح بعض اللغات بتعليقات متعددة الأسطر بين زوجين من الرموز، لكن هذا قد يؤدي إلى بعض الأخطاء الخفية إذا لم يوضع رمز الإغلاق، وتسمح جافاسكربت بهذا النوع من التعليقات باستخدام الرمز /* متبوعًا برمز الإغلاق */ بعد نهاية التعليقات: <script type="text/javascript"> document.write("هذا السطر يُطبع\n"); // تعليق من سطر واحد /* هنا تعليق نقسمه على عدة أسطر فيحتوي على هذا السطر وهذا السطر وذا أيضًا ولن يظهر أي من هذا في خرج السكربت فإذا أردنا إنهاء التعليق نعكس رمز البدء ليكون كما يلي: */ document.write("وهذا أيضًا"); </script> تبرز أهمية التعليقات كما ذكرنا في أنها تشرح الشيفرة لأي شخص يحاول قراءتها، حيث يجب الحرص على توضيح الأقسام الغامضة مثل القيم العشوائية المستخدمة، أو المعادلات الحسابية المعقدة. تذكر أن ذلك القارئ المحتار في فهم شيفرتك قد يكون أنت نفسك بعد بضعة أسابيع أو أشهر. التسلسلات باستخدام المتغيرات لقد شرحنا مفهوم المتغيرات في مقال مدخل إلى البيانات وأنواعها: أنواع البيانات الأساسية، وقلنا إنها عناوين نعلّم بها بياناتنا من أجل الإشارة إليها في المستقبل، ورأينا بعض الأمثلة عن استخدام المتغيرات في عدة أمثلة لقوائم ودفاتر عناوين، غير أن المتغيرات بالغة الأهمية في البرمجة إلى الحد الذي يجعلنا نعيد مراجعة كيفية استخدامها مرةً أخرى قبل أن ننتقل إلى جزء جديد. اكتب ما يلي في محث بايثون، سواءً في صدفة IDLE أو في نافذة أوامر دوس أو يونكس: >>> v = 7 >>> w = 18 >>> x = v + w # استخدم متغيرنا في عملية حسابية >>> print( x ) ما حدث في الشيفرة أعلاه هو أننا أنشأنا المتغيرات v وw وx وعدّلناها، وهذا أشبه بزرّ M على حاسبة الجيب القديمة التي تخزن نتيجةً لاستخدامها لاحقًا، يمكن تحسين تلك الشيفرة باستخدام سلسلة تنسيق لطباعة النتيجة: >>> print( "The sum of %d and %d is: %d" % (v,w,x) ) إحدى مزايا سلاسل التنسيق هنا أننا نستطيع تخزينها في متغيرات أيضًا: >>> s = "The sum of %d and %d is: %d" >>> print( s % (v,w,x) ) # هذا مفيد عند طباعة نفس الخرج بقيم مختلفة هذا يقصّر كثيرًا من طول تعليمة الطباعة، خاصةً حين تحتوي على قيم كثيرة، لكنه يجعلها أكثر غموضًا، وعندها تقرر بنفسك أيهما الأفضل من حيث القراءة: الأسطر الطويلة أم القصير؟ فإذا أبقينا سلسلة التنسيق هنا إلى جانب تعليمة الطباعة كما فعلنا فهذا حسن. يفضل تسمية المتغير بطريقة تشرح الغرض من وجوده، فبدلًا من تسمية سلسلة التنسيق باسم s، يفضل تسميتها sumFormat فتبدو الشيفرة كما يلي: >>> sumFormat = "The sum of %d and %d is: %d" >>> print( sumFormat % (v,w,x) ) # هذا مفيد عند طباعة نفس الخرج بقيم مختلفة يمكن معرفة أي تنسيق تمت طباعته بمجرد النظر إليه في هذا البرنامج لأنه لا يحتوي على سلاسل تنسيق كثيرة، لكن لا تزال فكرة التسمية المنطقية للمتغيرات ساريةً هنا، وسنحاول قدر الإمكان استخدام أسماء ذات معنى في ما يلي من الشرح؛ أما المتغيرات التي ذكرناها إلى الآن فلم يكن لها معنىً يستحق التسمية. أهمية الترتيب قد يظن المرء أن بنية التسلسل تلك مبالغ فيها لبداهتها، ولعل هذا صحيح بما أنها بديهية فعلًا، لكن الأمر ليس بتلك البساطة التي يبدو عليها، فقد تكون هناك مشاكل خفية كما في حالة الرغبة في ترقية جميع الترويسات في ملف HTML مثلًا، بمقدار رتبة واحدة، انظر المثال التالي، حيث تُميَّز الترويسات في HTML بإحاطة النص بوسم يشير إلى أنها ترويسة مع رتبتها: <h1> نص </h1> لترويسة المستوى الأول <h2> نص </h2> لترويسة المستوى الثاني <h3> نص </h3> لترويسة المستوى الثالث والمشكلة هنا أننا حين نصل إلى المستوى الخامس يصير نص الترويسة أصغر من نص المتن العادي نفسه، مما يبدو غريبًا على القارئ إذ يرى نص العنوان أصغر من متنه، وعلى ذلك نريد ترقية جميع الترويسات دفعةً واحدةً، يسهُل هذا بعملية بحث واستبدال في محرر نصي بسيط بأن نستبدل h2 بـ h1 مثلًا، لكن ماذا لو بدأنا بالأرقام الأكبر، مثل h4 إلى h3، ثم h3 إلى h2 وهكذا؛ سنجد في النهاية أن جميع الترويسات صارت من المستوى الأول h1، وهنا تبرز أهمية ترتيب الأحداث والإجراءات، وذلك ينطبق في حالة كتابتنا لبرنامج ينفذ عملية الاستبدال، وهو ما سنفعله على الأغلب بما أن ترقية الترويسات عملية واردة الحدوث، وقد رأينا أمثلةً أخرى نستخدم فيها المتغيرات والتسلسلات في مقالي مدخل إلى البيانات وأنواعها: أنواع البيانات الأساسية ومدخل إلى البيانات وأنواعها: التجميعات Collections، خاصةً أمثلة دفتر العناوين. جرب التفكير في أمثلة مشابهة لحلها، وإذا أتممت هذا فسننتقل إلى دراسة حالة جديدة نطورها بالتدريج كلما تقدمنا في هذه السلسلة، لنحسنها مع كل تقنية نتعلمها. جدول الضرب سنشرح الآن تدريبًا برمجيًا نطوره معنا أثناء دراسة المقالات التالية، وستتطور حلوله تدريجيًا مع تعلم تقنيات جديدة، ذكرنا أننا نستطيع كتابة سلاسل نصية طويلة بتغليفها بعلامات اقتباس ثلاثية، لنستخدم هذا الأسلوب لبناء جدول ضرب: >>> s = """ 1 x 12 = %d 2 x 12 = %d 3 x 12 = %d 4 x 12 = %d """ # احذر وضع تعليقات في السلاسل النصية >>> # إذ ستكون جزءًا من السلسلة نفسها >>> print( s % (12, 2*12, 3*12, 4*12) ) إذا وسعنا الشيفرة السابقة فسنتمكن من طباعة جدول ضرب العدد 12 كاملًا من 1 إلى 12، لكن هل من طريقة أفضل؟ بالتأكيد، وهي ما سنراها في الجزئية الموالية من هذه السلسلة. خاتمة عرفنا في هذا المقال أن IDLE هي بيئة تطوير خاصة بكتابة برامج بايثون وتطويرها، وأن التعليقات تسهل قراءة البرامج وفهمها، ولا تأثير لها على سير العمليات في البرنامج، وأن المتغيرات تستطيع تخزين نتائج بينية من أجل استخدامها لاحقًا. ترجمة -بتصرف- للفصل السادس: More Sequences and Other Things من كتاب Learning To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: الحلقات التكرارية في البرمجة المقال السابق: مدخل إلى البيانات وأنواعها: التجميعات Collections تعلم البرمجة كيف تتعلم البرمجة كيف تتعلّم البرمجة: نصائح وأدوات لرحلتك في عالم البرمجة1 نقطة
-
رأينا في التدريب الأخير من المقال السابق كيف طبعنا جزءًا من جدول ضرب العدد 12، لكن ذلك تطلب منا كثيرًا من الكتابة، وسيستغرق توسيعه وقتًا طويلًا، ولحسن الحظ توجد طريقة أسهل سترينا بداية المزايا القوية التي توفرها لنا لغات البرمجة في تنفيذ المهام وإنجازها. حلقات for تتيح لغة البرمجة تكرار تنفيذ أمر أو عدة أوامر لعدد محدَّد من المرات، في ما يسمى حلقة تكرار، حيث يمكن استعمال متغير تزيد قيمته مع كل دورة للحلقة، وستبدو هذه العملية في بايثون كما يلي: >>> for n in range(1,13): ... print( "%d x 12 = %d" % (n, n*12) ) ... 1 x 12 = 12 2 x 12 = 24 3 x 12 = 36 4 x 12 = 48 5 x 12 = 60 6 x 12 = 72 7 x 12 = 84 8 x 12 = 96 9 x 12 = 108 10 x 12 = 120 11 x 12 = 132 12 x 12 = 144 لندرس الشيفرة السابقة ونستخرج بعض الملاحظات منها: انتهى سطر for بنقطتين رأسيتين (:)، وهذا أمر مهم، إذ يخبر بايثون أن ما سيكتَب بعد هاتين النقطتين هو ما سيُكرَّر. كتبنا مجال الأعداد الذي نريده في دالة range() بالشكل range(1,13)، رغم أننا نريد تكرار عملية الضرب إلى العدد 12 فقط، لأن دالة range() تولد الأعداد من العدد الأول فيها إلى العدد الذي يسبق العدد الثاني، 13 في مثالنا، وهذا له أسبابه قطعًا وستعتاده مع الوقت، لكن تجدر الإشارة إلى أن هذه الدالة تستطيع توليد مجموعات معقدة من الأعداد، لكننا اخترنا هذا المثال البسيط لأنه يحقق الغرض. العامل for في بايثون هو عامل foreach في الواقع، إذ يطبق تسلسل الشيفرة التالي على كل عنصر في التجميعة، والتي هي في حالتنا قائمة الأعداد التي تولدها الدالة range()، ونستطيع استخدام قائمة أعداد صراحةً عوضًا عن الدالة range()، بالشكل التالي: >>> for n in [1,2,3,4,5,6,7,8,9,10,11,12]: ... print( "%d x 12 = %d" % (n, n*12) ) أُزيح سطر print موازنةً بسطر حلقة for الذي فوقه، وهذا مهم جدًا لأن هذه الإزاحة تخبر بايثون أن عليها تكرار القسم الخاص بـ print، ومن الممكن إزاحة أكثر من سطر، وستكرر بايثون هذه الأسطر المزاحة جميعًا لكل عنصر في التجميعة، ولا يهم مقدار الإزاحة المستخدمة طالما هي نفسها في كل الأسطر المزاحة، وستخبرنا بايثون إذا وجدت اختلافًا في الإزاحة. نحتاج إلى ضغط زر الإدخال Enter مرتين في المفسر التفاعلي لتشغيل البرنامج، لأن مفسر بايثون يضيف سطرًا جديدًا إلى شيفرة الحلقة التكرارية عندما نضغط مرةً واحدةً؛ أما مع الضغطة الثانية فستفترض بايثون أننا أنهينا إدخال الشيفرة، فتشغّل البرنامج. وبما أننا قد رأينا الآن هيكل حلقة for، لننظر في كيفية عملها خطوةً خطوةً على النحو الآتي: أولًا: تستخدم بايثون دالة range() لتوليد قائمة أعداد من 1 إلى 12، وفقًا لآلية خاصة تسمى بالمولد generator، وتشبه القائمة التي تزيد من عناصرها عنصرًا واحدًا في كل مرة حسب الطلب، مما يوفر الذاكرة عندما تكون القائمة كبيرةً، وهو نفس سبب توليد القائمة صراحةً باستخدام list() عندما طبعنا range() أعلاه، وهذا شبيه بما فعلناه في مثال مفاتيح القاموس keys() في المقال الخامس من هذه السلسلة والمتعلق بالمواد الخام للبرمجة. ثانيًا: تجعل بايثون قيمة n مساويةً للقيمة الأولى في القائمة، وهي 1 في هذه الحالة، ثم تنفذ الشيفرة المزاحة باستخدام القيمة n = 1: print( "%d x 12 = %d" % (1, 1*12) ) ثم تعود إلى سطر for وتضبط n على القيمة التالية في القائمة، وهي 2 في هذه الحالة، ثم تنفذ الشيفرة المزاحة مع القيمة n = 2: print( "%d x 12 = %d" % (2, 2*12) ) وتستمر في تكرار هذا التسلسل حتى تمر n على جميع القيم في القائمة، ثم تنتقل إلى الأمر التالي غير المزاح، في حالتنا لا توجد أي أوامر، لذا سيتوقف البرنامج. الحلقة التكرارية في VBScript تُعَد For...Next أبسط حلقة تكرارية في VBScript، وتُستخدم بالشكل التالي: <script type="text/vbscript"> For N = 1 To 12 MsgBox N & " x 12 = " & N*12 Next </script> يُعَد أسلوب VBScript أوضح وأسهل في فهم ما تفعله الشيفرة، إذ تتغير قيمة N من 1 إلى 12، وتنفَّذ الشيفرة التي توجد قبل الكلمة المفتاحية Next، وفي حالتنا تطبع الشيفرة النتيجة في صندوق حواري؛ أما إزاحة السطر هنا فاختيارية وليست شرطًا، لكنها تجعل الشيفرة أسهل في القراءة، وقد يحتوي متن الحلقة التكرارية على أكثر من سطر ينفَّذ على عناصر القائمة، كما في حالة بايثون التي رأيناها قبل قليل، ورغم أن VBScript تبدو أوضح للوهلة الأولى؛ إلا أن بايثون أكثر مرونةً كما سنرى بعد قليل. الحلقة التكرارية في جافاسكربت تستخدم جافاسكربت البُنية for الشائعة في كثير من لغات البرمجة الشبيهة بلغة C، وستبدو الحلقة كما يلي: <script type="text/javascript"> for (n=1; n <= 12; n++){ document.write(n + " x 12 = " + n*12 + "<BR>"); }; </Script> تبدو هذه الشيفرة معقدةً للوهلة الأولى، وهي تتكون من ثلاثة أجزاء بين القوسين () هي: جزء البداية: n = 1 الذي يُنفَّذ مرةً واحدةً قبل أي شيء آخر. جزء الاختبار: n <= 12 الذي يُنفَّذ قبل كل تكرار. جزء الزيادة: n++ وهو اختصار "زِد n بمقدار 1"، وينفَّذ بعد كل تكرار. لاحظ أن جافاسكربت تضع الشيفرة المكرَّرة، أي متن الحلقة التكرارية، بين قوسين معقوصين {}، وهذا كافٍ لتكون الحلقة صالحةً للتنفيذ، إلا أنه يفضَّل إزاحة الشيفرة التي داخل الأقواس المعقوصة لتحسين قابلية قراءة الشيفرة. لن ينفَّذ متن الحلقة loop body إلا إذا تحقق جزء الاختبار، أي كان true. وقد تحتوي هذه الأجزاء على شيفرات عشوائية، إلا أن الجزء الثاني الخاص بالاختبار يجب أن يعطي قيمةً بوليانيةً. مزيد من المعلومات حول حلقة for في بايثون تتكرّر حلقة for في بايثون على تسلسل، تذكر أن التسلسل الذي شرحناه في المقالات السابقة يشمل أشياء، مثل السلاسل النصية والقوائم والصفوف tuples، كما تستطيع بايثون أن تكرِّر عدة أنواع أخرى لكننا سنؤجل ذلك إلى وقت لاحق، وبناءً على ذلك نستطيع كتابة حلقات for تتعامل مع أي نوع من التسلسلات، ولنجرب مثلًا طباعة حروف كلمة حرفًا حرفًا باستخدام حلقة for مع سلسلة نصية: >>> for c in 'word': print( c ) ... w o r d لاحظ أننا طبعنا كل حرف على سطر منفصل، وأنه يمكننا إضافة متن الحلقة، عندما يكون سطرًا واحدًا، إلى نفس سطر الحلقة بوضعه بعد نقطتين رأسيتين :، إذ تخبران بايثون بوجود كتلة برمجية تليهما. ويمكن التكرار على صف tuple: >>> for word in ('one','word', 'after', 'another'): print (word) ... جعلنا في هذا المثال كل كلمة في سطر منفصل على خلاف المثال السابق، ويمكن وضعها جميعًا في سطر واحد باستخدام ميزة خاصة بدالة print()، إذ نستطيع إضافة وسيط argument بعد العنصر المراد طباعته كما يلي: >>> for word in ('one', 'word', 'after', 'another'): print( word, end='' ) ... لاحظ كيف ستظهر الكلمات الآن في سطر واحد، لأن الوسيط end='' يخبر بايثون أن تستخدم سلسلةً نصيةً فارغةً '' لنهاية السطر عوضًا عن محرف السطر الجديد الذي تستخدمه افتراضيًا، لنجرب حلقة for مرةً أخرى مع القوائم: >>> for item in ['one', 2, 'three']: print( item ) ... ستظهر هنا مشكلة عند استخدام الحلقات التكرارية التي على نمط foreach، وهي أن الحلقة تعطينا نسخةً مما كان في التجميعة، دون أن نستطيع تعديل محتوياتها مباشرةً، فإذا احتجنا إلى تعديلها؛ فعلينا استخدام برنامج غريب الشكل نستخدم فيه فهرس التجميعة، كما يلي: myList = [1,2,3,4] for index in range(len(myList)): print( myList[index] ) myList[index] += 1 print( myList ) سيزيد هذا البرنامج كل فهرس في myList، ولو أننا لم نستخدم طريقة الفهرس تلك، لكنا زدنا العناصر المنسوخة فقط دون تغيير القائمة الأصلية، وقد صار لدينا متن متعدد الأسطر في حلقتنا التكرارية. myList = [1,2,3,4] for index, value in enumerate(myList): print( value ) myList[index] += 1 print( myList ) لاحظ أننا لم نستخدم محث بايثون التفاعلي >>> في هذا المثال، لذا عليك كتابته في ملف كما شرحنا في مقال المزيد من التسلسلات البرمجية وأمور أخرى؛ أما إذا حاولنا كتابته في محث بايثون، فسنحتاج إلى أسطر فارغة إضافية لنخبر بايثون بانتهاء كتلة برمجية، وذلك بعد السطر myList[index] += 1 مثلًا، وهذه الطريقة مفيدة لتعلّم بداية الكتل البرمجية ونهايتها، بكتابة الشيفرة وتخمين أماكن الحاجة إلى السطر الإضافي، إذ يجب أن يكون عند الموضع الذي تتغير فيه الإزاحة. لا بد من ملاحظة أمر آخر في حلقات foreach، وهو أننا لا نستطيع حذف العناصر من التجميعة التي نمر عليها، لأن ذلك يربك الحلقة نفسها، فهو يشبه قطع فرع من شجرة أثناء جلوسك عليه، والحل هو استخدام نوع مختلف من الحلقات التكرارية، كما سنرى في جزئية لاحقة من هذه السلسلة. ربما تجب الإشارة إلى أن كلًا من جافاسكربت وVBScript لديهما بنىً للتكرار على العناصر الموجودة في تجميعة ما، ولن نتحدث عنها بتفصيل هنا، لكن إذا أردت أن تبحث في الأمر بنفسك فانظر صفحات المساعدة لبنية for each...in... في لغة VBScript، وبنية for...in... في جافاسكربت. حلقات While التكرارية تتطلب حلقات for أن يعلم المبرمج عدد مرات التكرار التي يريد تنفيذها قبل بدء الحلقة نفسها، أو أن يستطيع حسابها على الأقل، لكن ماذا لو أردنا تنفيذ مهمة ما حتى وقوع حدث معين لا نعرف موعده؟ فقد نرغب في قراءة بيانات من المستخدم ومعالجتها مثلًا إلى أن يخبرنا المستخدم نفسه بالتوقف عن ذلك، كما لن نعرف عدد عناصر البيانات التي سنعالجها إلى أن يكتفي المستخدم ويخبرنا بذلك أيضًا. يُعَد تنفيذ مثل هذه المهام باستخدام حلقة for ممكنًا نظريًا لكنه معقد، لهذا لدينا نوع آخر من الحلقات التي تحل مثل هذه المشاكل، وهي حلقة while، وستبدو في بايثون بالشكل التالي: >>> j = 1 >>> while j <= 12: ... print( "%d x 12 = %d" % (j, j*12) ) ... j = j + 1 لنحلل هذه الشيفرة: نهيئ أولًا j لتأخذ القيمة 1، وهذه الخطوة مهمة للغاية، أي تهيئة متغير التحكم في حلقة while، لأن نسيان تهيئته يتسبب في أخطاء كثيرة. ننفذ تعليمة while نفسها، التي تختبر تعبيرًا بوليانيًا هو j<=12 في حالتنا. ننفذ الكتلة المزاحة التي تتبعها إذا كانت النتيجة True، وهو محقق في حالتنا بما أن قيمة j أقل من 12، لذا سننتقل إلى الكتلة. ننفذ تعليمة الطباعة لإخراج أول سطر من جدولنا. يزيد السطر التالي في الكتلة متغير التحكم j، وهو السطر الأخير في حالتنا، ليشير إلى نهاية كتلة while. نعود إلى تعليمة while ونكرر الخطوات من 4 إلى 6 بقيمة j الجديدة. نكرر هذا التسلسل إلى أن تصل قيمة j إلى 13. هنا يعيد اختبار while القيمة False، فنتخطى الكتلة المزاحة إلى السطر الجديد الذي يوازي تعليمة while في إزاحتها. يتوقف البرنامج في مثالنا لأنه لا توجد أسطر أخرى. تعليمة while واضحة وبسيطة كما رأينا، لكننا نريد الإشارة إلى النقطتين الرأسيتين (:) اللتين في نهاية سطر تعليمة while -وتعليمة for أيضًا-، إذ تخبر هاتان النقطتان بايثون أن ما يليهما كتلة برمجية أو مجموعة مترابطة من التعليمات، وكل لغة لها طريقتها في إخبار المفسر بجمع عدة أسطر معًا كما سنرى، ففي حالة بايثون مثلًا، سنستخدم النقطتين الرأسيتين وإزاحة الأسطر. حلقة While في VBScript فيما يلي حلقة while في لغة VBScript: <script type="text/vbscript"> DIM J J = 1 Do While J <= 12 MsgBox J & " x 12 = " & J*12 J = J + 1 Loop </script> يعطينا هذا المثال نفس النتيجة التي حصلنا عليها من مثال بايثون السابق، مع ملاحظة انتهاء كتلة الحلقة التكرارية بالكلمة المفتاحية Loop حلقة While في جافاسكربت <script type="text/javascript"> j = 1; while (j <= 12){ document.write(j + " x 12 = "+ j*12 + "<BR>"); j++; } </script> تتشابه هذه البنية مع ما سبق، لكن مع بعض الأقواس المعقوصة بدلًا من كلمة Loop التي في VBScript، لاحظ أن ++J تعني زيادة قيمة j بمقدار 1، كما ذكرنا في مقال سابق، وأن جافاسكربت وVBScript لا تشترطان إزاحة الأسطر، على عكس لغة بايثون، لكننا أزحنا الأسطر لتسهيل قراءة الشيفرة فقط. لنراجع الآن حلقة for في جافاسكربت: for (j=1; j<=12; j++){....} نلاحظ أنها تشبه حلقة while تمامًا، لكنها مكتوبة في سطر واحد بحيث يمكن رؤية المهيئ initializer وشرط الاختبار ومعدِّل الحلقة معًا، وبهذا يتبين أن حلقة for في جافاسكربت ما هي إلا حلقة while ولكن بصورة مضغوطة، وسنستنتج أن بعض اللغات قد تستغني عن حلقة for نهائيًا، وهو ما يحدث حقًا. حلقات تكرارية مرنة إذا عدنا إلى مثال جدول ضرب العدد 12 الذي ذكرناه في بداية هذا المقال، فسنجد أن الحلقة التي أنشأناها ستطبع جدول هذا العدد بكفاءة، لكن هل يمكننا تعديل الحلقة لجعلها تطبع جدول العدد 7 مثلًا؟ ينبغي أن تبدو الحلقة كما يلي: >>> for j in range(1,13): ... print( "%d x 7 = %d" % (j,j*7) ) وهذا يعني أن علينا تغيير 12 إلى 7 مرتين، وإذا أردنا قيمةً أخرى غيرهما فسنغير في موضعين من جديد، ولكن ألا توجد طريقة أفضل لإدخال مضاعف الضرب ذاك؟، يمكن ذلك باستخدام متغير آخر للقيم التي في سلسلة الطباعة، ثم ضبط ذلك المتغير قبل تشغيل الحلقة التكرارية: >>> multiplier = 12 >>> for j in range(1,13): ... print( "%d x %d = %d" % (j, multiplier, j*multiplier) ) وهذا جدول العدد 12 السابق، وإذا أردنا تغييره إلى العدد 7 مثلًا، فلا نغير إلا قيمة multiplier، جرب كتابة هذا البرنامج في ملف سكربت بايثون وتشغيله من محث سطر الأوامر، ثم عدِّل قيمة المضاعف multiplier إلى أعداد أخرى، لاحظ أننا جمعنا هنا بين التسلسل والحلقات التكرارية، فقد كتبنا أمرًا وحيدًا في البداية هو multiplier = 12، متبوعًا بحلقة for. تكرار الحلقة نفسها لنطور مثالنا السابق قليلًا، ولنفترض أننا نريد طباعة جميع جداول الضرب للأعداد من 2 حتى 12، سيكون كل ما نحتاجه هو ضبط متغير المضاعف ليكون جزءًا من الحلقة التكرارية، ونفعل بذلك بالشكل التالي: >>> for multiplier in range(2,13): ... for j in range(1,13): ... print( "%d x %d = %d" % (j,multiplier,j*multiplier) ) لاحظ أن الجزء المزاح داخل حلقة for الأولى هو نفس الحلقة التي بدأنا بها، وستنفَّذ الحلقة كما يلي: نضبط multiplier أولًا على القيمة الأولى 2 ثم ننتقل إلى الحلقة الثانية الداخلية. نعيد ضبط multiplier على القيمة التالية 3 ثم ننتقل إلى الحلقة الداخلية مرةً أخرى. نكرر هذا حتى نمر على جميع الأعداد. يُعرف هذا الأسلوب باسم الحلقات المتشعبة nesting loops، لكن من مساوئه أن جميع الجداول ستكون مدمجةً معًا، ونستطيع إصلاح هذه المشكلة بطباعة سطر فاصل في نهاية الحلقة الأولى، كما يلي: >>> for multiplier in range(2,13): ... for j in range(1,13): ... print( "%d x %d = %d" % (j,multiplier,j*multiplier) ) ... print( "------------------- " ) لاحظ أن تعليمة الطباعة الثانية لها نفس إزاحة تعليمة for الثانية، وهي ثاني تعليمة في تسلسل التكرار، فتسلسل الإزاحة مهم جدًا في بايثون كما ذكرنا. دعنا نرى الآن كيفية تنفيذ هذا التدريب في جافاسكربت، لرؤية الفرق بينهما فقط: <script type="text/javascript"> for (multiplier=2; multiplier < 13; multiplier++){ for (j=1; j <= 12 ; j++){ document.write(j, " x ", multiplier, " = ", j*multiplier, "<BR>"); } document.write("---------------<BR>"); } </script> حاول أن تجعل السطر الفاصل يشير إلى الجدول التابع له، يمكنك استخدام متغير المضاعف وسلسلة التنسيق التي في بايثون لفعل ذلك. حلقات أخرى توفر بعض اللغات الأخرى بنىً مختلفةً للتكرار، كما رأينا في مثال VBScript أعلاه، غير أنها لا تخلو من صورة ما لحلقتي for وwhile، ولا تحوي بعض اللغات، مثل Modula 2 وOberon، إلا حلقة while فقط، بما أننا نستطيع تمثيل سلوك for منها كما رأينا قبل قليل. ومن الحلقات التكرارية الموجودة في اللغات الأخرى: do-while: هذه الحلقة هي نفسها حلقة while لكن مع وجود الاختبار في نهايتها، بحيث تُنفَّذ الحلقة مرةً واحدةً على الأقل. repeat-until: شبيهة بالسابقة أيضًا لكن مع عكس المنطق. GOTO وJUMP وLOOP: هذه الحلقات التكرارية موجودة في اللغات القديمة، وهي تعين علامةً في الشيفرة ثم تقفز إليها مباشرةً. خاتمة لقد رأينا أن حلقات for تكرر مجموعةً من الأوامر لعدد محدد وثابت من المرات، وأن while تكرر تلك الأوامر إلى أن يتحقق شرط محدد في الحلقة، ولا تنفذ متن الحلقة أصلًا إذا كان شرط إنهاء الحلقة غير متحقق من البداية، أي أعطى اختباره النتيجة false، وعلمنا أنه توجد أنواع أخرى من الحلقات التكرارية؛ لكن اللغة التي تحتوي عليها، ستحتوي على حلقتي for وwhile أو إحداهما على الأقل، وأن حلقات for في بايثون ما هي إلا حلقات foreach حقيقةً، إذ تعمل على قائمة من العناصر، كما تعلمنا الحلقات التكرارية المتشعبة، بإدخال حلقة فرعية داخل أخرى أكبر منها. ترجمة -بتصرف- للفصل السابع: Looping - Or the art of repeating oneself من كتاب Learning To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: أسلوب كتابة الشيفرات البرمجية وتحقيق سهولة قراءتها المقال السابق: بعض التسلسلات النصية المهمة لتعلم البرمجة ما هي البرمجة ومتطلبات تعلمها؟ الحلقات التكرارية Loops في Cpp بنى التحكم والحلقات التكرارية في PHP الحلقات التكرارية في لغة سي شارب #C حلقات for التكرارية ببساطة في جافاسكريبت1 نقطة
-
يتكون أبسط برنامج يمكن كتابته من سلسلة من بعض التعليمات statements المتتالية، وأصغرها هو الذي يحتوي تعليمةً برمجيةً واحدةً، حيث تُدخَل التعليمة عادةً في سطر واحد، كما يمكن أن تُقسم على عدة أسطر، وتعرَّف التعليمة بأنها مجموعة من الكلمات والرموز المكتوبة بلغة طبيعية، وسننظر الآن في بعضها، إذ تُظهر الأمثلة التالية ما يجب أن نكتبه في محث بايثون >>>، كما تُظهر النتيجة، ثم نشرح ما حدث. عرض الخرج يجب أن نتعلم أولًا كيف نجعل بايثون تعرض المعلومات التي نريدها، فإذا لم تعرض لنا اللغة شيئًا، فكيف نعرف ما فعله الحاسوب؟ وما فائدة الجهد الذي نبذله في البرمجة حينها إذا كنا لا نعرف هل أصبنا أم أخطأنا؟ >>> print('Hello there!') Hello there! انتبه إلى الملاحظة الأولى في المثال أعلاه، وهي أن المسافة التي بين المحث وبين أمر print ليست ضرورية، إذ ستضعها بايثون تلقائيًا إذا نسيناها، وما سنكتبه هو السطر الأول فقط؛ أما السطر الثاني فهو نتيجة البرنامج الذي كتبناه في السطر الأول، وقد عرضه لنا المفسر. أما الملاحظة الثانية فهي أن بايثون حساسة لحالة الأحرف، حيث سنحصل على خطأ إذا كتبنا Print بدلًا من print لأن بايثون تراهما كلمتين مختلفتين، وكذلك الحال بالنسبة لجافاسكربت؛ أما لغة VBScript فلا تهتم لهذا، لكن يجب تعويد النفس على الاهتمام بحالة الأحرف كعادة برمجية حسنة لئلا تقع في أخطاء بسببها إذا انتقلت من لغة برمجية لأخرى. وقد عرض لنا المفسر النص المكتوب بين علامتي الاقتباس لأن الدالة print() تخبر بايثون بعرض تسلسل المحارف H,e,l,l,o, ,t,h,e,r,e,!، وهو ما يُعرَف في الأوساط البرمجية باسم السلسلة النصية string، أو سلسلة المحارف النصية، حيث يجب أن تكون تلك المحارف داخل أقواس، وندل على السلسلة النصية بوضعها بين علامات الاقتباس، كما يمكن استخدام علامات الاقتباس المفردة أو المزدوجة في بايثون دون حرج، مما يسمح لنا بإدخال أحد نوعي الاقتباس في سلسلة نصية محاطة بالنوع الآخر، وهذا مفيد في حالة الفاصلة الإنجليزية العليا ': >>> print("Monty Python's Flying Circus has a ' within it...") Monty Python's Flying Circus has a ' within it... أما جافاسكربت وVBScript فحساستان لنوع علامات التنصيص التي يجب استخدامها، لهذا يُنصح فيهما بالالتزام بالعلامات المزدوجة ما أمكن. عرض النتائج الحسابية >>> print(6 + 5) 11 يطبع لنا المثال أعلاه نتيجة العملية الحسابية التي في السطر الأول، والتي جمعنا فيها 5 إلى 6، وقد عرفت بايثون أن هذه المحارف أرقام وعاملتها على هذا الأساس، كما تعرفت على علامة الجمع التي بينهما، فجمعت العددين وأخرجت لنا الناتج، لذا يمكن القول أن بايثون مفيدة كحاسبة للجيب، وهو أحد استخداماتها الكثيرة جدًا، جرب الآن بعض الحسابات الأخرى واستخدم العوامل الحسابية التالية: الطرح (-). الضرب (*). القسمة (/). يمكن دمج عدة تعبيرات حسابية كما يلي: >>> print( ((6 * 5) + (7 - 5)) / (7 + 1) ) 4.0 لاحظ الطريقة التي استخدمنا بها الأقواس لوضع الأعداد في مجموعات، لقد رأت بايثون تلك العملية السابقة كما يلي: ((6 * 5) + (7 - 5)) / (7 + 1) => (30 + 2) / 8 => 32 / 8 => 4 فماذا يحدث لو كتبنا نفس العمليات دون الأقواس؟ >>> print(6 * 5 + 7 - 5 / 7 + 1) 37.2857142857 حصلنا على هذه النتيجة لأن بايثون تنفذ عمليتي الضرب والقسمة قبل الجمع والطرح، لذا رأتها على النحو التالي: (6*5) + 7 - (5/7) + 1 => 30 + 7 - 0.7143 + 1 => 37 - 0.7143 + 1 => 38 - 0.7143 => 37.2857... ومع أن ترتيب بايثون لمعالجة العمليات الحسابية هو نفسه الذي تقضيه قوانين الرياضيات، إلا أنه يختلف عما يجب عليك توقعه كونك مبرمجًا، لأن بعض لغات البرمجة لها قوانينها في ترتيب معالجة العمليات الحسابية، وهو ما يعرف بأسبقية العوامل operator precedence، لذا تأكد من النظر أولًا في توثيق لغة البرمجة التي تتعامل معها لترى أسلوبها الخاص؛ أما بايثون فقاعدتها العامة هي ما يقتضيه الحدس والمنطق، لكن هذا له استثناءاته، مما يجعل استخدام الأقواس خيارًا آمنًا لضمان حصولنا على النتيجة التي نريدها، خاصةً عند التعامل مع حسابات طويلة مثل التي رأيناها في المثال السابق، ومن الأمور التي يجب ملاحظتها أننا إذا استخدمنا عامل القسمة / فسنحصل على النتيجة الدقيقة للعملية، كما يلي: >>> print(5/2) 2.5 فإذا أردنا الحفاظ على القسم الصحيح للناتج فقط فنستخدم عامليْ قسمة متتاليين // لنحصل على العدد الكامل في النتيجة، وستطبع بايثون ناتج القسمة كما يلي: >>> print(5//2) 2 أما إذا أردنا الحصول على باقي عملية القسمة فنستخدم محرف النسبة المئوية %: >>> print(5%2) 1 >>> print(7//4) 1 >>> print(7%4) 3 يُعرَف العامل % باسم عامل الباقي modulo، وقد يكون في بعض لغات البرمجة على الصورة MOD أو نحوها، أما في بايثون فنستطيع الحصول على ناتج القسمة والباقي معًا باستخدام الدالة divmod(): >>> print( divmod(7,4) ) (1, 3) هذه العمليات الحسابية للأعداد الصحيحة مهمة للغاية في البرمجة، فمنها نستطيع تحديد كون العدد زوجيًا أم فرديًا من خلال قسمته على 2 ورؤية الباقي (يكون زوجيًا إذا كان الباقي صفرًا)، كما يلي: >>> print( 47 % 2 ) 1 فنحن نعلم الآن أن العدد 47 هو عدد فردي، وقد يكون هذا أمرًا بدهيًا إذ يمكن معرفة هذا دون تكبد عناء لغة برمجية وانتظار خرج عملية فيها، لكن ماذا لو كنا نقرأ بيانات من ملف، أو كان المستخدم يدخل تلك البيانات، ثم يكون على برنامجنا معرفة هل العدد فردي أم زوجي من تلقاء نفسه، عندئذ لن نستطيع التدخل هنا لتقرير ذلك بالنظر في كل عدد، بل سنستخدم عامل الباقي كما فعلنا ليتحقق من المطلوب بدلًا منا، وتلك حالة واحدة فقط من الحالات التي تبرز فيها أهمية هذه العمليات، لذا تدرب عليها إلى أن تتقنها. دمج السلاسل النصية والأعداد >>> print( 'The total is: ', 23+45) The total is: 68 لقد طبعنا سلاسل نصيةً أوأعدادًا فيما سبق، أما الآن فسندمج الاثنين في تعليمة واحدة، فاصلين بينهما بفاصلة إنجليزية ,، ويمكن توسيع تلك الميزة بجمعها مع إحدى خصائص بايثون في إخراج البيانات، وهي سلسلة التنسيق format string: >>> print( "The sum of %d and %d is: %d" % (7,18,7+18)) The sum of 7 and 18 is: 25 تحتوي سلسلة التنسيق على علامات %، غير أنها تختلف عن عامل الباقي الذي تحدثنا عنه من قبل، بل يكون لها معنىً خاص حين تُستخدم في سلسلة كالتي بين أيدينا، وحالات الاستخدام المتعددة تلك تعني أن علينا قراءة المكتوب بانتباه لتحديد سياقه، ثم تحديد وظيفة % فيه، حيث يخبر الحرف d الذي بعد محرف % بايثون بوجوب وضع عدد عشري مكانه، والذي نحصل على قيمته -التي سنستخدمها لتحل محله- من القيم الموجودة داخل التعبير الذي بين الأقواس، والذي كتِب بعد علامة % المنفردة في نهاية العبارة، ومن المهم أن يكون عدد القيم التي في القوس النهائي مطابقًا لعدد علامات % الموجودة في السلسلة النصية. توجد حروف أخرى يمكن وضعها بعد علامة %، ويستعمَل كل منها لغرض مختلف، منها: %S للسلاسل النصية. %x للأعداد الست عشرية hexadecimal. %0.2f للأعداد الحقيقية التي لها منزلتان عشريتان كحد أقصى. %04d لإزاحة العدد بأصفار قبله ليكون من أربعة منازل عشرية. انظر توثيق بايثون للمزيد من المعلومات. ونستطيع طباعة أي كائن بايثون باستخدام دالة الطباعة، حتى لو كانت النتيجة على غير ما كنا نريد، فربما تكون وصفًا لنوع الكائن، لكننا نستطيع طباعة ذلك على أي حال. >>> print( "The sum of {:d} and {:d} is: {:d}".format(7,18,7+18) The sum of 7 and 18 is: 25 زيادة إمكانيات اللغة >>> import sys إذا كتبنا السطر أعلاه في محث بايثون ثم ضغطنا على زر الإدخال، فلن نرى شيئًا على الشاشة، غير أن هذا لا يعني عدم حدوث شيء ما في الخلفية، ولشرح ما حدث بعد كتابة هذه الأمر سننظر أولًا إلى معمارية بايثون نفسها، وحتى لو لم تكن تستخدم بايثون فتابع الشرح، إذ ستكون ثمة آليات مشابهة في اللغة التي تستخدمها. عند بدء لغة بايثون تتاح لنا عدة دوال وأوامر، وهذه الأوامر مدمجة في اللغة وتسمى بالمضمَّنات built-ins، لأنها مبنية داخل نسيج اللغة نفسها، غير أن بايثون تستطيع توسيع قائمة الدوال المتاحة بدمج وحدات توسيع extension modules فيها، وهو يشبه شراء المرء لأداة جديدة من متجر العُدد والآلات ليضيفها إلى مجموعته المنزلية، وفي مثالنا فإن الآلة هي sys، وقد وضعتها العملية import داخل صندوق الآلات الذي سنستخدمه؛ أما حقيقة ما يفعله هذا الأمر فهو إتاحة "أدوات" جديدة على شكل دوال للغة بايثون، تُعرَّف داخل وحدة اسمها sys، وتلك طريقة توسيع بايثون لتنفيذ أي شيء غير مدمج في النظام الأساسي، وستجد أكثر من مئة وحدة في المكتبة القياسية standard library التي تحصل عليها مع بايثون، كما يمكنك إنشاء وحداتك الخاصة واستيرادها واستخدامها مثل الوحدات التي وفرتها بايثون عند تثبيتها بالضبط، وسنعود إلى هذا الأمر لاحقًا. كذلك ستجد مزيدًا من الوحدات التي يمكن تحميلها من الإنترنت، فإذا بدأت مشروعًا لا تغطيه الوحدات التي في المكتبة القياسية، فانظر في الإنترنت أولًا فلعلك تجد شيئًا يساعدك. الخروج السريع لننظر الآن في كيفية استخدام تلك الأدوات التي أدخلناها، فإذا كتبنا الأمر التالي في محث بايثون؛ فسنجعل بايثون تنهي نفسها وتخرج، لأننا نكون قد نفّذنا الدالة exit المعرَّفة في وحدة sys. >>> sys.exit() لاحظ أننا نخرج من بايثون عادةً بكتابة محرف نهاية الملف End Of File واختصاره EOF في محث بايثون، وهو CTRL+Z على ويندوز أو CTRL+D على أنظمة يونكس Unix؛ أما إذا كنت تستخدم بيئة تطوير فتخرج من قائمة File ثم Exit، وإذا حاولنا تنفيذ هذا في أداة تطوير مثل IDLE؛ فإن الأداة تنتبه لمحاولة الخروج وتعرض رسالةً تقول شيئًا ما حول SystemExit، لكن لا تشغل بالك بها، فهذا يعني أن البرنامج يعمل وأن الأداة تحاول توفير الوقت عليك لئلا تبدأ من الصفر مرةً أخرى. لاحظ أن exit لها أقواس حولها، وذلك لأنها دالة معرفة في وحدة sys، حيث سنحتاج إلى وضع هذه الأقواس عند استدعاء دالة بايثون حتى لو لم تحتوي الأقواس نفسها على أي شيء، فإذا كتبنا sys.exit دون الأقواس، فستستجيب بايثون لنا بإخبارنا أن exit دالةٌ، بدلًا من تنفيذ الدالة نفسها. أخيرًا، لاحظ أن التعليمتين الأخيرتين مفيدتان عند استخدامهما معًا، أي أننا سنكتب ما يلي للخروج من بايثون بدلًا من EOF: >>> import sys >>> sys.exit() هكذا نكون قد كتبنا تسلسلًا بسيطًا من تعليمتين، ونكون قد خطونا قليلًا نحو البرمجة الحقيقية. استخدام جافاسكربت لا توجد طريقة سهلة في جافاسكربت لنكتب الأوامر ونراها تنفَّذ مباشرةً كما في بايثون، لكن نستطيع كتابة جميع الأوامر البسيطة أعلاه في ملف HTML واحد ثم تحميلها إلى المتصفح، وسنرى كيف تبدو حينئذ في جافاسكربت: <html><body> <script type="text/javascript"> document.write('Hello there!<br />'); document.write("Monty Python\'s Flying Circus has a \' within it<br />"); document.write(6+5); document.write("<br />"); document.write( ((8 * 4) + (7 - 3)) / (2 + 4) ); document.write("<br />"); document.write( 5/2 ); document.write("<br />"); document.write( 5 % 2 ); </script> </body></html> سيكون الخرج كما يلي: Hello there! Monty Python's Flying Circus has a ' within it 11 6 2.5 1 نستخدم document.write لإخراج النص إلى نافذة المتصفح، وهذا يكافئ تقريبًا دالة print في بايثون، وسنرى قريبًا طريقةً مختلفةً قليلًا في VBSCript لعرض المخرجات في المتصفح في المثال التالي. لاحظ كيف اضطررنا إلى كتابة <br /> كي نجبر البرنامج أن يعرض الخرج التالي في سطر جديد، وذلك لأن جافاسكربت تكتب مخرجاتها في صورة HTML، والتي تعرض السطر بأقصى عرض تسمح به نافذة المتصفح لديك، فإذا أردنا قسرها على إنهاء السطر وبدء سطر جديد، فسنستخدم رمز HTML الخاص بالسطر الجديد، وهو <br />. لاحظ كيف هرّبنا محارف الاقتباس المفردة بوضع شرطة مائلة خلفية \ قبل الاقتباس، سنشرح ذلك بالتفصيل حين نتحدث عن السلاسل النصية في فصل البيانات وأنواعها. VBScript كما ذكرنا بخصوص جافاسكربت؛ فيجب أن ننشئ ملفًا لوضع أوامر VBScript فيها ثم نفتحه في المتصفح، وإذا كتبنا الأوامر السابقة باستخدام VBScript فستبدو كما يلي: <html><body> <script type="text/vbscript"> MsgBox "Hello There!" MsgBox "Monty Python's Flying Circus has a ' in it" MsgBox 6 + 5 MsgBox ((8 * 4) + (7 - 3)) / (2 + 4) MsgBox 5/2 MsgBox 5 MOD 2 </script> </body></html> سنرى في الخرج كثيرًا من الصناديق الحوارية، يعرض كل منها خرجًا من أحد الأسطر التي في البرنامج، فإذا أردنا أن نجعل جافاسكربت تخرج لنا مثل تلك الصناديق الحوارية فسنستخدم alert("Hello There!") بدلًا من document.write("Hello there!<br>")، فقد استخدمنا alert هنا بدلًا من MsgBox التي في VBScript. لاحظ أننا لا نستطيع بدء سلسلة نصية باستخدام علامة اقتباس مفردة في VBScript، لكن يمكننا إدراج اقتباسات مفردة داخل سلاسل نصية ذات علامات اقتباس مزدوجة، باستخدام الدالة Chr التي إذا أعطيناها رمزًا لمحرف أعادت لنا ذلك المحرف، وبما أن هذا المثال يبدو فوضويًا للغاية، لنلق نظرةً على المثال التالي الذي يوضح كيفية عملها: <script type="text/vbscript"> Dim qt qt = Chr(34) MsgBox qt & "Go Away!" & qt & " he cried" </script> لمعرفة رمز أي محرف تريده؛ تستطيع الاسترشاد بهذا الموقع، وأخذ الرمز العشري decimal منه، أو بالنظر في خريطة المحارف التي يوفرها نظام التشغيل الخاص بك، إذ توفر أغلب نظم التشغيل المشهورة بريمجًا لذلك؛ أما إذا لم ترد استخدام هذا ولا ذاك لسبب ما؛ فاستخدم الجزء التالي من لغة جافاسكربت واستبدل المحرف الذي تريده بمحرف الاقتباس المزدوج الذي في المثال: <script type="text/javascript"> var code, chr = '"'; // put the character of interest here code = chr.charCodeAt(0); document.write("<br />The character code of " + chr + " is " + code); </script> لا تشغل بالك الآن بمعنى الأرقام التي في المثال، إذ سنعود إليها في الفصل التالي، وإنما سقناها الآن من أجل استخدامها إذا اضطررنا إلى إيجاد قيمة محرف ما. خاتمة تلك كانت نظرتنا الأولى على البرمجة، ولعلها كانت سهلة الفهم والإدراك، لكن سنحتاج إلى أن ننظر في أنواع البيانات التي سنقابلها في البرمجة وسنحتاج إليها قبل الشروع في البرمجة الحقيقية، كما سنرى الأمور والعمليات التي سنجريها على تلك البيانات. وقد عرفنا في هذا الفصل أن البرنامج قد يكون صغيرًا للغاية، لذا فلا مانع من أن يكون مجرد أمر واحد، وأن أسلوب بايثون في إجراء العمليات الحسابية هو نفسه الأسلوب المتبع في الرياضيات، وإذا أردنا الحصول على نتيجة كسرية فيجب أن نستخدم أعدادًا كسريةً كذلك، وأننا نستطيع دمج النصوص والأرقام باستخدام عامل التنسيق %، وأخيرًا عرفنا أننا نخرج من بايثون بكتابة import sys; sys.exit(). ترجمة -بتصرف- للفصل الرابع من كتاب Learning To Program لصاحبه Alan Gauld. اقرأ أيضًا المقال التالي: مدخل إلى البيانات وأنواعها: أنواع البيانات الأساسية المقال السابق: بداية رحلة تعلم البرمجة ما هي البرمجة؟ تعلم البرمجة1 نقطة
-
سنوسّع تطبيقنا وذلك بالسماح للمستخدمين أن يضيفوا ملاحظات جديدة. من الأفضل هنا أن نخزّن الملاحظات داخل حالة التطبيق App، ذلك إن أردنا أن تحدثّ الصفحة محتوياتها عند إضافة الملاحظة الجديدة. لندرج إذًا الدالة useState ونعرّف قطعًا للحالة تأخذ قيمها الابتدائية من القيم الابتدائية لمصفوفة الملاحظات التي يتم تمريرها كخصائص: import React, { useState } from 'react'import Note from './components/Note' const App = (props) => { const [notes, setNotes] = useState(props.notes) return ( <div> <h1>Notes</h1> <ul> {notes.map(note => <Note key={note.id} note={note} /> )} </ul> </div> ) } export default App يستخدم المكوِّن الدالة useState لتهيئة قطع الحالة المخزنة في notes بمصفوفة الملاحظات التي تمرر كخصائص: const App = (props) => { const [notes, setNotes] = useState(props.notes) // ... } علينا استخدام مصفوفة فارغة لتهيئة الملاحظات إن أردنا أن نبدأ التطبيق بقائمة فارغة من الملاحظات. سنحذف أيضًا الخصائص props من تعريف الدالة طالما أنها لن تُستخدم: const App = () => { const [notes, setNotes] = useState([]) // ... } لنركز الآن على القيم الأولية التي تمرر كخصائص للدالة، حيث سنضيف نموذج HTML إلى المكوِّن الذي سيضيف الملاحظات الجديدة: const App = (props) => { const [notes, setNotes] = useState(props.notes) const addNote = (event) => { event.preventDefault() console.log('button clicked', event.target) } return ( <div> <h1>Notes</h1> <ul> {notes.map(note => <Note key={note.id} note={note} /> )} </ul> <form onSubmit={addNote}> <input /> <button type="submit">save</button> </form> </div> ) } لقد أضفنا أيضًا الدالة addNote كمعالج حدث يُستدعى عندما يُسلّم (submit) النموذج عند النقر على زر التسليم. سنستخدم الطريقة التي ناقشناها في [القسم 1]() لتعريف معالج الحدث: const addNote = (event) => { event.preventDefault() console.log('button clicked', event.target) } يؤدي المعامل event دور الحدث الذي يستدعي دالة المعالج. يستدعي معالج الأحداث التابع ()event.preventDefaultr الذي يمنع حدوث التسليم الافتراضي للنموذج، والذي يسبب إعادة تحميل الصفحة إضافة إلى عدة أشياء أخرى. لنطبع الآن وجهة الحدث event.target على الطرفية: إنّ النموذج الذي عرّفناه في المكوًّن هو وجهة الحدث كما هو واضح، لكن كيف سنصل إلى البيانات الموجودة ضمن عنصر الإدخال input (وهو مربع النص في حالتنا) في النموذج؟ طرق كثيرة يمكن أن تفي بالغرض. سنلقي نظرة على أولها وهي استخدام المكوِّنات المقادة (controlled components). لنضف الآن قطعة حالة جديدة تدعى newNote لتخزّن ما يدخله المستخدم في العنصر input ضمن الصفة value: const App = (props) => { const [notes, setNotes] = useState(props.notes) const [newNote, setNewNote] = useState( 'a new note...' ) const addNote = (event) => { event.preventDefault() console.log('button clicked', event.target) } return ( <div> <h1>Notes</h1> <ul> {notes.map(note => <Note key={note.id} note={note} /> )} </ul> <form onSubmit={addNote}> <input value={newNote} /> <button type="submit">save</button> </form> </div> ) } سيُخزّن النص الموجود في مربع النص كقيمة ابتدائية للملاحظة الجديدة، لكن لو حاولنا إضافة أي نص فلن يسمح مربع النص بذلك. ستعرض الطرفية تنبيهًا قد يعطينا دليلًا على الخطأ الذي وقع: طالما أننا أسندنا قطعة من حالة المكوِّن App إلى الصفة value لعنصر الإدخال، فسيتحكم المكوِّن الآن بسلوك هذا العنصر. لذا لابد من تعريف معالج حدث جديد يزامن التغييرات التي تحدث في عنصر الإدخال مع حالة المكوِّن إن أردنا الكتابة ضمنه: const App = (props) => { const [notes, setNotes] = useState(props.notes) const [newNote, setNewNote] = useState( 'a new note...' ) // ... const handleNoteChange = (event) => { console.log(event.target.value) setNewNote(event.target.value) } return ( <div> <h1>Notes</h1> <ul> {notes.map(note => <Note key={note.id} note={note} /> )} </ul> <form onSubmit={addNote}> <input value={newNote} onChange={handleNoteChange} /> <button type="submit">save</button> </form> </div> ) } سنعرف الآن معالج حدث للخاصية onChange لعنصر إدخال النموذج: <input value={newNote} onChange={handleNoteChange} /> سيُستدعى الآن معالج الحدث عند حدوث أية تغييرات في عنصر الإدخال، وستتلقى دالة المعالج كائن الحدث كمعامل: const handleNoteChange = (event) => { console.log(event.target.value) setNewNote(event.target.value) } ترتبط الآن الخاصية target لكائن الحدث بعنصر الإدخال المُقاد (من قِبل المكوِّن)، وستشير القيمة event.target.value إلى محتوى عنصر الإدخال. ملاحظة: لا داعي لاستدعاء التابع ()event.preventDefault كما فعلنا سابقًا، لعدم وجود عمليات افتراضية عند حدوث تغيرات على عنصر الإدخال. يمكنك تتبع ما يجري عند استدعاء المعالج ضمن النافذة console في الطرفية: سترى كيف تتغير الحالة مباشرة داخل نافذة React Devtools، طبعًا إن كنت قد ثبتها سابقًا. ستعكس قطعة الحالة newNote في المكوِّن App التغيرات في قيمة عنصر الإدخال، إذًا يمكننا إكمال الدالة addNote التي تضيف ملاحظة جديدة: const addNote = (event) => { event.preventDefault() const noteObject = { content: newNote, date: new Date().toISOString(), important: Math.random() < 0.5, id: notes.length + 1, } setNotes(notes.concat(noteObject)) setNewNote('') } سننشئ أولًا كائنًا جديدًا يدعى noteObject يتلقى محتواه من قيمة الحالة newState. بينما يتولّد المعرِّف الفريد id وفقًا لعدد الملاحظات. سينجح هذا الأسلوب في تطبيقنا طالما أنه لن يستخدم لحذف الملاحظات. سنعطي الملاحظة احتمالًا بنسبة 50% لأن تعتبر مهمة بالاستفادة من الدالة ()Math.random وهي دالة تستخدم لتوليد أرقام عشوائية. نستخدم التابع concat الذي تعرفنا عليه سابقًا في إضافة الملاحظة الجديدة إلى قائمة الملاحظات: setNotes(notes.concat(noteObject)) لا يغير التابع المصفوفة الأصلية بل ينشئ مصفوفة جديدة وينسخ العناصر إليها ثم يضيف العنصر الجديد إلى نهايتها. وهذا أمر ضروري، إذ لا يجب علينا تغيير الحالة بشكل مباشر في React. سيقوم معالج الحدث أيضًا بتصفير قيمة عنصر الإدخال المقاد باستدعاء الدالة setNewNote المعرفة كالتالي: setNewNote('') ستجد شيفرة التطبيق الذي نعمل عليه في المسار part2-2 ضمن المخزن المخصص على github. انتقاء العناصر التي ستعرض سنضيف مهمة جديدة للتطبيق تقتضي إظهار الملاحظات الهامة فقط. ولنبدأ بإضافة قطعة حالة جديدة للمكوِّن App مهمتها تحديد الملاحظات التي يجب أن تعرض: const App = (props) => { const [notes, setNotes] = useState(props.notes) const [newNote, setNewNote] = useState('') const [showAll, setShowAll] = useState(true) // ... } سنعدل المكوًن أيضًا لكي يخزن قائمة بكل الملاحظات التي ستعرض ضمن المتغيّر notesDirectShow. يعتمد اختيار عناصر القائمة على حالة المكوِّن: import React, { useState } from 'react' import Note from './components/Note' const App = (props) => { const [notes, setNotes] = useState(props.notes) const [newNote, setNewNote] = useState('') const [showAll, setShowAll] = useState(true) // ... const notesToShow = showAll ? notes : notes.filter(note => note.important === true) return ( <div> <h1>Notes</h1> <ul> {notesToShow.map(note => <Note key={note.id} note={note} /> )} </ul> // ... </div> ) } يظهر تعريف المتغيّر notesDirectShow مختصرًا بالشكل التالي: const notesToShow = showAll ? notes : notes.filter(note => note.important === true) سترى في التعريف العامل الشرطي الذي ستراه أيضًا في عدة لغات برمجة أخرى. وسنشرح منطق هذا العامل من خلال المثال التالي: const result = condition ? val1 : val2 تعمل هذه الصيغة كالتالي: سيأخذ المتغير result القيمة val1 إذا تحقق الشرط condition وإلا سيأخذ القيمة val2. وبالعودة إلى الصيغة الموجودة في شيفرة التطبيق، سيأخذ المتغيّر notesToShow القيمة notes، وستظهر كل الملاحظات، إذا كان الشرط showAll محققًا. وإلا سيأخذ القيمة الأخرى، وستظهر الملاحظات الهامة فقط. لاحظ أن عملية الانتقاء قد تمت بمساعدة تابع الانتقاء في المصفوفات filter. notes.filter(note => note.important === true) ليس لعامل الموازنة (===) أهمية طالما أن القيمة note.important من النمط المنطقي. إذًا يمكننا ببساطة كتابة السطر البرمجي السابق بالشكل: notes.filter(note => note.important) إن المغزى من كتابة عامل الموازنة بالشكل(===) هو توضيح ناحية هامة بأن العامل (==) لا يؤدي دوره بالشكل المطلوب في كل الحالات ويجب عدم استخدامه في المقارنة حصرًا. اقرأ المزيد حول الموضوع لفهمٍ أعمق. يمكنك اختبار انتقاء الملاحظات بجعل القيمة الأولية false لقطعة الحالة showAll. سنقوم تاليًا بمنح المستخدم إمكانية تغيير قيمة الحالة showAll من واجهة المستخدم. وستظهر الشيفرة بعد التعديل كما يلي: import React, { useState } from 'react' import Note from './components/Note' const App = (props) => { const [notes, setNotes] = useState(props.notes) const [newNote, setNewNote] = useState('') const [showAll, setShowAll] = useState(true) // ... return ( <div> <h1>Notes</h1> <div> <button onClick={() => setShowAll(!showAll)}> show {showAll ? 'important' : 'all' } </button> </div> <ul> {notesToShow.map(note => <Note key={note.id} note={note} /> )} </ul> // ... </div> ) } سنتحكم بإخفاء أو إظهار الملاحظات باستخدام زر، وسيكون معالج الحدث الخاص به بسيطًا بحيث يمكن تعريفه مباشرة داخل الصفة onClick. يبدّل معالج الحدث قيمة showAll عند كل نقرة زر. () => setShowAll(!showAll) يتغير النص المكتوب على الزر حسب الحالة فمرة سيكون "important" ومرة "all": show {showAll ? 'important' : 'all'} ستجد شيفرة التطبيق الذي نعمل عليه في المسار part2-3 ضمن المخزن المخصص على github. التمارين 2.6-2.10 سنطور التطبيق الذي سنبدأه في التمرين الأول خلال التمارين اللاحقة. يفضل أن تسلم في مثل هذه الحالات النسخة النهائية من التطبيق. ويمكنك الإشارة إلى ذلك إن أردت من خلال التعليقات ضمن شيفرتك. تحذير: تنشئ الأداة create-react-app مستودع git محلي يحتوي المشروع، إلا إن كان في المجلد مستودع محلي سابق. من المرجح أنك لا تريد أن يغدو المشروع مستودعًا، لهذا نفذ الأمر التاليrm -rf .git في مسار المشروع. 2.6 دليل الهاتف: الخطوة 1 صمم دليل هاتف بسيط. سنعمل في هذا القسم على إضافة الأسماء فقط. اكتب الشيفرة المناسبة لإضافة شخص إلى دليلك. يمكنك استخدام الشيفرة التالية كنقطة انطلاق للمكوِّن App الخاص بتطبيقك: import React, { useState } from 'react' const App = () => { const [ persons, setPersons ] = useState([ { name: 'Arto Hellas' } ]) const [ newName, setNewName ] = useState('') return ( <div> <h2>Phonebook</h2> <form> <div> name: <input /> </div> <div> <button type="submit">add</button> </div> </form> <h2>Numbers</h2> ... </div> ) } export default App تستخدم قطعة الحالة newName في قيادة عنصر الإدخال في النموذج. من المفيد أحيانًا تصيير قطع الحالة أو المتغيرات لتظهر قيمها بشكل نصي لأغراض التنقيح. إذ يمكنك إضافة الشيفرة التالية مؤقتًا إلى العنصر الذي تصّيره: <div>debug: {newName}</div> لا تنس الاستفادة مما تعلمته عن تنقيح تطبيقات React في القسم 1، كما سيمنحك الموسِّع React developer tools قدرة كبيرة على تتبع التغيرات التي تحدث في حالة التطبيق. بعد إتمامك العمل ستبدو واجهة التطبيق مشابهة للواجهة التالية: لاحظ في الشكل السابق كيف يُستخدم الموسِّع الذي ذكرناه. تذكر: يمكنك أن تضع اسم الشخص كقيمة للخاصية key. تذكر أن تمنع التسليم الافتراضي للنموذج. 2.7 دليل الهاتف: الخطوة 2 امنع المستخدم من إدخال أسماء موجودة أصلًا في الدليل. استفد من توابع المصفوفات التي تقدمها JavaScript لإتمام المطلوب. وأظهر رسالة تحذير عندما يحاول المستخدم القيام بذلك باستخدام التابع alert. تلميح: يفضل استخدام القالب النصي إذا أردت أن تضع قيمة متغير ما ضمن سلسلة نصية. `${newName} is already added to phonebook` فإن كانت قيمة المتغير newName هي Arto Hellas سيعيد القالب النصي ما يلي: `Arto Hellas is already added to phonebook` كما يمكن استعمال إشارة (+) بكل بساطة: newName + ' is already added to phonebook' طبعًا ستبدو شيفرتك إحترافية أكثر عندما تستخدم القالب النصي. 2.8 دليل الهاتف: الخطوة 3 اجعل المستخدم قادرًا على إضافة رقم الهاتف أيضًا، لذا عليك إضافة عنصر إدخال آخر إلى النموذج، وطبعًا إضافة معالج حدث مناسب: <form> <div>name: <input /></div> <div>number: <input /></div> <div><button type="submit">add</button></div> </form> حتى هذه النقطة ستبدو واجهة التطبيق مشابه للصورة التالية: لاحظ كيف يقوم الموسٍّع بعمله! 2.9 دليل الهاتف: الخطوة 4 * أضف للتطبيق إمكانية البحث عن الأشخاص بالاسم: استخدم لذلك عنصر إدخال جديد وضعه خارج النموذج. توضح الصورة السابقة أنّ منطق الانتقاء غير حساس لحالة الأحرف أي البحث عن arto سيعطيك النتيجة Arto أيضًا إن وجدت. تذكر: أضف دائمًا بعض البيانات الجاهزة في تطبيقك كما فعلنا في الشيفرة التالية: const App = () => { const [persons, setPersons] = useState([ { name: 'Arto Hellas', number: '040-123456' }, { name: 'Ada Lovelace', number: '39-44-5323523' }, { name: 'Dan Abramov', number: '12-43-234345' }, { name: 'Mary Poppendieck', number: '39-23-6423122' } ]) // ... } سيوفر عليك ذلك عناء إدخال البيانات يدويًا كل مرة عند اختبار وظيفة جديدة. 2.10 دليل الهاتف: الخطوة 5 إن صممت تطبيقك ليستخدم مكوِّنًا واحدًا، أعد بناءه بوضع الأجزاء التي تراها مناسبة في مكوِّنات جديدة. ابق على حالة المكوِّن ومعالجات الأحداث ضمن المكوِّن الجذري App. يكفي أن تشكل ثلاثة مكوِّنات جديدة. يمكنك على سبيل المثال عزل عملية البحث في مكوِّن وكذلك النموذج الذي يُستخدم لإضافة الأشخاص وأيضًا عملية تصيير كل الأشخاص في الدليل أو عملية تصيير تفاصيل شخص واحد. يمكن أن يشبه المكوِّن الجذري بعد إعادة البناء الشكل التالي: const App = () => { // ... return ( <div> <h2>Phonebook</h2> <Filter ... /> <h3>Add a new</h3> <PersonForm ... /> <h3>Numbers</h3> <Persons ... /> </div> ) } سيصيّر المكوِّن الجذري عنوان التطبيق فقط، وتتولى المكوِّنات الجديدة بقية المهام. تذكر: قد تواجهك المشاكل في هذا التمرين إن لم تعرف المكوِّنات في المكان الصحيح، ولعلك ستستفيد الآن من مراجعة الفقرة لا تعرف مكوِّنًا داخل مكوِّن آخر من القسم السابق. ترجمة -وبتصرف- للفصل Forms من سلسلة Deep Dive Into Modern Web Development1 نقطة
-
في عام 2003، قرأت مقالةً في مجلة "نيويورك تايمز" كانت قد تضمنت هذا الاقتباس عن "ستيف جوبس": روعة هذا التعبير غيرت مهنتي كمبرمج بشكل كامل. في نهاية اليوم أنا من يكتب"الشيفرة" ومن ينشئ المنتج بيديه. فكيف لأحد آخر أن يحدد كيف يعمل المنتج في النهاية؟ الحقيقة الكامنة لكل المبرمجين هي أنهم غارقون في الخلف ولا يتعاملون بشكل مباشر مع المستخدم. فالمستخدم لا يتعامل مباشرةً مع عملهم بل يتعامل مع ما يصنعه المصممون. اختلاف المنظور هو ما يمنع المبرمجين من رؤية الصورة بشكل كامل فهم يفتقدون أهم جزء وهو المستخدم. أيها المبرمجون، تعَلُّم التصميم يجعل من الممكن أن تقوموا بتجميع كامل النظام في عقولكم، من كيفية تعامل المستخدم مع منتجكم وحتى آخر مرحلة حيث تقومون بتخزين المعلومات في قاعدة البيانات الخاصة بكم. هذا المسار المتكامل يمكنك من تطوير منتج أفضل من المنتجات المنافسة. كَوني مبرمجًا منذ أكثر من 15 سنة فإن تعلمي للتصميم قد طوّر أدائي تطويرًا جذريًا. كثيرًا ما نسمع بأنه يجب على المصممين أن يتعلموا البرمجة ولكنني أؤمن بالعكس, للحصول على منتجات رائعة فإن المبرمجين عليهم أن يتعلموا التصميم. فهم التصميم يؤدي لفهم المستخدم عندما بدأت بتعلم التصميم كانت إحدى أكثر اللحظات التي وقفت وتساءلت فيها هي أنه على الرغم من أنني أعمل في الخلفية إلا أن ما اصنعه يجب عليه أن يجعل حياة المستخدم أسهل، فمستخدموك لديهم العديد من المشاكل التي يحاولون حلها وإذا ركزت فقط على حل المشاكل التقنية فقد لا تستطيع التوصل لحل للمشكلة. إحدى أفضل الطرق للتأكد من أنك على المسار الصحيح لخدمة الاشخاص الذين سيستعملون منتجك بالفعل هي الانخراط مبكرًا في عملية التصميم، ويفضَّل أن يكون منذ اليوم الأول. وإدراكك لمشاكل المستخدم منذ البداية يمكنك من اتمام العمل بسلاسة وبشكل تام. صرّح الريادي المشهور ومؤسس شركة "Y Combinator"، "بول غراهام" بالتالي: كل شيء ليس كما يبدو عليه سوف أعيد القول بأنه تقريباً من المستحيل أن يمر يوم بدون رؤيتك لمقال عن إذا ما كان يجب على المصممين أن يتعلموا البرمجة. ما يجهله الناس هو أن المبرمجين قادرون على تعلم التصميم ويجب عليهم تعلم التصميم للعمل بشكل أفضل مع المصممين والحصول على منتجات رائعة حقًا. ولسوء الحظ, هنالك نوع من التنافسية بين المبرمجين والمصممين على من يمتلك الوظيفة الأصعب، ومن على صواب، ومن على خطأ، ومن يعرف أكثر والعديد من النقاط الأخرى، وهذا التنافر عن العمل سويًا لا يفيد بأي شكل من الأشكال. بمجرد تعلمك للتصميم ستلاحظ بأن عمل المصممين ليس سهلاً كما يبدو، ومن الناحية الأخرى، تعَلَّم البرمجة وسوف تدرك بأن المبرمجين ليسوا متجهمين وهدفهم ليس افساد تصاميمك. عندها، سوف يتمكن كل من المصممين والمبرمجين بتقدير عمل الآخر واحترام ما يقومون به مما يؤدي لعملهم سوياً كفريق. استمتع أكثر بأداء عملك بالنسبة لي، أفضل شيء بالنسبة لتعلم التصميم هو أنني أستمتع بعملي أكثر من السابق. أصبحت قادرًا على الانخراط في محادثات هادفة مع المصممين عن طريق التحدث بلغتهم التي يفهمونها مما أكسبني شعورًا كبيرًا بالرضى، بالإضافة لذلك, اصبحت متلهفاً أكثر كلما اقتربنا من الاعلان عن مشروع جديد وهذا لأن مشاركتي تخطّت الجوانب التقنية التي تحدث في الخفاء. أيضًا, تعلُم التصميم يساعد المبرمجين على خلق منتج يعادِل بين الإبداع والمنطق بدون "مستند خصائص التشغيل" ومن الممكن تجنب قوالب الفوتوشوب "PSD" وبرمجة تصاميمك وتنسيقاتك بطريقة فعالة خلال كتابتك لشيفرة البرمجة. وعندما تجد ثغرات في تصميمك و في صفحات النسق (style sheets) فبإمكانك إصلاحها فورًا وإنهاء عملك بدون أي تأخير او قلق. التأقلم هنالك تدفق كبير للأجهزة الحديثة التي يتم انتاجها يومياً بمختلف الأشكال والأحجام لذلك فإن القدرة على التأقلم بأسرع ما يمكن هي شيء أساسي. يجب على المبرمجين أن يعملوا بتصميم متوافق مع هذه المتطلبات والمواصفات، وهذا يعني بأنه من المهم أن يكون المبرمجون قادرون على ملاحظة وتحديد هذه التغييرات. كيف سيتصرف التصميم عندما تنتقل من جهاز الكمبيوتر للهاتف المحمول أو الساعة الذكية؟ سوف تتمكن بمعرفتك التصميمية من التعامل مع عملك بأسلوب مختلف عما كنت سوف تفعل عادةً, مما يعطيك ميّزة تنافسية كبيرة وسوف توفّر الكثير من الوقت عليك وعلى فريقك. كثيرًا ما يختلط التصميم بالبرمجة في شركتي، وعندما يكون المبرمج يعرف عن التصميم فإن النتائج تكون أفضل على صعيد كل من سرعة العمل والجودة فيما ننتجه. كيف تعلمتُ التصميم أولى خطواتي كانت على موقع "DesignLab" حيث ساعدني احد المرشدين طوال الوقت، وقمت أيضًا بالانتساب لبرنامج التصميم على موقع "BLOC" وكان كلا الموقعين رائعين حقًا, ولكن بالطبع لا شيء يغني عن الممارسة المستمرة لذلك يجب عليك الممارسة يوميًا حتى تصل للدرجة المطلوبة. ترجمة -بتصرف- للمقال Why developers should learn design لصاحبه Christian Rennella1 نقطة
-
1 نقطة