لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 03/14/18 في كل الموقع
-
1 نقطة
-
يجب ان تقوم بتعريف المتغير hour$ قبل الجملة الشرطية $hour = date('H'); او تقوم بتعديل الشرط ليصبح if (date('H') < 7) { .. } بالتوفيق1 نقطة
-
1 نقطة
-
أعلم أنَّه ليس من السهل الاعتراف بالأخطاء التي تقوم بها، لكن الخطأ هو جزءٌ رئيسي من كل عمليات التعليم، بدءًا من التعلم كيفية المشي إلى تعلم لغة برمجة جديدة مثل بايثون. هذه قائمة بثلاثة أخطاء التي وقعتُ فيها أثناء تعلمي لبايثون، عرضتها هنا لكي يحاول مبرمجو بايثون الجدد تفاديها وعدم الوقوع فيها، وهذه الأخطاء أدت إلى حدوث مشاكل كبيرة أخذت من وقتي ساعات حتى حللتها. الخطأ الأول: استخدام أنواع البيانات القابلة للتغير كوسائط افتراضية عند تعريف الدالة لنقل أنَّ لديك دالة صغيرة التي تبحث عن روابط في الصفحة الحالية وتستطيع إضافتها إلى قائمة (list) معيّنة. def search_for_links(page, add_to=[]): new_links = page.search_for_links() add_to.extend(new_links) return add_to لا يبدو أنَّ هنالك أيّ خطأ في الدالة السابقة، وهذا صحيح، فهي تعمل لكن هنالك مشاكل فيها؛ فلو مررنا قائمةً (list) إلى المعامل add_to فستعمل كما يجب، لكن ماذا يحدث لو تركنا القيمة الافتراضية دون تعديل؟ جرِّب تنفيذ الشيفرة الآتية: def fn(var1, var2=[]): var2.append(var1) print var2 fn(3) fn(4) fn(5) ستتوقع رؤية الناتج الآتي: [3] [4] [5] لكنك ستُفاجأ بالناتج الآتي: [3] [3, 4] [3, 4, 5] لماذا؟! يمكنك أن تستنتج أن القائمة (list) نفسها ستستعمل في كل مرة، فعندما نكتب دالة مثل الدالة السابقة في بايثون فسيتم تهيئة القائمة (list) كجزءٍ من تعريف الدالة، أي أنها لن تُهيّئ كل مرة تُستدعى فيها الدالة، وهذا يعني أنَّ الدالة ستحتفظ بكائن القائمة نفسه مرارًا وتكرارًا، ما لم تُحدِّد قيمةً أخرى له: fn(3, [4]) الناتج: [4, 3] الناتج يماثل ما قد توقعناه. الطريقة الصحيحة لفعل ذلك هي: def fn(var1, var2=None): if not var2: var2 = [] var2.append(var1) لنعد كتابة الدالة السابقة: def search_for_links(page, add_to=None): if not add_to: add_to = [] new_links = page.search_for_links() add_to.extend(new_links) return add_to نقلنا عملية التهيئة من مكان تعريف الدالة إلى داخلها مما يعني أنَّ عملية التهيئة ستتم في كل مرة تُشغَّل فيها الدالة. لاحظ أنَّ ذلك ليس ضروريًا إذا كنتَ تستعمل أنواع بيانات غير قابلة للتعديل مثل tuple أو string أو int. وهذا يعني أنَّك تستطيع تعريف دالة كما في الدالة الآتية دون إمكانية حدوث أخطاء غير متوقعة: def func(message="my message"): print message الخطأ الثاني: استخدام أنواع البيانات القابلة للتعديل كمتغيرات في الأصناف هذا الخطأ شبيهٌ كثيرًا بالخطأ السابق. تمعّن في الشيفرة الآتية: class URLCatcher(object): urls = [] def add_url(self, url): self.urls.append(url) الشيفرة السابقة تبدو طبيعية جدًا، فلدينا كائن لتخزين روابط URL، وعند استدعائنا للدالة add_url فسنمرر إليها رابط URL لتخزِّنه، صحيح؟ لنجرِّبها: a = URLCatcher() a.add_url('http://www.google.') b = URLCatcher() b.add_url('http://www.bbc.co.') الناتج: b.urls ['http://www.google.com', 'http://www.bbc.co.uk'] a.urls ['http://www.google.com', 'http://www.bbc.co.uk'] ما هذا؟! لم نتوقع ذلك. إذ أنشأنا كائنين منفصلين a و b، وأسندنا رابطًا للكائن a مختلفًا عن رابط الكائن b، فكيف امتلك كلا الكائنين الرابطين نفسهما؟ اتضح أنَّ هذه المشكلة شبيهة جدًا بالمشكلة في المثال الأول، فقائمة (list) عناوين URL قد تمت تهيئتها عند تعريف الصنف (class)، وبالتالي أمست جميع الكائنات المُنشَأة من ذاك الصنف تستعمل القائمة نفسها. هنالك بعض الحالات التي نستفيد فيها من هذه الميزة، لكنها ستضرك في أغلبية الأوقات، فلو أردتَ تخزين بيانات كل كائن على حدة فيمكنك تعديل الشيفرة لتصبح كما يلي: class URLCatcher(object): def __init__(self): self.urls = [] def add_url(self, url): self.urls.append(url) أصبحت قائمة urls تُهيّئ عند إنشاء الكائن، وعندما نُنشِئ كائنين فستُهيّئ قائمتان منفصلتان. الخطأ الثالث: عملية إسناد قيم إلى نوع بيانات قابل للتعديل هذا الخطأ أربكني لفترة حتى فهمته، دعنا نستعمل نوع بيانات قابل للتعديل مثل dict: a = {'1': "one", '2': 'two'} لنفترض أننا نريد أخذ قيمة المتغير a واستعمالها في مكانٍ آخر دون تعديل القيمة الأصلية: b = a b['3'] = 'three' أليس هذا بسيطًا؟ لننظر الآن إلى القيمة المخزّنة في المتغير a التي لم نُعدِّلها قط: {'1': "one", '2': 'two', '3': 'three'} ماذا؟! كيف ستبدو قيمة المتغير b إذًا؟ {'1': "one", '2': 'two', '3': 'three'} دعنا نعود خطوةً إلى الوراء وننظر ماذا يحدث لو استعملنا أنواع البيانات غير القابلة للتعديل، مثل tuple: c = (2, 3) d = c d = (4, 5) قيمة c هي: (2, 3) بينما قيمة d هي: (4, 5) لقد جرى كل شيءٍ على ما يرام، لذا ماذا حدث في مثالنا؟ عند استخدام أنواع البيانات القابلة للتعديل فسنحصل على شيءٍ شبيهٍ بالمؤشرات (pointers) في لغة C، فعندما قلنا أنَّ b = a في الشيفرة السابقة فهذا يعني أنَّ المتغير b أصبح يُشير إلى a، وكلا المتغيرين يشير إلى نفس الكائن في ذاكرة بايثون؟ هل هذا مألوف لديك؟ ذلك لأن هذه المشكلة شبيهة بالمشاكل السابقة، وكنتُ أنوي تسمية هذا الدرس باسم «المشاكل التي تحدث مع أنواع البيانات القابلة للتعديل». هل يحدث الأمر نفسه مع القوائم (list)؟ نعم. وكيف سنلتف على المشكلة؟ حسنًا، يجب أن نكتب الشيفرة الآتية التي تنسخ القائمة: b = a[:] السطر السابق سيؤدي إلى نسخ مرجعية كل عنصر من عناصر القائمة ووضعه في قائمة جديدة، لكن لنأخذ حِذرنا فإذا كان نوع بيانات أحد الكائنات الموجودة في القائمة قابلًا للتعديل فسيؤدي ذلك إلى الحصول إلى مرجعية لتلك الكائنات بدلًا من نسخها. تخيل وجود قائمة على قطعة من الورق، ففي المثال الأصلي كان ينظر الشخص A والشخص B إلى الورقة نفسها، فلو عدّل شخصٌ ما القائمةَ فسيرى كلا الشخصين التعديلات التي أجريت على القائمة، وعندما نسخنا المرجعيات فأصبح لكل شخصٍ قائمته الخاصة به، لكن لنفترض أنَّ تلك القائمة تحتوي على أماكن يمكن البحث فيها عن طعام، فلو كانت «الثلاجة» موجودة في القائمة فحتى لو نسخها الشخص A و B فما تزال تشير إلى الثلاجة نفسها؛ فلو أتى الشخص A وعدّل محتويات الثلاثة (لنفترض أنه أكل جميع الحلويات فيها) فسيلاحظ الشخص B أن الحلويات قد اختفت من الثلاثة. ولا توجد طريقة سهلة للالتفاف على هذه المشكلة، وهذا أمرٌ مهمٌ عليك تذكره عندما تبرمج لكي تكتب شيفرتك بطريقة لا تسبِّب أيّة مشاكل. تعمل أنواع dict بنفس الطريقة، ويمكنك إنشاء نسخة كاملة باستعمال الدالة copy(): b = a.copy() أكرِّر أنَّ ذلك سيُنشِئ متغيرًا جديدًا من نوع dict يُشير إلى نفس العناصر الموجودة في المتغير الأصلي، وبالتالي لو كان لدينا قائمتان متماثلتين وعدّلنا كائنًا قابلًا للتعديل مُشار إليه عبر مفتاح موجود في المتغير a فيمكن معرفة تلك التعديلات من داخل المتغير b. الإشكاليات التي تواجهنا مع أنواع البيانات القابلة للتعديل تكون نتيجةً لمرونة تلك الأنواع، حيث لا تُشكِّل أيٌّ مما سبق مشكلةً حقيقة، وإنما هي أمور ضرورية يجب أخذها بالحسبان لتنجب المشاكل. وعمليات النسخ الكاملة التي ذكرناها آنفًا لن تكون ضروريةً في 99% من الحالات، أي يجب تعديل برنامجك لكي لا يحتاج إلى استخدام تلك النسخ من الأساس. ترجمة –وبتصرّف– للمقال 3 mistakes to avoid when learning to code in Python لصاحبه Pete Savage1 نقطة
-
في بدايات التسعينات، قام Guido van Rossum بإنشاء لغة البايثون. تُعتبر البايثون من أشهر لغات البرمجة حاليا، ولها حضور واسع في العديد من المجالات التطبيقية والعلمية، وتتميز بسهولة شفرتها البرمجية وسرعة تعلمها مع متانة وقوة تضاهي اللغات الأخرى. سوف نتناول في هذا المقال المواضيع التالية: التعليقات. أنواع البيانات. المتغيرات والتراكيب. جمل التحكم. الدوال Functions. الوحدات. الفئات. ملاحظة: إصدار البايثون 3 هو المعتمد في شرح هذا المقال، وناتج العمليات والأوامر في هذا المقال سيتم كتابتها بعد الرمز # =>. التعليقات تبدأ التعليقات ذات السطر الواحد برمز #، أما التعليقات التي تحتوي أكثر من سطر فتجب إحاطتها بثلاث علامات تنصيص (منفردة أو مزدوجة) في البداية والنهاية. أنظر المثال التالي: # Single line comments start with a number symbol. """ Multiline strings can be written using three "s, and are often used as documentation. """ دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن أنواع البيانات والعمليات الأرقام: 3 # => 3 العمليات الرياضية: 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7.0 يوجد نوعان من القسمة في بايثون 3، الأولى تُسمى القسمة بعدد فاصل عائم “floating point division” ونَستخدم رمز القسمة المعروف / ، وناتج العملية هو دائما عدد حقيقي من النوع float: 10.0 / 3 # => 3.3333333333333335 أما النوع الثاني من القسمة فيُسمى القسمة الصحيحة “integer division” ونَستخدم الرمز // لهذا النوع، ويكون ناتج العملية دون الفاصلة والأرقام التي بعدها: 5 // 3 # => 1 5.0 // 3.0 # => 1.0 # يعمل هذا النوع من القسمة على الأعداد الحقيقية أيضا -5 // 3 # => -2 -5.0 // 3.0 # => -2.0 عملية باقي القسمة: 7 % 3 # => 1 عملية الأس: 2**3 # => 8 قاعدة أولوية العمليات حسب الأقواس: (1 + 3) * 2 # => 8 القيم المنطقية (لاحظ الحرف الكبير في البداية): True False عكس القيمة المنطقية باستخدام not: not True # => False not False # => True العمليات المنطقية (العمليات المنطقية حساسة لحالة الأحرف): True and False # => False False or True # => True القيمة المنطقية False تساوي الرقم 0، والقيمة المنطقية True تساوي الرقم 1: 0 and 2 # => 0 -5 or 0 # => -5 0 == False # => True 2 == True # => False 1 == True # => True -5 != False != True #=> True عملية فحص المساواة باستخدام ==: 1 == 1 # => True 2 == 1 # => False فحص عدم المساواة: 1 != 1 # => False 2 != 1 # => True المقارنات: 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True 1 < 2 < 3 # => True 2 < 3 < 2 # => False تفحص عملية is إذا كان متغيران يشيران لنفس الكائن أم لا، ولكن العملية == تفحص إذا كانا بنفس القيمة أم لا: a = [1, 2, 3, 4] b = a b is a # => True b == a # => True b = [1, 2, 3, 4] b is a # => False b == a # => True تُنشَأ النصوص باستخدام علامات التنصيص المزدوجة أو الفردية: "This is a string." 'This is also a string.' تستطيع جمع النصوص ببعضها، ولكن حاول تجنب هذه الطريقة: "Hello " + "world!" # => "Hello world!" تستطيع دمج النصوص ببعضها دون استخدام + : "Hello " "world!" # => "Hello world!" من الممكن التعامل مع النص وكأنه مصفوفة من الحروف: "This is a string"[0] # => 'T' للحصول على طول نص نستخدم الدالة المضمنة len : len("This is a string") # => 16 تستطيع استخدام الدالة format لإجراء عملية التنسيق على النص: "{} can be {}".format("Strings", "interpolated") # => "Strings can be interpolated" تستطيع عند استخدام الدالة format ترقيم المدخلات حسب ترتيبها واستخدامها في تنسيق النص أكثر من مرة: "{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick") # => "Jack be nimble, Jack be quick, Jack jump over the candle stick" أو باستخدام طريقة تسمية المدخلات: "{name} wants to eat {food}".format(name="Bob", food="lasagna") # => "Bob wants to eat lasagna" تستطيع في البايثون 3 استخدام الطريقة القديمة في بايثون 2 لعمل تنسيق للنصوص: "%s can be %s the %s way" % ("Strings", "interpolated", "old") # => "Strings can be interpolated the old way" None عبارة عن كائن: None # => None لا تستخدم فحص المساواة باستخدام رمز == للمقارنة مع None واستخدم عملية الفحص is بدلا منها: "etc" is None # => False None is None # => True None والرقم 0 والمتغيرات الفارغة من الأنواع strings، lists، dict، وtuples جميعها تُرادف القيمة المنطقية False، أما باقي القيم فهي True: # All other values are True bool(0) # => False bool("") # => False bool([]) # => False bool({}) # => False bool(()) # => False المتغيرات والتراكيب: تتوفّردالة خاصة للطباعة (الإخراج على الطرفية) وتسمى print: print("I'm Python. Nice to meet you!") # => I'm Python. Nice to meet you! يُطبَع سطر جديد تلقائيا عند استخدام الدالة print. تستطيع استخدام المعطى end لتغيير هذا الأمر وتحديد النص الذي تريده بدلا من السطر الجديد: print("Hello, World", end="!") # => Hello, World! للحصول على مدخلات من الطرفية نستخدم الدالة input: input_string_var = input("Enter some data: ") # Returns the data as a string ملاحظة/ في النسخ القديمة من البايثون، كانت الدالة input باسم raw_input. لا يوجد في البايثون تعريفات، ولكن يوجد إعطاء قيم مباشرة. الطريقة المتعارف عليها في تسمية المتغيرات هي الأحرف الصغيرة مع التسطير السفلي: some_var = 5 some_var # => 5 محاولة استخدام متغير لم يأخذ قيمة مسبقاً ينتج عنه خطأ، راجع كيفية معالجة الأخطاء تحت عنوان جمل التحكم. some_unknown_var # ينتُج خطأ من الصنف NameError تشبه القوائم المصفوفات في اللغات الأخرى: li = [] other_li = [4, 5, 6] نستخدم append لإضافة عناصر في نهاية القائمة: li.append(1) # li is now [1] li.append(2) # li is now [1, 2] li.append(4) # li is now [1, 2, 4] li.append(3) # li is now [1, 2, 4, 3] نستخدم الدالةpop لحذف العناصر من آخر القائمة. ترجع التعليمة أدناه القيمة 3 وتصبح مكونات القائمة [1, 2, 4]: li.pop() # => 3 and li is now [1, 2, 4] تعود القائمة إلى حالتها السابقة لتنفيذ الدالة pop بعد تنفيذ الدالة append على النحو التالي: li.append(3) # li is now [1, 2, 4, 3] again. تستطيع التعامل مع القائمة مثل المصفوفة من حيث الوصول لعناصرها: li[0] # => 1 li[-1] # => 3 في حال استخدام فهرس خارج حدود القائمة سينتج خطأ من نوع IndexError: li[4] # Raises an IndexError تستطيع استخدام مجال للحصول على جزء أكبر من القائمة بحيث نحدد فهرس البداية وفهرس النهاية. li[1:3] # => [2, 4] ملاحظة: فهرس النهاية غير مشمول في القيمة المرجعة، حيث يعدّ النمط المستخدم هو نمط نطاق مغلق-مفتوح. في حال عدم استخدام فهرس النهاية: li[2:] # => [4, 3] في حال عدم استخدام فهرس البداية: li[:3] # => [1, 2, 4] اختيار عنصر كل خطوتين ابتداء من العنصر الأول في القائمة: li[::2] # =>[1, 4] إرجاع كامل المصفوفة بطريقة عكسية: li[::-1] # => [3, 4, 2, 1] القاعدة العامة للاستعلامات السابقة في القوائم هي كالتالي(البداية start، النهاية end والخطوة step): # li[start:end:step] نسخ عميق (Deep Copy): li2 = li[:] # => li2 = [1, 2, 4, 3] عندما نفحص المساواة باستخدام عملية is كالتالي: (li2 is li) ستكون النتيجة False. لحذف عنصر من القائمة: del li[2] # li is now [1, 2, 3] لحذف أول عنصر في القائمة يساوي القيمة المدخلة في الدالة remove: li.remove(2) # li is now [1, 3] li.remove(2) # ValueError لأن القيمة غير موجودة إضافة عنصر في مكان معين في القائمة: li.insert(1, 2) # li is now [1, 2, 3] again الحصول على فهرس أول عنصر في القائمة يساوي القيمة المعطاة: li.index(2) # => 1 li.index(4) # ValueError لأن القيمة غير موجودة لإضافة قائمة لقائمة وإرجاع النتيجة كقائمة جديدة: li + other_li # => [1, 2, 3, 4, 5, 6] لتمديد قائمة وإضافة قائمة إليها: li.extend(other_li) # Now li is [1, 2, 3, 4, 5, 6] لفحص وجود قيمة في القائمة: 1 in li # => True للحصول على حجم القائمة (عدد العناصر التي بها): len(li) # => 6 نوع البيانات Tuple تشبه القائمة ولكنها غير قابلة للتعديل (ثابتة-immutable): tup = (1, 2, 3) tup[0] # => 1 tup[0] = 3 # Raises a TypeError لاحظ أنه في حالة وجود عنصر واحد في tuple لابد من وضع فاصلة عادية بعد العنصر، أما في حالة وجود أكثر من عنصر فتصبح الفاصلة إضافية: type((1)) # => <class 'int'> type((1,)) # => <class 'tuple'> type(()) # => <class 'tuple'> تستطيع تنفيذ أغلب عمليات القوائم على النوع Tuple: len(tup) # => 3 tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) tup[:2] # => (1, 2) 2 in tup # => True تستطيع تفريغ (unpacking) محتويات Tuples وكذلك القوائم في متغيرات كما في الأمثلة التالية: a, b, c = (1, 2, 3) # a = 1, b = 2, c = 3 a, *b, c = (1, 2, 3, 4) # a = 1, b = [2, 3], c = 4 عند عدم استخدام الأقواس فإن نوع البيانات التلقائي الذي سيتم استخدامه هو Tuple: d, e, f = 4, 5, 6 تبديل قيم المتغيرات بطريقة سهلة: e, d = d, e # d = 5, e = 4 القواميس عبارة عن مؤشرات (مُخططات) من المفاتيح للقيم (كل مفتاح يؤشر على قيمة خاصة به). تعريف قاموس فارغ: empty_dict = {} تعريف قاموس بقيم مسبقة: filled_dict = {"one": 1, "two": 2, "three": 3} لاحظ أن المفاتيح في القواميس لابد أن يكون نوع بياناتها ثابتا (immutable) وذلك لضمان الحصول على مفتاح ثابت (لا تتغير قيمته). أنواع البيانات الثابتة والتي من الممكن استخدامها هي int , float, string, tuple. invalid_dict = {[1,2,3]: "123"} # => Raises a TypeError: unhashable type: 'list' valid_dict = {(1,2,3):[1,2,3]} # Values can be of any type, however. يمكن للقيم – عكس المفاتيح – أن تكون من أي نوع. للبحث عن قيم نستخدم الأقواس المعكوفة: filled_dict["one"] # => 1 للحصول على مفاتيح قاموس على شكل قائمة (الترتيب في القواميس غير ثابت): list(filled_dict.keys()) # => ["three", "two", "one"] للحصول على قيم قاموس على شكل قائمة: list(filled_dict.values()) # => [3, 2, 1] للتأكد من وجود مفتاح قاموس معين: "one" in filled_dict # => True 1 in filled_dict # => False في حالة استخدام مفتاح غير موجود للبحث في قاموس، فإن ذلك ينتج خطأ: filled_dict["four"] # KeyError استخدم الدالة get لتجنب الخطأ السابق: filled_dict.get("one") # => 1 filled_dict.get("four") # => None تدعم الدالة get إعادة قيمة تلقائية في حالة عدم وجود المفتاح: filled_dict.get("one", 4) # => 1 filled_dict.get("four", 4) # => 4 تضيف الدالة setdefault المفتاح المُمرر إلى القاموس في حالة عدم وجوده. تضيف التعليمة التالية مفتاحا باسم five وتعطيه قيمة 5، أما التعليمة الثانية فلا تحدت تغييرا على القاموس. filled_dict.setdefault("five", 5) # filled_dict["five"] is set to 5 filled_dict.setdefault("five", 6) # filled_dict["five"] is still 5 للإضافة إلى القاموس: filled_dict.update({"four":4}) # => {"one": 1, "two": 2, "three": 3, "four": 4} filled_dict["four"] = 4 # طريقة أخرى حذف المفتاح من القاموس: del filled_dict["one"] # Removes the key "one" from filled dict بعض طرق التفريغ في القواميس: {'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2} {'a': 1, **{'a': 2}} # => {'a': 2} المجموعات: empty_set = set() some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4} نوع البيانات الخاص بعناصر المجموعات لابد أن يكون ثابتا: invalid_set = {[1], 1} # => Raises a TypeError: unhashable type: 'list' valid_set = {(1,), 1} للإضافة إلى المجموعة: filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5} إجراء عملية التقاطع بين مجموعتين: other_set = {3, 4, 5, 6} filled_set & other_set # => {3, 4, 5} إجراء عملية الاتحاد بين مجموعتين: filled_set | other_set # => {1, 2, 3, 4, 5, 6} إجراء عملية الطرح بين مجموعتين: {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} لإجراء عملية فرق التماثل بين مجموعتين: {1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} لفحص إذا كانت المجموعة على الشمال هي مجموعة تحتوي المجموعة على اليمين أم لا: {1, 2} >= {1, 2, 3} # => False عكس المثال السابق: {1, 2} <= {1, 2, 3} # => True فحص وجود قيمة في مجموعة: 2 in filled_set # => True 10 in filled_set # => False جمل التحكم some_var = 5 جملة if: if some_var > 10: print("قيمة المتغيّر أكبر تماما من 10") elif some_var < 10: # هذه الجملة اختيارية print("قيمة المتغيّر أصغر من 10") else: # هذه الجملة اختيارية print("قيمة المتغيّر تساوي 10") جملة for: for animal in ["dog", "cat", "mouse"]: print("{} is a mammal".format(animal)) لاحظ استخدام الدالة format في جملة for السابقة. يمكن أيضا تطبيق الجملة على مجال عددي range: for i in range(4): print(i) for i in range(4, 8): print(i) for i in range(4, 8, 2): print(i) جملة while: x = 0 while x < 4: print(x) x += 1 # اختصارا ل x = x + 1 معالجة الأخطاء باستخدام try/except (استخدم raise لتوليد الخطأ): try: raise IndexError("This is an index error") except IndexError as e: pass except (TypeError, NameError): pass else: print("All good!") finally: print("We can clean up resources here") ملاحظات حول معالجة الأخطاء: Pass تعني عدم وجود عملية للتنفيذ. تستطيع سرد أكثر من نوع خطأ في جملة except. تستطيع استخدام جملة else مع try/except اختياريا (تنفذ في حالة كانت الشفرة البرمجية في try لم تُصدر أي خطأ). نستخدم جملة finally لتنفيذ شفرة برمجية بعد try/except بغض النظر عن وجود أخطاء أم لا، وعادةً يُعاد تحرير المصادر المستخدمة. بدلا من استخدام جملة finally لإعادة تحرير المصادر المستخدمة، تستطيع استخدام جملة with: with open("myfile.txt") as f: for line in f: print(line) تُقدم البايثون كائنًا متُعددًا (Iterable) وهو كائن مجرد (عام) يُتعامل معه مثل sequence. فمثلا الكائن المُرجع من الدالة range هو كائن مُتعدد: filled_dict = {"one": 1, "two": 2, "three": 3} our_iterable = filled_dict.keys() print(our_iterable) # => dict_keys(['one', 'two', 'three']). تستطيع المرور على عناصر الكائن المتعدد والتعامل معها: for i in our_iterable: print(i) # Prints one, two, three على الرغم من خاصية الكائن المتعدد، إلا أنه لا تستطيع استخدام الفهرس معه: our_iterable[1] # Raises a TypeError تستطيع الحصول من خلال الكائن المُتعدد على كائن iterator منه بحيث تستطيع المرور على عناصره: our_iterator = iter(our_iterable) يحتفظ الكائن iterator بحالته كلما تم استخدامه، فمثلا، باستخدام وظيفة next تستطيع الحصول على العنصر التالي في هذا الكائن: next(our_iterator) # => "one" next(our_iterator) # => "two" next(our_iterator) # => "three" بعد الحصول على كافة عناصر iterator فإن استخدام الدالة next سيعيد خطأ: next(our_iterator) # Raises StopIteration تستطيع الحصول على كافة عناصر iterator دفعة واحدة على شكل قائمة وذلك باستخدام الدالة list : list(filled_dict.keys()) # => Returns ["one", "two", "three"] الدوال نستخدم الكلمة def في تعريف الدالة، ونستخدم كلمة return في إرجاع النتيجة: def add(x, y): print("x is {} and y is {}".format(x, y)) return x + y تطبع الدالة السابقة قيمتيْ المعامليْن المُمرّرين لها وتعيد ناتج جمعهما: add(5, 6) # => prints out "x is 5 and y is 6" and returns 11 يمكن أيضا استدعاء الدالة بذكر أسماء المعاملات (شرط الترتيب غير مطلوب هنا للمعاملات): add(y=6, x=5) تستطيع تعريف دالة باستقبال عددًا غير محدد من المعاملات: def varargs(*args): return args varargs(1, 2, 3) # => (1, 2, 3) من الممكن استخدام المعاملات المُسماة لاستقبال عدد غير محدد من المعاملات أيضا: def keyword_args(**kwargs): return kwargs keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} كما نستطيع دمج الطريقتين في نفس الدالة: def all_the_args(*args, **kwargs): print(args) print(kwargs) all_the_args(1, 2, a=3, b=4) # => (1, 2) {"a": 3, "b": 4} توجد طريقة أخرى لاستدعاء الدوال باستخدام args/kwargs وذلك عندما تكون المعطيات من النوع tuple أو قاموس: args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # equivalent to foo(1, 2, 3, 4) all_the_args(**kwargs) # equivalent to foo(a=3, b=4) all_the_args(*args, **kwargs) # equivalent to foo(1, 2, 3, 4, a=3, b=4) يمكن أيضا إرجاع نتيجة من قيم متعددة على شكل tuple: def swap(x, y): return y, x x = 1 y = 2 x, y = swap(x, y) # => x = 2, y = 1 يختلف المتغيّر في نطاق scope الدالة عن المتغيّرات العامة Global: x = 5 def set_x(num): x = num # => 43 print(x) # => 43 تُستخدَم الكلمة المفتاحية global لتعريف متغيّر عام من داخل الدالة: def set_global_x(num): global x print(x) # => 5 x = num # هذا المتغير يمثل المتغير على النطاق العام وقيمته الان 6 print(x) # => 6 set_x(43) set_global_x(6) تعدّ الدوال في بايثون كائنات من الفئة الأولى: def create_adder(x): def adder(y): return x + y return adder add_10 = create_adder(10) add_10(3) # => 13 كما يمكنك تعريف دوال غير مسمّاة Anonymous functions: (lambda x: x > 2)(3) # => True (lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 ويمكنك تمرير الدالة معاملا لدالة أخرى: list(map(add_10, [1, 2, 3])) # => [11, 12, 13] list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3] list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] تستطيع استخدام مبدأ “تفهيم القائمة” للحصول على نفس نتيجة الدوال map و filter: [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] تستطيع استخدام مبدأ “تفيهم القاموس” و “تفهيم المجموعة” كذلك: {x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} {x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} الوحدات Modules الوحدات في بايثون عبارة عن ملفات بايثون عادية. تستطيع أن تكتب الوحدة الخاصة بك وتستوردها في الشفرة البرمجة الخاصة بمشروعك. اسم الوحدة سيكون نفس اسم الملف الذي أنشأته لهذا الغرض. تُستورَد الوحدات بالطريقة التالية: import math print(math.sqrt(16)) # => 4.0 تستطيع الحصول على دوال محددة من الوحدات: from math import ceil, floor print(ceil(3.7)) # => 4.0 print(floor(3.7)) # => 3.0 تستطيع استيراد جميع الدوالّ من الوحدة دفعة واحدة ولكن هذا الأمر غير منصوح به: from math import * تستطيع اختصار أسماء الوحدات عند استيرادها: import math as m math.sqrt(16) == m.sqrt(16) # => True تُستخدَم الدالة المضمنة dir لمعرفة مكان ملف الوحدة. import math dir(math) إذا كان لديك ملف بايثون باسم math في نفس المجلد الذي يوجد به ملف العمل الخاص بك، فإن الملف math هو الذي سيُحمَّل ويُستورد بدلا من الوحدة التلقائية المضمنة في البايثون باسم math ذلك لأن الأولوية في حال تشابه الأسماء هي للملفات في مجلد العمل المحلي أو الحالي. دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن الأصناف Classes نستخدم كلمة class لتعريف صنف: class Human: لتعريف خاصية للصنف (هذه الخاصية تكون مُشاركة بين كل العناصر المتولدة من هذا الصنف): species = "H. sapiens" init هو المشيّدات Constructor الأساسي ويُستدعى عند توليد عنصر من الصنف. التسطير السفلي المكرر مرتين قبل كلمة init وبعدها يدل على أن هذا الكائن أو الخاصية يستخدمه بايثون ولا يجب علينا استخدامها مباشرة. def __init__(self, name): # إعطاء قيمة المعطى للخاصية الموجودة في الصنف self.name = name # قيمة مبدئية self._age = 0 الدالة say هي تابع عيّنة Instance method، أي أن لكل كائن نسخة خاصة به منها. تأخذ هذه التوابع أن self في أول معامل يُمرّر لها: def say(self, msg): print ("{name}: {message}".format(name=self.name, message=msg)) def sing(self): return 'yo... yo... microphone check... one two... one two...' يمكن أيضا تعريف تابع متشارك بين كل كائنات الصنف: @classmethod def get_species(cls): return cls.species نستطيع كذلك تعريف تابع ساكن يُستدعى دون الحاجة لإنشاء كائن من الصنف: @staticmethod def grunt(): return "*grunt*" يحوّل التعليمة property@ دالة إلى خاصيّة للقراءة فقط لها نفس اسم الدالة، لتؤدّي بالتالي وظيفة المسترجعات Getters. @property def age(self): return self._age يمكننا جعل الخاصية قابلة للتعيين لتصبح الدالة تعمل معدّلا Setter: @age.setter def age(self, age): self._age = age كما يمكننا السماح بحذفها: @age.deleter def age(self): del self._age يقوم مُفسر البايثون بتنفيذ كافة اشيفرة البرمجية في ملف الوحدة الذي يقرأه، ومن خلال الخاصية name نتأكد من أن كتلة الشفرة البرمجية التي في جملة الشرط ستُنفَّذ في حال كانت الوحدة هي البرنامج الرئيسي المُنفذ: if __name__ == '__main__': i = Human(name="Ian") i.say("hi") # "Ian: hi" j = Human("Joel") j.say("hello") # "Joel: hello" # استدعاء دالة الفئة i.say(i.get_species()) # "Ian: H. sapiens" # تغيير الخاصية المشتركة Human.species = "H. neanderthalensis" i.say(i.get_species()) # => "Ian: H. neanderthalensis" j.say(j.get_species()) # => "Joel: H. neanderthalensis" # استدعاء الدالة الساكنة print(Human.grunt()) # => "*grunt*" لا تستطيع استدعاء الدالة الساكنة من خلال العنصر المتولد i لأن استدعاءها بهذه الطريقة سيضيف self كمعامل لها مما سينتج عنه خطأ: print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given i.age = 42 i.say(i.age) # => "Ian: 42" j.say(j.age) # => "Joel: 0" del i.age # i.age # => this would raise an AttributeError ترجمة -وبتصرف- للمقال Learn X in Y minutes Where X=Python3 اقرأ أيضا: تعلم لغة بايثون1 نقطة
-
روبي هي لغة برمجة كائنيّة التوجّه بسيطة وقويّة في ذات الوقت، تم تطويرها في منتصف التسعينات بواسطة عالم الحاسوب Yukihiro Matsumoto والشهير باسم Matz. كان هدفه من تطوير اللغة جعل البرمجة أكثر متعةً وإنتاجيّة. تعمل اللُّغة على العديد من أنظمة التشغيل، مثل ويندوز، ماك والنسخ المختلفة من UNIX. مميزات لغة روبي مفتوحة المصدر ذات توجّهات عامّة (general purpose) كائنيّة التّوجّه ديناميكيّة ومفسّرة محمولة صيغة نظيفة مفتوحة المصدر كون اللّغة مفتوحة المصدر يعنى أنّه يوجد عدد غير منتهي من المطوّرين قائمين على اللّغة، وسرعة في معالجة الأخطاء. ذات توجهات عامة يعنى إمكانية استخدامها في أنواع مختلفة من البرامج، سواء في قواعد البيانات أو واجهات رسوميّة أو برامج علميّة أو الويب، إلى آخره. لغة كائنية التوجه الميزة هي أنّها الأسلوب الأفضل والآمن لتطوير البرمجيّات. دينامكية لن تكون مضطرًا أن تعلن عن نوع المتغير، بعكس لغات أخرى مثل Java. مفسرة بمعنى أنها تستخدم مفسّرًا وليس مترجمًا (المترجم: هو برنامج يقوم بتحويل الشيفرات البرمجيّة من لغة مثل C مثلاً إلى ملفّ تنفيذي. أمّا المفسر: هو برنامج يقوم بتنفيذ الشيفرات البرمجيّة سطرًا بعد سطر وهذا له مميزات وسلبيات. فمن المميزات هي المحموليّة على أكثر من نظام تشغيل وأكثر من بنية من العتاد. بعكس اللّغات المترجمة التي ستحتاج إلى إعادة ترجمة برنامجك كل مرّة لكل منصّة. من السلبيات، البطء وإمكانيّة الإطّلاع على الشيفرات البرمجيّة، إلّا أنّ هذا الأمر لا يعتبر مشكلة في عالم المصادر الحرة) المحمولية بمعنى أنّها مدعومة على العديد من النظم. وكذلك هي لغة بسيطة. Ruby on Rails لروبي قاعدة داعمين مخلصين في اليابان منذ بداية صدورها، إلا أنّ انطلاقتها الحقيقيّة كانت عند إطلاق David Heimmier Hansson لإطار العمل Ruby on Rails والذي يمكن اعتباره سبب شهرة روبي. يجعل إطار العمل Rails من إنشاء تطبيقات الويب عملاً سهلاً وممتعًا، وبديهيًّا فإنّ السبب وراء ذلك هو سهولة لغة روبي في الأساس. الكائنات Objects أحد أهم مبادئ روبي هي أنّ كل شيء في اللُّغة هو كائن. الكائن في البرمجة هو أي كيان له خصائصه المميّزة وأفعاله (المسمّاة دوال Methods). على سبيل المثال، اطّلع على الأسطر البرمجيّة التالية: "hello".reverse => "olleh" 6.even? => true [6,4,3,7].sort => [3,4,6,7] في السّطر الأول، كلمة hello هي كائن يمكن كتابته عكسيًّا بتطبيق الفعل/الدالّة reverse عليه. السّطر الثّاني يشير إلى إمكانيّة التحقّق ممّا إذا كان الرقم 6 (والذي هو كائن في روبي أيضًا) عددًا زوجيًّا أم لا. السّطر الثّالث يوضح أنّه يمكن ترتيب الأرقام تصاعديّا في قائمة باستخدام الدالة sort. تنصيب روبي نحتاج قبل البدء في استخدام روبي إلى تنصيبها أوّلاً. تختلف عمليّة التنصيب قليلاً باختلاف نظام التشغيل المستخدم، كذلك هناك العديد من الطرق لتنصيب روبي، اخترنا أبسطها. Windows إذا كنت تستخدم نظام التشغيل ويندوز فإنّ أفضل طريقة هي استخدام Ruby Installer، اضغط على زرّ Download وانتظر انتهاء التحميل، ثم افتح برنامج Ruby Installer واتّبع التعليمات، في أحد النوافذ سيظهر لك خيار Add Ruby executable to your path، أشّر عليه وتابع عمليّة التّنصيب مثلما تنصّب أي برنامج آخر على ويندوز. Mac إذا كنت تستخدم نظام التشغيل ماك فإنَّ روبي مثبَّتة عليه بشكل قياسي ولكن هناك احتمال كبير أنّ النسخة المثبَّتة ليست أحدث نسخة. لمعرفة نسخة روبي الموجودة لديك، افتح الطرفيّة (وذلك بالبحث عن Terminal وفتحه) واكتب الأمر التالي: ruby -v أبسط طريقة لتنصيب أحدث نسخة من روبي على نظام ماك هو استخدام مدير الحزم Homebrew. بعد تنصيب Homebrew على جهازك، اكتب الأمر التالي في الطرفيّة وسيقوم البرنامج بفعل كل شيءٍ لك: brew install ruby Linux إذا أردت إدارة نُسخ متعدِّدة من روبي على جهازك أو كنت تستخدم نظام لينكس فإنَّ الخيار الأمثل لديك هو استخدام مدير الإصدارات، هناك الكثير من هذه البرامج بما فيها (Ruby Version Manager (RVM. لكي تتمكّن من تنصيب روبي باستخدام RVM، افتح الطرفيّة واكتب الأمر التالي: \curl -L https://get.rvm.io | bash -s stable --ruby يمكنك بعد ذلك معرفة نسخ روبي المنصّبة على جهازك باستخدام أمر: rvm list بعد معرفة النسخ يمكنك تحديد النسخة التي تريدها أن تكون الافتراضيّة عن طريق كتابة أمر: rvm use [Ruby Version] –default حيث [Ruby Version] هو رقم النسخة، مثلا 2.0.0 أو غير ذلك. معرفة إصدار روبي على جهازك كما لاحظت وستلاحظ أيضًا مع تعمّقك في استخدام روبي أنّك ستحتاج في أغلب التنصيبات إلى استخدام الطرفيّة لتنفيذها. هذا الأمر شائع جدًا وستجد أنّك في كثيرٍ من الأحيان تستخدم الطرفيّة لتشغيل سكربتات وكتابة أوامر عندما تتعامل مع روبي. أتوقّع أنّك تعاملت مع الطرفيّة من قبل إذا كنت تستخدم أحد نظامي التشغيل ماك أو لينكس. ولكن على كلّ حال إذا لم تستخدم الطرفيّة من قبل فلا تقلق، ربّما تبدو صعبة في بادئ الأمر ولكن مع الوقت ستلاحظ مدى سهولتها وإنتاجيّتها. سنستخدم الآن الطرفيَّة للتحقُّق من أنّ عمليّة التنصيب تمّت بنجاح. اكتب السطر التالي: ruby -v إذا انتهى التنصيب بنجاح فسيظهر لك اسم نسخة روبي المنصّبة، كما هو ظاهر في الصورة أدناه، تخبرني الطرفيّة أنّ نسخة روبي الموجودة على حاسوبي هي ruby 2.2.3، وهي أحدث إصدار وقت كتابة هذا الدّرس. سطر أوامر روبي التفاعلي يوفّر سطر أوامر روبي التفاعلي (IRB) مجالاً لكتابة شيفرات روبي والحصول على نتائج لحظيًّة حيثُ يتمّ تنفيذ الأمر فور ضغطك على زرّ Enter. تأتي هذه الأداة مدمجة مع روبي، لذلك فلن تحتاج إلى عمليَّات تنصيب إضافيّة. سنجرّب الآن كتابة شيفرات برمجيّة بسيطة للتعرُّف على مدى سهولة اللُّغة في سطر أوامر روبي التفاعليّ والتي تعمل في الطرفيّة مباشرةً. للبدء، كل ما عليك فعله هو فتح الطرفيّة وكتابة أمر irb ثمّ الضغط على Enter. يؤدّي هذا إلى بدء جلسة IRB، أي أنّه الآن بإمكانك كتابة وتنفيذ أوامر روبي. لطباعة Hello World على الشاشة اكتب الأمر التالي: puts "Hello World" puts هو أمر في روبي وهو اختصار لـ put string والذي يطبع السلاسل النصيّة Strings. سلسلة "Hello World" هي كائن روبي يخزّن النصّ المكتوب بين علامتي التنصيص. لنجرّب استخدام الدالّة المذكورة سابقًا reverse على نص "Hello World". اكتب الأمر التالي: puts "Hello World".reverse ستلاحظ ظهور النصّ معكوسًا. النقطة الموجودة بعد السلسلة هي الطريقة التي نضيف بها الدوال إلى الكائنات في روبي. ربّما تريد أن تجرّب الدالّة على نصوص مختلفة أيضًا لفهم طريقة عملها أكثر. العمليات الحسابية يمكن لروبي التعامل مع الأرقام أيضًا فيمكننا إجراء عمليّات حسابيّة مختلفة. جرّب العمليّات الحسابيّة التالية أو عمليّات حسابيّة أخرى من اختيارك: 1 + 1 5 – 7 * 2 456549 * 45 + 23543 كما ذكرنا سابقًا فإنّ روبي تعتبر أن كلّ شيء هو كائن، فالأرقام في روبي إذًا هي كائنات لها خصائص ودوال. اكتب السطر التالي ولاحظ ما سيظهر لك: 2.even? ستجيب عليك روبي true، نعم اثنان هو رقم زوجي (even). لاحظ مدى سهولة لغة روبي. لو عرضت السطر السابق على شخص لا يعرف شيئًا على البرمجة، بنسبة كبيرة جدًا سيفهم المقصود منه. تسمّى القوائم الموجودة بين أقواس مربّعة بالمصفوفة Array. إليك مثال على مصفوفة تحتوي على بعض الأرقام: [2, 7, 4, 8] بديهيًّا فهذه المصفوفة هي كائن، وبالتّالي فهناك دوالّ خاصّة بها. لنجّرب دالّة sort. أضف .sort إلى نهاية المصفوفة: [2, 7, 4, 8].sort ماذا حدث بعد كتابة الأمر؟ تم ترتيب المصفوفة تصاعديًّا. لأنّ الدّالة sort وكما يوضّح اسمها تُرتّب المصفوفة التي تعمل معها ترتيبًا تصاعديًا. العبارات المنطقية مثال آخر على مدى سهولة ووضوح روبي، اكتب السطر التالي في جلسة IRB لديك ثم اضغط Enter: 4.times do لن يحدث شيء ولكن ستلاحظ ظهور علامة (*) بدلاً من علامة (<) بعد رقم السّطر. هذه العلامة توضّح أنّنا لا زلنا في مرحلة كتابة الشيفرات البرمجيّة، بمعنى آخر أنّ الشيفرات البرمجيّة لم تنته بعد. اكتب شيئًا مثل التّالي أو اطبع نصًّا آخر من اختيارك ثمّ اضغط Enter: puts "Ruby is so easy" نهايةً اكتب end في السطر الجديد واضغط Enter لإنهاء مرحلة الإدخال. ربّما يمكنك تخمين ماذا تفعل هذه الشيفرات البرمجيّة قبل حتّى تشغيلها. نحن ببساطة نخبر روبي أن تفعل أمرًا لعددٍ من المرّات. في هذا المثال، نطلب من اللُّغة طباعة النصّ الموجود بين علامتي التنصيص 4 مرّات. إذا لم تفهم ما المقصود تمامًا في الفقرة السّابقة فالمطلوب أن نكتب الأسطر التالية (سطرًا بعد الآخر): 4.times do puts "Ruby is so easy" end كتابة برنامج روبي الآن وبعد أن رأينا كيف تعمل روبي في سطر أوامر روبي التفاعليّ فقد حان الوقت لكتابة روبي وحفظها في ملفّ. افتح محرّر النصوص المفضّل لديك، لا تحتاج إلى برنامج معيّن لكتابة روبي، مجرّد محرّر نصوص بسيط يفي بالغرض. ولكن يفضّل اختيار محرّر نصوص يدعم خاصيّة تعليم الصيغة وتلوينها syntax highlighting. بعض الاقتراحات: Notepad++، Sublime Text. للبدء كل ما علينا فعله هو كتابة ما يلي في الملفّ: puts "Hello World" لاحظ أنّ هذه الشيفرة البرمجيّة مشابهة تمامًا لما كتبناه سابقًا في سطر أوامر روبي التفاعليّ، وبالتّالي فيجب أن نتوقّع نتائج مشابهة عند تشغيل البرنامج. لتشغيل البرنامج علينا أوّلاً حفظ الملفّ. أقترح عليك إنشاء مجلّد باسم learnRuby أو أيّ اسم آخر لحفظ ملفّات روبي التي سنعمل عليها في هذه السلسلة، احفظ الملف باسم hello.rb أو أيّ اسم آخر مع وجوب إضافة rb. في آخره حيث rb. هو الامتداد المستخدم لكلّ سكربتات روبي. بعد حفظ الملفّ، افتح الطرفيّة واذهب إلى المجلّد الذي قمت بحفظ الملفّ به عن طريق كتابة الأمر التالي: cd [file path] حيث file path هو مسار الملفّ. مثلاً إذا قمت بحفظ الملفّ في مجلّد learnRuby في C على ويندوز فالمسار سيكون C:\learnRuby وبالتّالي سيكون الأمر: cd C:\learnRuby بعد التوجّه إلى المجلّد الذي يحتوي على الملفّ نقوم بتشغيل البرنامج، كل ما علينا فعله هو كتابة: ruby hello.rb بعد تنفيذ الأمر ستلاحظ ظهور النصّ المكتوب، نفس العمليّة التي قمنا بها في سطر أوامر روبي التفاعليّ. الفرق الوحيد بين كتابة روبي في ملف وبين كتابتها في سطر أوامر روبي التفاعليّ هو أن سطر أوامر روبي التفاعليّ ينفّذ أمر روبي في كل مرّة نضغط Enter. أمّا كتابة شيفرات روبي في ملفّات يسمح لك بكتابة أكثر من سطر أوامر والتي ستُنفّذّ جميعًا عند تشغيل البرنامج. يمكننا التحقُّق من ذلك بالعودة إلى الملفّ المستخدم وإضافة أوامر أخرى. مثلاً، جرّب الأوامر التالية أسفل الأمر الموجود في الملفّ: puts 1 + 1 3.times do puts "Ruby" end احفظ الملف، وأعد تشغيله كما فعلت من قبل، ماذا تلاحظ؟ بمجرّد الضغط على Enter نحصل على نتيجة تنفيذ جميع الشيفرات البرمجيّة مرّة واحدة. التعليقات في روبي مع زيادة حجم الشيفرات البرمجيّة وتعقيدها، سيصبح من الصعوبة قراءتها وفهمها. لهذا السبب فمن المفيد إضافة ملاحظات إلى برنامجك لتوضيح وظيفة أجزاء البرنامج لك ولأي مبرمج آخر سيقرأ هذه الشيفرات فيما بعد. تسمّى تلك الملاحظات تعليقات. تبدأ التعليقات في روبي برمز التلبيد Hash (#) وكل ما يأتي بعد هذا الرمز يتمّ تجاهله ولا يُنفّذ. جرّب كتابة تعليق في ملفّ hello.rb وأعد تشغيل البرنامج. تحقّق هل حدث اختلاف في النتائج أم لا. مثال على تعليق: # هذا البرنامج يطبع حاصل ضرب الرقمين 3 * 4 puts 3 * 4 ختام تعرّفنا في هذا الدّرس على مدى بساطة روبي وقربها من الإنجليزيّة العاديّة، ما يميّزها عن لغات البرمجة الأخرى وكيف يمكن تنصيب وبدء البرمجة باستخدامها. كذلك تعرّفنا على بعض المفاهيم الخاصّة باللّغة والتي إن لم تفهمها فلا تقلق، ليس من المفترض أن تعرف كلّ هذا حيث أنّنا سنستعرض هذا كلّه باستفاضة في الدروس القادمة من هذه السلسلة. إذا استعصى عليك أمر أو واجهت مشكلة، لا تتردد في السؤال عنها في قسم التعليقات أدناه. *مصدر المعلومات: ويكيبيديا.1 نقطة