تصف التعليمات الشرطية في البرمجة قدرتنا على تنفيذ تسلسل واحد من بين عدة تسلسلات محتملة من الشيفرات -التي تمثل الفروع- وفقًا لوقوع حدث ما، وقد كانت أبسط صورة لتلك التعليمات الشرطية في الأيام الأولى لاستخدام لغة التجميع Assembly هي تعليمة JUMP
التي تجعل البرنامج يقفز إلى عنوان ما في الذاكرة، غالبًا عندما يكون ناتج التعليمة السابقة صفرًا، وقد استُخدمت هذه التعليمة في برامج بالغة التعقيد، دون استخدام أي صورة شرطية أخرى وقتها، ليؤكد هذا قول ديكسترا Dijkstra عن الحد الأدنى المطلوب للبرمجة، ثم ظهرت نسخة جديدة من تعليمة JUMP
مع تطور لغات البرمجة عالية المستوى، وهي GOTO
، التي لا تزال متاحةً حتى الآن في لغة QBASIC، والتي يمكن تحميلها واستخدامها من www.qbasic.net، لننظر إلى الشيفرة التالية مثلًا -بعد تثبيت QBASIC-:
10 PRINT "Starting at line 10" 20 J = 5 30 IF J < 10 GOTO 50 40 PRINT "This line is not printed" 50 STOP
لاحظ كيف تحتاج إلى بضع ثوان لتعرف الخطوة التالية رغم صغر البرنامج، إذ لا يوجد هيكل للشيفرة، بل عليك أن تكتشف ما يفعله البرنامج بينما تقرؤه بنفسك، وهذا الأمر مستحيل في البرامج كبيرة الحجم، لهذا لا تحتوي أغلب لغات البرمجة الحديثة بما فيها لغة بايثون وجافاسكربت وVBScript، على تعليمة JUMP أو GOTO بحيث يمكن استخدام أي منهما مباشرةً، وإن وجدت فستحثك اللغة على عدم استخدامها، فما العمل إذًا في حالة البرمجة الشرطية؟.
تعليمة if الشرطية
إن أول ما يرد إلى الذهن عند التفكير في حالات شرطية هي البنية if.. then.. else
، والتي تعني "إذا حدث س، فسيكون ص، وإلا سيكون ع"، فهي تتبع منطقًا لغويًا بحيث إذا تحقق شرط بولياني ما -أي كان true-، فستُنفَّذ كتلة من التعليمات، وإلا ستنفَّذ كتلة أخرى.
بايثون
إذا أردنا كتابة مثال GOTO السابق بلغة بايثون، فسيبدو كما يلي:
import sys # فقط exit لنستطيع استخدام print( "Starting here" ) j = 5 if j > 10: print( "This is never printed" ) else: sys.exit()
هذه الصورة أسهل من سابقتها في القراءة وفهم المراد منها، ونستطيع وضع أي شرط اختباري نريده بعد تعليمة if
، طالما أنه يقيَّم إلى True
أو False
، جرب تغيير علامتي >
و <
وانظر ما سيحدث.
لاحظ النقطتين الرأسيتين :
في نهاية سطري التعليمتين if
وelse
، إذ تخبرنا هاتان النقطتان أن ما يليهما كتلة مستقلة من الشيفرة، بينما تخبرنا إزاحة تلك الكتلة ببدايتها ونهايتها.
VBScript
سيبدو المثال السابق في VBScript كما يلي:
<script type="text/vbscript"> MsgBox "Starting Here" DIM J J = 5 If J > 10 Then MsgBox "This is never printed" Else MsgBox "End of Program" End If </script>
يكاد يكون هذا المثال مطابقًا لمثال بايثون، مع فرق أن كلمة Then
مطلوبة للكتلة الأولى، وأننا نستخدم End If
لنعلن نهاية بنية if/then، ولعلك تذكر أننا استخدمنا كلمة Loop
لإنهاء حلقة Do While
في مثال VBScript من مقال سابق، ذلك أن VBScript تستخدم في اصطلاحها محددًا لنهاية التعليمة.
جافاسكربت
يبدو مثال if
في جافاسكربت كما يلي:
<script type="text/javascript"> var j; j = 5; if ( j > 10 ){ document.write("This is never printed"); } else { document.write("End of program"); } </script>
لاحظ أن جافاسكربت تستخدم أقواسًا معقوصةً لتحديد كتل الشيفرات الموجودة داخل الجزء الخاص بتعليمة if
والجزء الخاص بتعليمة else
، وأن الاختبار البولياني يوجد بين قوسين، وليس هناك استخدام صريح لكلمة then
.
من المنظور الجمالي للتنسيق، يمكن وضع الأقواس المعقوصة في أي مكان، لكننا اخترنا صفها كما في المثال لإبراز بنية الكتلة البرمجية، ويمكن إهمال الأقواس المعقوصة كليًا إذا كان لدينا سطر واحد فقط داخل الكتلة كما في حالتنا هذه، لكن يفضل بعض المبرمجين وضعها للحفاظ على اتساق الكتابة، ولاحتمال إضافة سطر آخر مستقبلًا، فوضعها الآن أفضل من نسيانها لاحقًا.
التعابير البوليانية
لعلك تذكر أننا ذكرنا في مقال البيانات وأنواعها، نوعًا من البيانات اسمه النوع البولياني، وقلنا إن هذا النوع لا يحوي إلا قيمتين فقط، هما True
وFalse
، ورغم أننا لا ننشئ متغيرًا بوليانيًا إلا نادرًا، إلا أننا نحتاج إلى إنشاء قيم بوليانية مؤقتة باستخدام التعابير، والتعبير هو تجميعة من المتغيرات و/أو القيم، تجمعها معًا عوامل لإخراج قيمة ناتجة، لننظر إلى المثال التالي:
if x < 5:
print( x )
التعبير هنا هو x < 5
، والنتيجة ستكون True
إذا كانت x أقل من 5، وFalse
إذا كانت x أكبر من (أو تساوي) 5.
قد تكون التعابير معقدةً بما أنها تقيَّم إلى قيمة نهائية وحيدة، إذ يجب أن تكون تلك القيمة True
أو False
في حالة الفرع، لكن يختلف تعريف هاتين القيمتين من لغة لأخرى، فأغلب اللغات تساوي بين القيمة False
وبين الصفر أو القيمة غير الموجودة أو غير المعرفة والتي تدعى NULL
أو Nil
أو None
، وبناءً على ذلك تقيَّم القائمة الفارغة أو السلسلة النصية الفارغة إلى false في السياق البولياني وتعتمد بايثون هذا السلوك، مما يعني أننا نستطيع استخدام حلقة while
لمعالجة القائمة إلى أن تصبح فارغةً، بالشكل التالي:
while aList: # افعل شيئًا هنا
أو يمكن استخدام تعليمة if
لننظر هل القائمة فارغة أم لا، دون اللجوء إلى دالة len()
كما يلي:
if aList: # افعل شيئًا هنا
يمكن جمع عدة تعابير بوليانية باستخدام عوامل بوليانية كذلك، والتي تقلل من عدد تعليمات if
التي علينا كتابتها، كما في المثال التالي:
if value > maximum: print( "Value is out of range!" ) else if value < minimum: print( "Value is out of range!" )
لاحظ أن كتلة الشيفرة التي يجب تنفيذها متطابقة في شرطي المثال أعلاه، ويمكن أن نوفر على أنفسنا بعض الكتابة وعلى الحاسوب بعض العمل، بأن نجمع الاختبارين في اختبار واحد كما يلي:
if (value < minimum) or (value > maximum): print( "Value is out of range!" )
لاحظ كيف جمعنا الاختبارين باستخدام عامل or
البولياني، وبما أن بايثون تقيِّم مجموعة الاختبارات المجمعة تلك إلى نتيجة واحدة؛ فنستطيع القول أن هذين التعبيرين إنما هما تعبير واحد، ونستطيع استيعاب هذا الأسلوب إذا عرفنا أننا نقيّم المجموعة الأولى من الأقواس أولًا، ثم نقيّم المجموعة الثانية، ثم نجمع القيمتين الناتجتين لنشكل قيمةً نهائيةً وحيدةً تكون إما True أو False. تستخدم بايثون أسلوبًا أكثر كفاءةً من هذا يُعرف بالتقييم المقصور أو تقييم الدارة المقصورة short-circuit evaluation، وإذا تأملنا في هذه الاختبارات، فسنجد أننا نفكر فيها بالمنطق اللغوي البشري الذي يستخدم حروف العطف مثل ("و" "and") و("أو" "or") و("النفي" "not")، مما يتيح لنا كتابة اختبار واحد مجمَّع بدلًا من عدة اختبارات منفصلة، كما سنرى فيما يلي.
تعليمات if المتسلسلة
يمكن سَلسَلة تعليمات "if..then..else" معًا بجعلها متشعبةً، بحيث تتداخل كل واحدة مع الأخرى، لننظر مثالًا على ذلك في بايثون:
# افترض أن السعر قد حُدد مسبقًا... price = int(input("What price? ")) if price == 100: print( "I'll take it!" ) else: if price > 500: print( "No way!" ) else: if price > 200: print( "How about throwing in a free mouse mat?" ) else: print( "price is an unexpected value!" )
لاحظ أننا استخدمنا ==
المزدوجة لاختبار التساوي في تعليمة if
الأولى، بينما استخدمنا علامة =
مفردةً لإسناد القيم إلى المتغيرات، وهذا الخطأ شائع جدًا في الكتابة بلغة بايثون، لأنه يعارض المنطق الرياضي الذي تعودنا عليه، وبايثون تحذرك من أن هذا خطأ لغوي syntax error، وعليك النظر والبحث لإيجاده.
ننفذ اختبار "أكبر من" بدءًا من القيمة العظمى إلى الصغرى، فإذا عكسنا هذا المنطق، أي بدأنا من price > 200
فستتحقق التعليمة دومًا ولن ننتقل إلى اختبار > 500
، وبالمثل يجب أن يبدأ استخدام تسلسل اختبارات "أقل من" من القيمة الصغرى ثم ننتقل إلى العظمى، وهذا أيضًا أحد الأخطاء الشائعة في البرمجة ببايثون.
جافاسكربت وVBScript
يمكن أن نسلسل تعليمات if
في جافاسكربت وVBScript أيضًا، لكننا لن نشرح إلا VBScript لأن المثال واضح:
<script type="text/vbscript"> DIM Price price = InputBox("What's the price?") price = CInt(price) If price = 100 Then MsgBox "I'll take it!" Else If price > 500 Then MsgBox "No way Jose!" Else If price > 200 Then MsgBox "How about throwing in a free mouse mat too?" Else MsgBox "price is an unexpected value!" End If End If End If </script>
يجب ملاحظة وجود تعليمة End If
مطابقة لكل تعليمة If
، واستخدامنا لدالة التحويل CInt
الخاصة بلغة VBScript لتحويل الدخل من سلسلة نصية إلى عدد صحيح.
تعليمات الحالة Switch/Case
تتسبب إزاحة الشيفرات بملء الصفحة بسرعة، وهو أحد مساوئ سلسلة تعليمات if/else
أو تشعبها، لكن شيوع هذا التسلسل المتشعب في البرمجة جعل كثيرًا من اللغات توفر نوعًا آخر من التفريع خاصًا بها، ويشار إليه عادةً باسم تعليمة Case
أو Switch
، التي تبدو في جافاسكربت كما يلي:
<script type="text/javascript"> function doArea(){ var shape, breadth, length, area; shape = document.forms["area"].shape.value; breadth = parseInt(document.forms["area"].breadth.value); len = parseInt(document.forms["area"].len.value); switch (shape){ case 'Square': area = len * len; alert("Area of " + shape + " = " + area); break; case 'Rectangle': area = len * breadth; alert("Area of " + shape + " = " + area); break; case 'Triangle': area = len * breadth / 2; alert("Area of " + shape + " = " + area); break; default: alert("No shape matching: " + shape) }; } </script> <form name="area"> <label>Length: <input type="text" name="len"></label&lgt; <label>Breadth: <input type="text" name="breadth"></label> <label>Shape: <select name="shape" size=1 onChange="doArea()"> <option value="Square">Square <option value="Rectangle">Rectangle <option value="Triangle">Triangle </select> </label> </form>
لا تقلق من حجم الشيفرة أعلاه، فما هي إلا امتداد لما شرحناه في المقالات السابقة وإن زاد حجمه قليلًا.
تحتوي استمارة HTML التي في آخر الشيفرة على حقلين نصيين لإدخال الطول length و العرض breadth، أما حقل الإدخال الثالث فهو قائمة منسدلة من القيم التي ألحقناها بسمة onChange
التي تستدعي دالةً ما، وكل تلك الحقول لديها عناوين labels
مرتبطة.
تسمح شيفرة الاستمارة في HTML بالتقاط التفاصيل والبيانات، ثم تستدعي دالة جافاسكربت حين يختار المستخدم أحد الأشكال، وبما أننا لم نشرح الدوال بعد، فيكفي أن تعلم الآن أن الدالة هي برنامج صغير تستدعيه البرامج الأخرى، وفي حالتنا هذه عرَّفنا تلك الدالة في أول الشيفرة.
تنشئ الأسطر الأولى بعض المتغيرات المحلية، وتحوِّل سلاسل الإدخال النصية إلى أعداد صحيحة عند الحاجة، وما نريده هو تعليمة switch
، التي تختار الإجراء المناسب وفقًا لقيمة الشكل.
لاحظ أن الأقواس التي حول shape
ضرورية، ولا تُحدَّد كتل الشيفرة التي داخل بنية case
باستخدام الأقواس المعقوصة كما هو متوقع، فإذا أردنا إنهاءها، فسنستخدم تعليمة break
؛ أما مجموعة تعليمات case
الخاصة بـ switch
فهي مرتبطة معًا مثل كتلة واحدة بين قوسين معقوصين.
يلتقط الشرط الأخير default
أي شيء لم تلتقطه تعليمات case
السابقة.
جرب توسيع المثال السابق ليشمل الدوائر، وتذكر أن تضيف خيارًا جديدًا إلى القائمة المنسدلة في استمارة HTML وتعليمة case
جديدة إلى switch
.
بنية Case الاختيارية في VBScript
تحتوي لغة VBscript على بنية case كما يلي:
<script type="text/vbscript"> Dim shape, length, breadth, SQUARE, RECTANGLE, TRIANGLE SQUARE = 0 RECTANGLE = 1 TRIANGLE = 2 shape = CInt(InputBox("Square(0),Rectangle(1) or Triangle(2)?")) length = CDbl(InputBox("Length?")) breadth = CDbl(InputBox("Breadth?")) Select Case shape Case SQUARE area = length * length MsgBox "Area = " & area Case RECTANGLE area = length * breadth MsgBox "Area = " & area Case TRIANGLE area = length * breadth / 2 MsgBox "Area = " & area Case Else MsgBox "Shape not recognized" End Select </script>
تجمع الأسطر الأولى البيانات من المستخدم وتحولها إلى النوع المناسب، تمامًا مثلما يحدث في جافاسكربت، وتظهر تعليمة select
بنية case
الخاصة بلغة VBScript، حيث تنهي كل تعليمة Case
الكتلة التي سبقتها، كذلك لدينا فقرة Case Else
التي تلتقط أي شيء لم تلتقطه تعليمات Case
التي سبقتها، كما في حالة default
في جافاسكربت.
وكما تعودنا في أسلوب VBScript في التنسيق، فإن الشيفرة تغلَق بتعليمة End select
.
ربما تجب الإشارة إلى استخدام الثوابت الرمزية بدلًا من الأعداد، أي استخدام المتغيرات SQUARE
وRECTANGLE
وTRIANGLE
، لأنها تجعل الشيفرة أسهل في القراءة، كما أن استخدام الأحرف الكبيرة هو اصطلاح لبيان كونها قيمًا ثابتةً وليست متغيرات، مع أن VBScript تسمح بأي أسماء نريدها للمتغيرات.
الاختيار المتعدد في بايثون
لا توفر بايثون بنية case
صراحةً، وإنما تعوضنا عن ذلك بتوفير صيغة مضغوطة من if/else-if/else
:
menu = """ Pick a shape(1-3): 1) Square 2) Rectangle 3) Triangle """ shape = int(input(menu)) if shape == 1: length = float(input("Length: ")) print( "Area of square = ", length ** 2 ) elif shape == 2: length = float(input("Length: ")) width = float(input("Width: ")) print( "Area of rectangle = ", length * width ) elif shape == 3: length = float(input("Length: ")) width = float(input("Width: ")) print( "Area of triangle = ", length * width/2 ) else: print( "Not a valid shape, try again" )
لاحظ استخدام elif
، وعدم تغير الإزاحة على عكس مثال تعليمة if
المتشعبة، وتجدر الإشارة إلى أنه لا فرق بين استخدام if
المتشعبة أو elif
، فكلاهما صالح، كما أنهما تؤديان نفس الغرض، غير أن elif
أيسر في القراءة إذا كان لدينا عدة اختبارات.
أما الشرط الأخير فهو else
التي تلتقط أي شيء لم تلتقطه الاختبارات السابقة، كما في default
في جافاسكربت وCase Else
في VBScript.
توفر VBScript نسخةً معقدةً من هذه التقنية هي ElseIf...Then
التي تُستخدم بنفس طريقة elif
في بايثون، لكنها غير شائعة بما أن Select Case
أسهل استخدامًا.
إيقاف الحلقة التكرارية
يغطي هذا الجزء استخدامًا خاصًا للتفريع كنا نريد شرحه في مقال الحلقات التكرارية، لكن اضطررنا إلى الانتظار حتى شرح تعليمات if، لذا نعود الآن إلى موضوع الحلقات التكرارية لنرى كيف يمكن أن يحل التفريع مشكلةً شائعةً فيها، فقد نريد الخروج من حلقة تكرارية قبل أن تنتهي. توفر أغلب اللغات آليةً لإيقاف تنفيذ الحلقة، وفي بايثون تكون تلك الآلية هي كلمة break
، ويمكن استخدامها في حلقتي for
وwhile
. تُستخدم هذه الكلمة غالبًا عند البحث في قائمة عن قيمة ما وإيجادها، عندها لا نريد متابعة البحث إلى نهاية الحلقة، كما تُستخدم إذا اكتشفنا خللًا في البيانات، أو إذا قابلنا شرط خطأ error condition؛ أما أكثر الاستخدامات شيوعًا خاصةً في بايثون التي اعتُمد فيها هذا السلوك لكثرة استخدامه، فهو عند قراءة الدخل باستخدام حلقة while
.
في مثالنا التالي سنستخدم كلمة break
للخروج من الحلقة عندما نقابل أول قيمة صفرية في قائمة من الأعداد:
nums = [1,4,7,3,0,5,8] for num in nums: print( num ) if num == 0: break # اخرج من الحلقة فورًا print("We finished the loop")
في المثال السابق نستطيع رؤية كيفية اختبار شرط الخروج في تعليمة if
، ثم استخدام break
للقفز خارج الحلقة. تحتوي جافاسكربت على الكلمة المفتاحية break
لإيقاف الحلقات التكرارية، وتُستخدم بنفس الطريقة المستخدمة في بايثون؛ أما VBScript، فتستخدم الكلمات Exit For
أو Exit Do
للخروج من حلقاتها التكرارية.
اقتباستوجد كلمة قريبة في سلوكها من
break
، وهيcontinue
غير أنها أقل استخدامًا منها، ووظيفتها الخروج من متن الحلقة فقط، بدلًا من إنهاء الحلقة بالكلية، حيث تقفز إلى بداية الحلقة التكرارية وتبدأ التكرار التالي، قد يكون هذا مفيدًا إذا أردنا معالجة أنواع بعينها من البيانات مثلًا، لكن يمكن الحصول على نفس النتيجة بشرطif
داخل الكتلة البرمجية، تحتوي بايثون وجافاسكربت على كلمةcontinue
، على عكس VBScript.
الجمع بين الشروط والحلقات التكرارية
بما أن الأمثلة التي أوردناها سابقًا كانت نظريةً وتجريديةً، فسننظر الآن في مثال يستخدم كل ما تعلمناه سابقًا لنشرح تقنيةً شائعةً في البرمجة، وهي عرض القوائم للتحكم في مدخلات المستخدم، لنرى الشيفرة أولًا ثم نشرحها:
menu = """ Pick a shape(1-3): 1) Square 2) Rectangle 3) Triangle 4) Quit """ shape = int(input(menu)) while shape != 4: if shape == 1: length = float(input("Length: ")) print( "Area of square = ", length ** 2 ) elif shape == 2: length = float(input("Length: ")) width = float(input("Width: ")) print( "Area of rectangle = ", length * width ) elif shape == 3: length = float(input("Length: ")) width = float(input("Width: ")) print( "Area of triangle = ", length * width / 2 ) else: print( "Not a valid shape, try again" ) shape = int(input(menu))
لقد زدنا ثلاثة أسطر على مثال بايثون السابق، وهي:
4) Quit while shape != 4: shape = int(input(menu))
لكن هذه الأسطر الثلاثة جعلت البرنامج أكثر سهولةً، فقد مكنّا المستخدم من استمرار حساب أحجام الأشكال المختلفة إلى أن يجمع كل المعلومات التي يريدها، وذلك بإضافة الخيار Quit
إلى القائمة وحلقة while
، كما لا نحتاج الآن إلى إعادة تشغيل البرنامج يدويًا في كل مرة.
أما السطر الثالث الذي أضفناه فقد كان لتكرار عملية اختيار الشكل input(menu)
ليتمكن المستخدم من تغيير الشكل والخروج من البرنامج إذا أراد.
يوهم هذا البرنامج المستخدم بأنه يعرف ما يرغب به وينفذه له، ويختلف سلوك البرنامج في كل مرة باختلاف مدخلات المستخدم، مما يجعل المستخدم يبدو وكأنه هو المتحكم بينما يكون المتحكم الحقيقي هو المبرمج، لأنه توقع جميع المدخلات الصالحة وجعل البرنامج يتفاعل معها، فتكون العبقرية الحقيقية هنا للمبرمج وليس للبرنامج أو الحاسوب، فالحواسيب غبية كما ذكرنا من قبل.
تتضح الآن سهولة توسعة وظائف برنامجنا بمجرد إضافة بعض الأسطر ودمج تسلسلات -الكتل البرمجية التي تحسب مساحات الأشكال-، والحلقات التكرارية -حلقة while
-، والتعليمات الشرطية -بنية if
/ elif
-، وبهذا نكون قد أنهينا الوحدات الثلاث الأساسية التي تتكون منها البرمجة وفقًا لديكسترا، ونستطيع الآن برمجة أي شيء، من الناحية النظرية، بما أننا تعلمنا هذه الوحدات، غير أننا لا زلنا بحاجة إلى تقنيات أخرى لنتعرف على كيفية تسهيل كتابة البرامج على أنفسنا.
مبدأ DRY: لا تكرر نفسك
إحدى المزايا التي نريد الإشارة إليها في هذا البرنامج هو أننا اضطررنا إلى تكرار سطر input()
مرةً قبل الحلقة ومرةً داخلها؟ ولا يفضَّل تكرار الشيفرة البرمجية نفسها أكثر من مرة، لأننا سنضطر إلى تذكر تغيير كلا السطرين إذا احتجنا إلى تعديلها أو تغييرها، مما يفسح مجالًا للخطأ والنسيان، وهنا يمكن استخدام حيلة مبنية على خاصية break
التي تحدثنا عنها في مقال الحلقات التكرارية في البرمجة، حيث نجعل في هذه الحيلة حلقة while
حلقةً لا نهائية، ثم نختبر شرط الخروج، ونستخدم break
للخروج منها، انظر إلى المثال التالي:
menu = """ Pick a shape(1-3): 1) Square 2) Rectangle 3) Triangle 4) Quit """ while True: shape = int(input(menu)) if shape == 4: break if shape == 1: length = float(input("Length: ")) print( "Area of square = ", length ** 2 ) elif shape == 2: length = float(input("Length: ")) width = float(input("Width: ")) print( "Area of rectangle = ", length * width ) elif shape == 3: length = float(input("Length: ")) width = float(input("Width: ")) print( "Area of triangle = ", length * width / 2 ) else: print( "Not a valid shape, try again" )
يسمى تقليل التكرار هذا، والذي يبدو بدهيًا في أوساط المبرمجين، باسم مبدأ DRY، وهو اختصار لـ: "لا تكرر نفسك Dont Repeat Yourself".
التعابير الشرطية
توجد صورة أخرى من التفريع شائعة جدًا في البرمجة، عندما نريد إسناد قيمة مختلفة إلى متغير وفقًا لشرط ما، ويمكن فعل هذا بسهولة باستخدام شرط if/else
كما يلي:
if someCondition: value = 'foo' else: value = 'bar'
إلا أن لغات البرمجة توفر اختصارًا لذلك، وهو ما يسمى ببنية التعبير الشرطي، ويبدو في بايثون كما يلي، وهو مطابق تمامًا في وظيفته للشيفرة أعلاه:
value = 'foo' if شرط ما else 'bar'
لا تحتوي VBScript على مثل هذه البنية، وتوفر جافاسكربت شيئًا شبيهًا بها، لكن البنية اللغوية له مبهمة قليلًا:
<script type="text/javascript"> var someCondition = true; var s; s = (someCondition ? "foo" : "bar"); document.write(s); </script>
لاحظ البنية الغريبة للشرط بين القوسين ()
، الذي له نفس وظيفة الأمثلة السابقة في بايثون، إلا أنه يستخدم مجموعةً مختصرةً من الرموز، وهو يقول: "إن تحقق التعبير الذي يسبق علامة الاستفهام وكان true، فأعد القيمة التي بعد علامة الاستفهام، وإلا فأعد القيمة التي بعد النقطتين الرأسيتين". لا يُعَد القوسان ضروريين في هذا المثال رغم استخدامنا لهما، لأنهما يوضحان للقارئ ما يحدث في الشيفرة، ويُنصح باستخدامهما حتى في التعبيرات الشرطية في بايثون.
إن مثل هذه الاختصارات تبدو جماليةً مريحةً في استخدامها، لكن كثيرًا من المبرمجين ينأون عنها ويرونها غير عملية، لذا يجب استخدمها متى كان وجودها ضروريًا ومتى دعت الحاجة إليها، ويُفضل تجنبها إذا جعلت الشيفرة تبدو معقدةً أكثر من اللازم.
تعديل التجميعات من داخل الحلقات التكرارية
لقد ذكرنا في مقال الحلقات التكرارية في البرمجة أن تعديل التجميعة collection من داخل حلقة تكرارية أمر صعب، لكن لم نشرح كيفية تعديلها وقتها، إذ أردنا الانتظار حتى نشرح التفريع أولًا، وقد أتى وقت بيان ذلك، يمكن استخدام حلقة while
لتنفيذ التعديلات أثناء التكرار على التجميعة نفسها، وهذا ممكن لأننا نستطيع التحكم الصريح في الفهرس داخل بنية while
على عكس حلقة for
التي يحدَّث الفهرس فيها تلقائيًا. لننظر الآن كيف نحذف جميع الأصفار من قائمة ما:
myList = [1,2,3,0,4,5,0] index = 0 while index < len(myList): if myList[index] == 0: del(myList[index]) else: index += 1 print( myList )
تجدر الإشارة هنا إلى أننا لا نزيد الفهرس عند حذف عنصر، بل تحرك عملية الحذف باقي العناصر للأعلى كي يشير الفهرس القديم إلى العنصر التالي في التجميعة.
سنستخدم فرع if/else
لنتحكم في وقت زيادة الفهرس، ويسهل هنا ارتكاب خطأ في تنفيذ مثل هذا التعديل، لذا احرص على اختبار شيفرتك جيدًا، هناك مجموعة أخرى من دوال بايثون مصممة خصيصًا لتعديل محتويات القائمة، وسننظر فيها في مقال لاحق.
خاتمة
في نهاية هذا المقال نريد التذكير بما يلي:
-
استخدم
if/else
لتفريع مسار البرنامج. -
استخدام
else
أمر اختياري يعود إليك. -
يمكن تمثيل القرارات المتعددة باستخدام بنية
Case
أوif/elif
. -
تعيد التعابير البوليانية القيمة
True
أوFalse
، ويمكن دمجها باستخدامand
أوor
. -
دمج القوائم باستخدام البنية
Case
يسمح لنا ببناء تطبيقات يتحكم فيها المستخدم.
ترجمة -بتصرف- للفصل العاشر: Decisions, Decisions من كتاب Learning To Program لصاحبه Alan Gauld.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.