اذهب إلى المحتوى

مقدمة في البرمجة الشرطية


أسامة دمراني

تصف التعليمات الشرطية في البرمجة قدرتنا على تنفيذ تسلسل واحد من بين عدة تسلسلات محتملة من الشيفرات -التي تمثل الفروع- وفقًا لوقوع حدث ما، وقد كانت أبسط صورة لتلك التعليمات الشرطية في الأيام الأولى لاستخدام لغة التجميع 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.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...