أصبحت تعرف أن هنالك تعليمات وأن البرامج تتألف من سلسلة من التعليمات، لكن قوة البرمجة الحقيقية لا تقع في تنفيذ مجموعة من التعليمات واحدةً تلو الأخرى وكأنك تتبضع قائمة التسوق. فاعتمادًا على نتيجة بعض التعبيرات البرمجية يستطيع البرنامج أن يتخطى تنفيذ مجموعة من التعليمات أو تكررها أو يختار بعضها لتنفيذه.
من النادر أن تجد برامج تنفذ من أول سطر حتى آخر سطر بالترتيب، لذا تكون هنالك حاجة إلى بنى التحكم flow control لتقرير ما هي التعليمات البرمجية التي ستنفذ ووفق أي شروط.
يمكن بسهولة تحويل بنى التحكم البرمجية إلى رموز في مخططات التدفق flowcharts التي نرسمها، لذا سأوفر لك نسخة منها تحاكي الشيفرات التي نكبها. الشكل الآتي يظهر مخططًا تدفقيًا يساعد في اتخاذ القرار عمّا سنفعله إذا كان الجو ماطرًا. تتبع الأسهم من البداية إلى النهاية:
مخطط تدفقي يخبرك ما تفعل إن كانت السماء تمطر
من الشائع أن يكون في المخططات التدفقية أكثر من طريق من البداية إلى النهاية، والأمر سيان بالنسبة إلى شيفرات تطبيقات الحاسوب. تُمثَّل نقاط التفرع في المخططات التدفقية باستخدام شكل المعيّن diamond بينما تُمثَّل بقية الخطوات بمستطيلات عادية، وتكون البداية والنهاية على شكل مستطيل بحواف مدورة.
قبل أن تتعلم عن عبارات بنى التحكم، فعليك أن تعرف كيفية تمثيل خيارات «نعم» و «لا»، بعدها ستحتاج إلى فهم كيفية كتابة نقاط التفرع بلغة بايثون؛ ولهذا الغرض سنحتاج إلى تعلم القيم المنطقية أو البوليانية Boolean وعوامل المقارنة والعوامل المنطقية.
القيم المنطقية Boolean
يكون لأنواع البيانات التي تعلمناها سابقًا من سلاسل نصية وأرقام صحيحة وأرقام ذات فاصلة، عدد لا متناهي من القيم التي يمكن أن تأخذها. لكن للقيم المنطقية أو البوليانية تملك نوعين من القيم فقط: True
و False
(نقول عنها أنها قيم بوليانية Boolean نسبةً إلى العالم الرياضي جورج بولي)، وحين إدخالها في شيفرة بايثون فستلاحظ عدم وجود علامات الاقتباس التي تحيط بالسلاسل النصية، وتبدأ دومًا بالحرف الكبير T أو F وتكون بقية الكلمة بأحرف صغيرة.
أدخل ما يلي في الصدفة التفاعلية، لاحظ الأخطاء التي ستظهر لك في بعض التعليمات:
➊ >>> spam = True >>> spam True ➋ >>> true Traceback (most recent call last): File "<pyshell#2>", line 1, in <module> true NameError: name 'true' is not defined ➌ >>> True = 2 + 2 SyntaxError: can't assign to keyword
وكأي قيمة أخرى، يمكن للقيم المنطقية أن تستعمل في التعابير البرمجية ويمكن أن تخزن في المتغيرات ➊، وإن لم تستعمل حالة الأحرف الصحيحة ➋ أو جربت استخدام True
أو False
لأسماء المتغيرات ➌ فستظهر لك رسالة خطأ.
عوامل المقارنة
تقارن عوامل المقارنة comparison operators بين قيمتين وتكون النتيجة هي قيمة منطقية بوليانية واحدة، الجدول الآتي يستعرض عوامل المقارنة:
العامل | المعنى |
---|---|
== | يساوي |
!= | لا يساوي |
< | أصغر |
> | أكبر |
<= | أصغر أو يساوي |
>= | أكبر أو يساوي |
الجدول 2: عوامل المقارنة
تكون نتيجة استخدام هذه العوامل هي True
أو False
اعتمادًا على القيم التي تعطيها لها. لنجرب الآن بعض تلك العوامل ولنبدأ بالعاملين ==
و !=
:
>>> 42 == 42 True >>> 42 == 99 False >>> 2 != 3 True >>> 2 != 2 False
وكما قد تتوقع، ستكون نتيجة عامل «يساوي» ==
هي True
حينما تساوت القيمتان على يمينه ويساره، وعامل «لا يساوي» ستكون نتيجته True
حينما تختلف القيمتان على يمينه ويساره. يمكننا استخدام العاملين ==
و !=
على أي نوع من أنواع البيانات:
>>> 'hello' == 'hello' True >>> 'hello' == 'Hello' False >>> 'dog' != 'cat' True >>> True == True True >>> True != False True >>> 42 == 42.0 True ➊ >>> 42 == '42' False
لاحظ أن القيم العددية سواءً كانت صحيحة int أو ذات فاصلة عائمة float لا تتساوي مع القيمة النصية. فالتعبير 42 == '42' ➊ نتيجته هي Flase
لأن بايثون تعدّ الرقم 42 مختلفًا عن السلسلة النصية '42'.
أما المعاملات >
و <
و
<= و >=
في لا تعمل إلا مع القيم العددية:
>>> 42 < 100 True >>> 42 > 100 False >>> 42 < 42 False >>> eggCount = 42 ➊ >>> eggCount <= 42 True >>> myAge = 29 ➋ >>> myAge >= 10 True
الفرق بين عامل =
و ==
قد تلاحظ أن عامل المساواة ==
يحتوي على إشارتي يساوي، بينما عامل الإسناد فيه إشارة يساوي واحدة. ومن السهل الخلط بينهما بالنسبة إلى المبتدئين، لذا تذكر أن:
-
عامل المساواة
==
يتأكد إن كانت القيمتان عن يمينه ويساره متساويتين. -
عامل الإسناد
=
يضع التي على اليمين في المتغير الذي على اليسار.
قد يساعدك في التذكر أن عامل المساواة ==
فيه حرفان، مثل معامل عدم المساواة !=
تمامًا.
ستستخدم عوامل المقارنة كثيرًا لمقارنة قيمة أحد المتغيرات مع قيمة أخرى، كما في eggCount <= 42
➊ و myAge >= 10
➋، فلو كنتَ تعرف قيمة المتغير كيف ستكون قبل أن تشغل برنامجك فلا حاجة إلى المقارنة كلها، فليس من المنطقي أن تكتب 'dog' != 'cat'
في شيفرتك بل تكتب True
مباشرةً. سترى أمثلة كثيرة عن ذلك أثناء تعلمك لبنى التحكم.
العوامل المنطقية البوليانية
تستخدم العوامل المنطقية الثلاثة and
و or
و not
لمقارنة القيم المنطقية، وكما في عوامل المقارنة ستكون نتيجة هذه التعابير هي قيمة منطقية، ولنبدأ شرح هذه العوامل بالتفصيل بدءًا من العامل and
و or
.
العوامل المنطقية الثنائية
يعمل العاملان and
و or
على قيمتين أو تعبيرين منطقيين، لهذا يسميان بالعوامل المنطقية الثنائية binary Boolean operators. ينتج العامل nad
القيمة True
إذا كانت كلا القيمتان المنطقيتان تساوي True
، وإلا فالنتيجة هي False
. أدخل التعابير البرمجية الآتية في الصدفة التفاعلية لترى أثر هذا العامل عمليًا:
>>> True and True True >>> True and False False
جداول الحقيقة truth table هو جدول في الجبر المنطقي البولياني يوضح ناتج كل شكل من أشكال التعابير المنطقية. جدول الحقيقة الآتي يوضح ناتج كل عملية ممكنة مع العامل and
:
التعبير | النتيجة |
---|---|
True and True | True |
True and False | False |
False and True | False |
False and False | False |
الجدول 2: جدول الحقيقة للعامل and
وفي المقابل تكون نتيجة العامل or
هي True
إذا كان أحد القيمتين المنطقيتين يساوي True
، أما إذا كانت كلتاهما Flase
فنتيجة التعبير هي False
:
>>> False or True True >>> False or False False
يمكنك أن تعرف ناتج كل تعبير ممكن مع العامل or
من جدول الحقيقة الخاص به.
التعبير | النتيجة |
---|---|
True or True | True |
True or False | True |
False or True | True |
False or False | False |
الجدول 3: جدول الحقيقة للعامل or
العامل not
وعلى النقيض من العاملين and
و or
، يستخدم العامل not
على قيمة أو تعبير منطقي واحد، ولهذا هو عامل أحادي unary operator. ما يفعله العامل not
هو عكس القيمة المنطقية الحالية:
>>> not True False ➊ >>> not not not not True True
وكما في نفي النفي في حديثنا العادي، يمكننا أن نجعل العامل not
متشعبًا ➊، لكن لا يوجد سبب لفعل ذلك في البرامج العملية. الجدول الآتي هو جدول الحقيقة للعامل not
:
التعبير | النتيجة |
---|---|
not True | False |
not False | True |
الجدول 4: جدول الحقيقة للعامل not
المزج بين العوامل المنطقية وعوامل المقارنة
لما كانت نتيجة استخدام عوامل المقارنة هي قيمة منطقية، فيمكننا استخدامها في تعابير برمجية مع العوامل المنطقية.
تذكر أن العوامل المنطقية and
و or
و not
هي عوامل منطقية لأنها تعمل على القيم المنطقية True
و False
؛ بينما التعابير التي تحتوي على عوامل مقارنة مثل 4 < 5
ليست قيمًا منطقية بحد ذاتها لكنها تعابير تُنتِج قيمًا منطقية.
جرب إدخال بعض التعابير المنطقية التي فيها عوامل مقارنة في الصدفة التفاعلية:
>>> (4 < 5) and (5 < 6) True >>> (4 < 5) and (9 < 6) False >>> (1 == 2) or (2 == 2) True
سيقدر الحاسوب قيمة التعبير على اليسار أولًا، ثم قيمة التعبير الذي على اليمين، ثم بعد أن يعرف ما هي القيمة المنطقية لكلٍ منها فسيقدر قيمة التعبير البرمجي كاملًا ويخرج قيمة منطقية وحيدة.
يمكنك أن تتخيل أن عملية تقدير قيمة التعبير البرمجي (4 < 5) and (5 < 6)
تشبه ما يلي:
يمكنك أن تستعمل أكثر من عامل منطقي في تعبير واحد، بالإضافة إلى عوامل المقارنة:
>>> 2 + 2 == 4 and not 2 + 2 == 5 and 2 * 2 == 2 + 2 True
سيكون للعوامل المنطقية ترتيب لتقدير القيمة كما في العوامل الرياضية، فبعد تقدير قيمة العمليات الحسابية وعمليات المقارنة، ستعمل بايثون على عوامل not
أولًا، ثم عوامل and
ثم عوامل or
.
عناصر بنى التحكم
تبدأ عبارات بنى التحكم بجزء يسمى عادةً بالشرط condition ويكون متبوعًا دومًا بكتلة برمجية اشتراطية clause، وقبل أن نتعلم عن بنى التحكم في بايثون فسنشرح ما هو الشرط وما هي الكتلة البرمجية.
الشروط
تعدّ جميع التعابير المنطقية البوليانية التي رأيتها حتى الآن شروطًا conditions، فالشروط هي تعابير برمجية، لكنها تطلق في سياق الحديث عن بنى التحكم.
يكون للشروط دومًا نتيجة منطقية إما True
أو False
، وتقرر بنى التحكم ما الذي يجب فعله اعتمادًا على الشرط إن كان True
أو False
، وجميع بنى التحكم تقريبًا تستخدم الشروط.
الكتل البرمجة
تجمَِع أسطر الشيفرات البرمجية في بايثون على شكل كتل blocks، ويمكنك أن تعرف متى تبدأ الكتلة ومتى تنتهي من المسافة البادئة indent للأسطر البرمجية.
هنالك ثلاث قواعد للكتل البرمجية في بايثون:
- تبدأ الكتلة البرمجية حين زيادة المسافة البادئة.
- يمكن أن تحتوي الكتل البرمجية على كتل أخرى.
- تنتهي الكتل حينما تقل المسافة البادئة إلى الصفر أو إلى المسافة البادئة للكتلة الأب.
من الأسهل فهم الكتل البرمجية بالنظر إلى بعض الشيفرات التي لها مسافة بادئة، لذا لنعثر على الكتل البرمجية في البرنامج البسيط الآتي:
name = ‘Ahmed’ password = 'swordfish' if name == 'Ahmed': ➊ print('Hello, Ahmed’) if password == 'swordfish': ➋ print('Access granted.') else: ➌ print('Wrong password.')
تبدأ أول كتلة من الشيفرات ➊ في السطر print('Hello, Ahmed’) وتضم إليها جميع الأسطر البرمجية التي تليها، وداخل هذه الكتلة هنالك كتلة أخرى ➋ التي تحتوي سطرًا واحدًا داخلها فيه print('Access granted.')، أما الكتلة الثالثة ➌ والأخيرة ففيها print('Wrong password.').
تنفيذ البرنامج
تبدأ بايثون بتنفيذ مثالنا السابق hello.py
من أول البرنامج حتى نهايته سطرًا بسطر، وعملية تنفيذ البرنامج (التي تسمى program execution أو اختصارًا execution) هي اصطلاح يشير إلى التعليمة البرمجية التي يجري تنفيذها حاليًا، فلو كانت شيفرة برنامجك مطبوعةً على ورقة وتشير بإصبعك إلى السطر الذي يجري تنفيذه حاليًا فتشير إصبعك هنا إلى خط سير تنفيذ البرنامج.
لا تنفذ جميع البرامج من الأعلى إلى الأسفل، فلو كنت تستعمل إصبعك لتتبع خط سير أحد البرامج التي فيها بنى تحكم فسترى أنك تنتقل من مكانٍ إلى آخر في الشيفرة المصدرية، وأنك قد تتخطى أجزاء من الشيفرة كليًا.
عبارات بنى التحكم
حان الوقت الآن لنتحدث عن أهم جزء من بنى التحكم: عبارات بنى التحكم نفسها. تمثل العبارات في مخططات التدفق -مثل التي رأيتها في صورة "مخطط تدفقي يخبرك ما تفعل إن كانت السماء تمطر" على شكل معيّن، وتشير إلى القرارات التي يتخذها برنامجك.
عبارة if
أكثر نوع شائع من بنى التحكم هو العبارة الشرطية if، ففيها ستُنفَّذ الكتلة البرمجية التي تلي if
إذا كان الشرط محققًا أي True
، وسيتخطاها البرنامج إن لم يكن الشرط محققًا أي False
.
فإذا أردنا أن نقرأ عبارة if
البرمجة باللغة العربية فسنقول «إذا كان الشرط محققًا، فنفذ الكتلة البرمجية الآتية».
تتألف عبارة if
في بايثون مما يلي:
-
الكلمة المفتاحية
if
-
الشرط، وهو التعبير الذي تكون نتيجته هي
True
أوFalse
-
نقطتان رأسيتان
:
- كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
لنقل مثلًا أنك تريد كتابة شيفرة تتحقق إن كان اسم المستخدم هو Ahmed، وعلى فرض أننا قد أسندنا سابقًا قيمةً ما إلى المتغير name
:
if name == 'Ahmed': print('Hi, Ahmed.')
تنتهي جميع عبارات بنى التحكم بنقطتين رأسيتين :
متبوعة بكتلة برمجية، والكتلة البرمجية في مثالنا هي التي تحتوي على print('Hi, Ahmed.')
. يوضح الشكل الآتي المخطط التدفقي للشيفرة السابقة:
عبارات else
يمكن اختياريًا أن يأتي بعد كتلة if
العبارة else، وتنفذ كتلة else
في حال كان شرط عبارة if
غير محقق False
. أي بالعربية يمكننا أن نقول «إذا كان الشرط محققًا، فنفذ الكتلة البرمجية الآتية، وإلا فنفذ هذه الكتلة».
لا تملك عبارة else
شرطًا، وتتألف else
مما يلي:
-
الكلمة المفتاحية
else
-
نقطتان رأسيتان
:
- كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
وبالعودة إلى مثالنا السابق للترحيب بالمستخدم، فسنضيف العبارة else
لطباعة تحية مختلفة لأي شخص ليس اسمه أحمد:
if name == 'Ahmed': print('Hi, Ahmed.') else: print('Hello, stranger.')
يبين المخطط التدفقي للبرنامج السابق
عبارات elif
تعرفنا سابقًا على عبارة if
و else
التي يجب أن تنفذ إحداهما، لكن ماذا لو كنّا نريد وجود أكثر من احتمال أو أكثر من شرط؟ تعمل العبارة elif
كأنها «وإلا إذا كان كذا» else if
، وتأتي بعد عبارة if
أو elif
أخرى.
توفر عبارة elif
شرطًا بديلًا يمكن التحقق إن كان محققًا إن كانت الشروط التي تسبقه غير محققة.
تتألف عبارة elif
في بايثون مما يلي:
-
الكلمة المفتاحية
elif
-
الشرط، وهو التعبير الذي تكون نتيجته هي
True
أوFalse
-
نقطتان رأسيتان
:
- كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
لنضف عبارة elif
إلى برنامجنا الذي نتحقق فيه من اسم المستخدم:
if name == 'Ahmed': print('Hi, Ahmed.') elif age < 12: print('You are not Ahmed, kiddo.')
سنتحقق هذه المرة من عمر المستخدم، فإن كان عمره أقل من 12 فسيقول له «أنت لست أحمد يا غلام!». يمكننا تمثيل البرنامج بمخطط التدفق الآتي:
مخطط التدفق للعبارة elif
ستفَّذ الكتلة البرمجية التي تلي elif
إن كان عمر المستخدم age < 12
وكان الشرط name == 'Ahmed'
غير محقق False
. لكن إن كان كلا الشرطين غير محقق فسيتجاوز البرنامج تنفيذ الكتلتين البرمجيتين، وليس من الضروري أي ينفذ أحد الكتل البرمجية، فقد تنفذ عبارة واحدة أو لا تنفذ أي عبارة.
بعد أن يتحقق شرط إحدى العبارات الشرطية فسيتجاوز البرنامج بقية عبارات elif
كلها. فعلى سبيل المثال أنشِئ الملف vampire.py
وضع فيه الشيفرة الآتية:
age = 3000 if name == Ahmed: print('Hi, Ahmed.') elif age < 12: print('You are not Ahmed, kiddo.') elif age > 2000: print('Unlike you, Ahmed is not an vampire.') elif age > 100: print('You are not Ahmed, grannie.')
أضفنا هنا عبارتَي elif
لبرنامج الترحيب بالمستخدم، وأضفنا جوابين مختلفين بناءً على العمر age. يظهر المخطط التدفقي الآتي سير عمل البرنامج:
المخطط التدفقي لعبارات elif
متعددة في برنامج vampire.py
.
لترتيب عبارات elif
أهمية، ولتجربة أهمية ترتيبها فلنحاول إضافة علّة لبرنامجنا. تذكر أن البرنامج سيتخطى عبارات elif
بعد تحقيق شرط إحداها، لذا إذا غيرنا ترتيب الشيفرة إلى ما يلي وحفظناه باسم vampire2.py
:
name = 'Abdullatif' age = 3000 if name == 'Ahmed': print('Hi, Ahmed.') elif age < 12: print('You are not Ahmed, kiddo.') ➊ elif age > 100: print('You are not Ahmed, grannie.') elif age > 2000: print('Unlike you, Ahmed is not an undead, vampire.')
إذا جربنا البرنامج وكانت قيمة المتغير age
تساوي 3000 مثلًا، فقد تتوقع أن برنامج سيطبع العبارة التي تقول أن عمره أكثر من 2000 سنة، لكن ولمّا كانت الشرط age > 100
محققًا True
(وذلك لأن 3000 أكبر من 100 بالفعل) ➊، فستعرض عبارة الترحيب بالعجوز وستخطى تنفيذ البرنامج جميع عبارات elif
الأخرى. لذا من المهم الانتباه إلى ترتيب عبارات elif
.
المخطط التدفقي الآتي يظهر سير تنفيذ الشيفرة السابقة. لاحظ كيف جرى تبديل المعين الذي يحتوي على age > 100 و age > 2000.
المخطط التدفقي لتنفيذ برنامج vampire2.py
، لاحظ أن الفرع الذي عليه إشارة × لا ينفذ أبدًا، لكنه إذا كان العمر age أكبر من 2000 فهو بكل تأكيد أكبر من 100 أيضًا.
يمكنك أن تضع عبارة else
بعد آخر عبارة elif
اختياريًا، وفي هذه الحالة سنضمن تنفيذ كتلة برمجية واحدة فقط لا غير، أي في حال كانت جميع شروط if
و elif
هي False
فستنفَّذ كتلة else
. لنعد كتابة مثال الترحيب بالمستخدم لنستعمل فيه if
و elif
و else
:
name = 'Abdullatif' age = 3000 if name == 'Ahmed': print('Hi, Ahmed.') elif age < 12: print('You are not Ahmed, kiddo.') else: print('You are neither Ahmed nor a little kid.')
يظهر الشكل الآتي المخطط التدفقي للمثال السابق، الذي سنسميه littleKid.py
.
المخطط التدفقي لبرنامج liitleKid.py
.
يمكننا وصف هذا النمط من بنى التحكم باللغة العربية: «إذا كان أول شرط محققًا فافعل كذا، وإلا إن كان الشرط الثاني محققًا فافعل كذا، وإلا فافعل كذا». من المهم أن تنتبه إلى ترتيب عبارات if
وelif
و else
حين استخدامها لكي تتجنب العلل المنطقية في برامجك. وتذكر أن هنالك عبارة if
وحيدة فقط لا غير، وأي عبارات elif
يجب أن تأتي بعدها؛ وإذا أردت ضمان تنفيذ إحدى الكتل البرمجية فأنهِ بنى التحكم بعبارة else
.
حلقة التكرار while
يمكنك أن تعيد تنفيذ إحدى الكتل البرمجية مرارًا وتكرارًا باستخدام عبارة while. وستُنفَّذ الشيفرة الموجودة في الكتلة التي تلي شرط while
طالما كان الشرط محققًا True
.
تتألف عبارة while
في بايثون مما يلي:
-
الكلمة المفتاحية
while
-
الشرط، وهو التعبير الذي تكون نتيجته هي
True
أوFalse
-
نقطتان رأسيتان
:
- كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
يمكنك ملاحظة أن عبارة while
شبيهة جدًا بعبارة if
، والفرق بينهما هو في السلوك. فبعد الانتهاء من الكتلة التي تلي شرط if
سيكمل البرنامج تنفيذ الشيفرة التي تليها، لكن في نهاية كتلة while
فسيعود تنفيذ البرنامج إلى بداية عبارة while
. نسمي عبارة while
عادةً «حلقة التكرار while» أو «حلقة while».
للنظر إلى الفرق بين العبارة الشرطية if
وحلقة while
لهما نفس الشرط وتفعلان نفس الفعل في الكتلة التي تليهما. هذه هي الشيفرة التي نستعمل العبارة الشرطية if
فيها:
spam = 0 if spam < 5: print('Hello, world.') spam = spam + 1
وهذه هي الشيفرة التي نستعمل الحلقة while
فيها:
spam = 0 while spam < 5: print('Hello, world.') spam = spam + 1
تشبه هذه التعابير بعضها بعضًا، إذ تتحقق if
و while
من أن قيمة المتغير spam
أصغر من 5، ثم تعرض رسالةً ترحيبيةً وتزيد قيمة المتغير spam
بمقدار 1.
لكن حينما تشغل البرنامجين السابقين فستجد نتيجةً مختلفةً لكلٍ منهما، ففي البرنامج الذي فيه if سترى عبارة الترحيب مرة واحدة، بينما تكرر العبارة الترحيبية 5 مرات في برنامج while! لننظر إلى المخططين التدفقيين للبرنامجين السابقين في الشكلين المواليين لنفهم ما حدث:
المخطط التدفقي للبرنامج الذي يحتوي على العبارة الشرطية if
.
المخطط التدفقي للبرنامج الذي يحتوي على العبارة الشرطية while
.
تتحقق العبارة الشرطية if
من الشرط وتطبع "Hello, World" مرةً واحدةً بعد تحقق الشرط، ثم ينتهي تنفيذ البرنامج. بينما البرنامج الذي فيه حلقة while
فسينفذ 5 مرات لأن قيمة العدد spam
تزيد مرة في نهاية كل حلقة تكرار، وهذا يعني أن الحلقة ستنفذ 5 مرات قبل أن يصبح الشرط spam < 5
غير محقق False
.
ستجري عملية التحقق من شرط حلقة while
في بداية كل دورة iteration، أي في بداية كل تنفيذ لحلقة while
؛ وإذا كان الشرط محققًا True
فستنفذ الكتلة، ثم بعد ذلك يعاد التحقق من الشرط مجددًا. لاحظ أنه إذا كان شرط حلقة while
غير محقق False
من أول مرة فلن تنفَّذ الحلقة أبدًا وسيتخطاها البرنامج.
حلقة while المزعجة
هذا برنامج بسيط يطلب منك باستمرار أن تدخل "your name" في سطر الأوامر حين سؤاله عن اسمك.
أنشِئ ملفًا جديدًا من File ثم New وأدخل الشيفرة الآتية واحفظها في الملف yourName.py
:
➊ name = '' ➋ while name != 'your name': print('Please type your name.') ➌ name = input() ➍ print('Thank you!')
يضبط البرنامجُ المتغيرَ name
إلى سلسلة نصية فارغة ➊، وبهذا يكون الشرط name != 'your name'
محققًا True
وبالتالي سيبدأ تنفيذ حلقة while
➋.
سيسأل البرنامجُ المستخدمَ عن اسمه، ثم يأخذ المدخلات ويخزنها في المتغير name
➌، ولمّا كنّا قد وصلنا إلى نهاية حلقة التكرار فسنعود إلى بداية حلقة while
ونتحقق من الشرط، وإن لم يكن الاسم name مساويًا إلى السلسلة النصية 'your name'
فيسكون الشرط محققًا True
وسيعاد تنفيذ حلقة while
مجددًا.
لكن حينما يدخل المستخدم الكلمتين your name فسيصبح شرط حلقة while
غير محقق False
، وبالتالي بدلًا من إعادة تكرار الحلقة فسيكمل برنامجنا تنفيذ بقية البرنامج ➍.
المخطط التدفقي في الشكل الآتي يوضح آلية عمل البرنامج yourName.py
:
المخطط التدفقي للبرنامج yourName.py
.
لنجرب الآن البرنامج، بالضغط على زر F5 لتشغيله، ثم كتابة أي عبارة سوى "your name" عدة مرات قبل أن نرضخ للضغط الذي يمارسه البرنامج تجاهنا ونكتب "your name".
Please type your name. Abdullatif Please type your name. Hsoub Please type your name. %#@#%*(^&!!! Please type your name. your name Thank you!
إذا لم ندخل "your name" أبدًا فلن يصبح شرط while
غير محقق False
وبالتالي سيستمر تنفيذ البرنامج إلى الأبد. وفي حالة برنامجنا كانت لدينا الدالة input()
التي تمكننا من إكمال سير البرنامج حينما ندخل العبارة الصحيحة وبالتالي تتغير حالة الشرط، لكن قد لا يتغير الشرط في بعض البرامج مما يسبب مشكلة، لذا هنالك حاجة لتعلم طريقة للخروج من حلقة while
.
العبارة break
هنالك طريقة نجعل فيها برنامجنا يخرج من حلقة while
قبل انتهاء تنفيذها. فإذا وصل التنفيذ إلى عبارة break
فسيخرج البرنامج من حلقة while
مباشرةً. وتتألف عبارة break
في بايثون من الكلمة المحجوزة break
فقط.
أليس ذلك بسيطًا؟ لنكتب برنامجًا يشبه البرنامج السابق لكنه يستخدم العبارة break
للخروج من حلقة التكرار، أدخِل الشيفرة الآتية واحفظها في ملف باسم yourName2.py
:
➊ while True: print('Please type your name.') ➋ name = input() ➌ if name == 'your name': ➍ break ➎ print('Thank you!')
ننشِئ في أول سطر ➊ حلقة تكرار لا نهائية، وذلك بجعل شرط حلقة while
محققًا دومًا True
، وبالتأكيد إذا وضعنا True
شرطًا لحلقة while
فستكون قيمته هي True
دومًا.
بعد أن يبدأ تنفيذ حلقة التكرار فلن يخرج البرنامج منها إلا إذا استخدام عبارة break
، لاحظ أن حلقات التكرار اللانهائية التي لا ينتهي تنفيذها أبدًا هي علّة منطقية في البرامج.
وكما في المثال السابق، سيطلب البرنامج من المستخدم أن يدخل your name ➋، وسنتحقق إن كان المتغير name
يساوي 'your name' باستخدام البنية الشرطية if
➌، وإذا كان الشرط محققًا True
فستنفذ العبارة break
➍، وسينتقل التنفيذ إلى خارج الحلقة وستطبع رسالة الشكر ➎.
إذا لم يكن شرط العبارة if محققًا فهذا يؤدي إلى دورة جديدة لحلقة while
، وسيتحقق البرنامج من شرط تنفيذ حلقة while
➊، ولمّا كان الشرط محققًا True
دومًا، فستنفذ حلقة التكرار مجددًا وتسأل المستخدم أن يدخل your name.
المخطط التدفقي في الشكل التالي يوضح آلية عمل البرنامج yourName2.py
:
المخطط التدفقي للبرنامج yourName2.py
مع حلقة تكرار لا نهائية، لاحظ أن المسار ×
لا ينفذ منطقيًا أبدًا لأن شرط الحلقة هو True
دومًا.
هل وقعت في حلقة تكرار لا نهائية؟
إذا شغلت تطبيقًا يحتوي على علة تؤدي إلى حلقة تكرار لا نهائية، فاضغط على Ctrl+C
أو أعد تشغيل الصدفة من Shell ثم Restart Shell؛ مما يرسل إشارة KeyboardInterrupt إلى برنامجك تؤدي إلى إيقاف تشغيله مباشرةً. يمكنك التجربة بإنشاء برنامج بسيط باسم infiniteLoop.py
:
while True: print('Hello, world!')
سيطبع البرنامج السابق العبارة Hello, World! إلى اللانهاية لأن شرط حلقة while
محقق True
دومًا. قد تستفيد من استخدام الاختصار Ctrl+C
لإنهاء تنفيذ البرامج حتى دون أن تكون عالقًا في حلقة تكرار لا نهائية.
عبارة continue
وكما في عبارة break
، نستعمل العبارة continue داخل حلقات التكرار، وحينما يصل التنفيذ إلى عبارة continue
فسينتقل تنفيذ البرنامج إلى بداية حلقة التكرار مباشرةً ويعيد التحقق من شرط الحلقة، أي نفس ما يحدث حين الوصول إلى نهاية دورة حلقة التكرار.
لنستخدم continue
لكتابة برنامج يسأل عن اسم المستخدم وكلمة المرور، أدخل ما يلي في ملف جديد واحفظه باسم swordfish.py
:
while True: print('Who are you?') name = input() ➊ if name != 'Abdullatif': ➋ continue print('Hello, Abdullatif. What is the password? (It is a fish.)') ➌ password = input() if password == 'swordfish': ➍ break ➎ print('Access granted.')
إذا أدخل المستخدم أي اسم باستثناء Abdullatif ➊ فستنقل العبارة continue
➋ التنفيذ إلى بداية حلقة التكرار، وحين إعادة التحقق من شرط الدخول إلى الحلقة فسيكون محققًا دومًا لأنه True
.
بعد أن يتجاوز المستخدم الشرط الموجود في if
فسنسأله عن كلمة المرور ➌، وإذا أدخل كلمة المرور swordfish فستنفذ عبارة break
➍ وبالتالي نخرج من حلقة التكرار كليًا وستطبع العبارة Access granted ➎، وإذا لم تكن كلمة المرور صحيحةً فسنصل إلى نهاية دورة حلقة التكرار ثم نعود إلى بدايتها ونتحقق من الشرط مجددًا الذي هو True دومًا… المخطط التدفقي في الشكل الآتي يوضح آلية عمل البرنامج swordfish.py
:
المخطط التدفقي للبرنامج swordfish.py
، لاحظ أن المسار ×
لا ينفذ منطقيًا أبدًا لأن شرط الحلقة هو True
دومًا.
شغل البرنامج السابق وجرب بعض المدخلات، ولن يسألك البرنامج عن كلمة المرور حتى تدعي أنك Abdullatif، وسيطبع لك رسالة أن الوصول مسموح لك إن أدخلت كلمة المرور الصحيحة:
Who are you? I'm fine, thanks. Who are you? Who are you? Abdullatif Hello, Abdullatif. What is the password? (It is a fish.) Mary Who are you? Abdullatif Hello, Abdullatif. What is the password? (It is a fish.) swordfish Access granted.
القيم التي تكافئ True والقيم التي تكافئ False
ستعدّ الشروط في بايثون بعض القيم في أنواع البيانات المختلفة على أنها مكافئة للقيمة True
وأخرى للقيمة False
. فلو استخدمنا القيم 0 و 0.0 و '' (سلسلة نصية فارغة) في الشروط فستكافئ False
، بينما ستكافئ أي قيمة أخرى True
. ألقِ نظرةً هنا:
name = '' ➊ while not name: print('Enter your name:') name = input() print('How many guests will you have?') numOfGuests = int(input()) ➋ if numOfGuests: ➌ print('Be sure to have enough room for all your guests.') print('Done')
يبدأ البرنامج بتهيئة المتغير name مع قيمة نصية فارغة، وبالتالي سيكون شرط حلقة while
محققًا True
➊، وسيتحقق أيضًا إذا أدخل المستخدم سلسلة نصية فارغة أثناء سؤاله عن الاسم name (بالضغط مباشرةً على زر Enter دون كتابة شيء).
سيبدأ تنفيذ الحلقة بطلب إدخال الاسم وعدد الضيوف، وإذا كان عدد الضيوف numOfGuests ليس صفرًا 0 ➋ فسيكون الشرط محققًا True
وسيطبع البرنامج تذكيرًا للمستخدم ➌.
كان بإمكاننا كتابة name != ''
بدلًا من not name
، و numOfGuests != 0
بدلًا من numOfGuests، لكن استخدام القيم التي تكافئ True
أو False
في شروط سيجعل مقروئية شيفرتك أفضل.
حلقات تكرار for والدالة range()
ستعمل حلقة while لطالما كان الشرط محققًا True
(ومن هنا أتى اسمها while)، لكن ماذا لو أردنا تنفيذ كتلة من الشيفرات لعدد محدد من المرات؟ يمكننا فعل ذلك عبر حلقة التكرار for والدالة range().
ستبدو عبارة for
كالآتي for i in range(5):
وستتضمن ما يلي:
-
الكلمة المحجوزة
for
- اسم المتغير
-
الكلمة المحجوزة
in
-
استدعاء للدالة
range()
مع تمرير 3 أعداد صحيحة كحد أقصى إليها -
نقطتان رأسيتان
:
- كتلة برمجية تلي ما سبق، تكون فيها الأسطر مسبوقة بمسافة بادئة
لننشئ برنامجًا ولنسمه fiveTimes.py
الذي يساعدنا على معاينة حلقة for
عمليًا:
print('My name is') for i in range(5): print('Hani Five Times (' + str(i) + ')')
سترى أن الكتلة البرمجية لحلقة التكرار for
تنفذ 5 مرات، وستكون قيمة المتغير i
في أول مرة تعمل فيها الحلقة هو 0، وستطبع print()
العبارة Hani Five Times (0) ثم بعد أن تنتهي بايثون من تنفيذ أول دورة في حلقة التكرار فسيعود التنفيذ إلى بداية الحلقة وستزيد قيمة المتغير i
بمقدار 1، ولهذا سيؤدي استدعاء الدالة range(5) إلى حدوث 5 تكرارات داخل حلقة for
، إذ سيبدأ المتغير i من القيمة 0 ثم 1 ثم 2 ثم 3 ثم 4، وعمومًا ستزداد قيمة المتغير إلى أن تصل إلى الرقم الذي مررناه إلى الدالة range() لكن دون تضمينه في النتائج.
الشكل الآتي يوضح المخطط التدفقي لهذا البرنامج:
إذا شغلت البرنامج فسترى العبارة Hani Five Times متبوعةً بقيمة المتغير i في دورة حلقة for
الحالية:
My name is Hani Five Times (0) Hani Five Times (1) Hani Five Times (2) Hani Five Times (3) Hani Five Times (4)
ملاحظة: يمكنك استخدام break
و continue
داخل حلقات for
أيضًا، وستؤدي العبارة continue
إلى تخطي الدورة الحالية لحلقة التكرار والانتقال إلى الدورة الآتية، كما لو أن تنفيذ البرنامج وصل إلى نهاية دورة حلقة for
الحالية ثم عاد إلى بداية الحلقة. يمكنك أن تستعمل العبارتين break
و continue
داخل حلقات while
و for
فقط، وإذا حاولت أن تجرب استخدامها في مكانٍ آخر فستعطيك بايثون رسالة خطأ.
لنأخذ قصة عالم الرياضيات الشهير كارل فريدريش غاوس (قد تعرفه باسم غاوس أو Gauss)، أراد مدرسه حينما كان صغيرًا أن يعطيه وظيفة صعبة وطلب منه جمع الأرقام من 0 إلى 100، وخطرت ببال الفتى غاوس طريقة ذكية للإجابة عن ذاك السؤال بثوانٍ معدودة، لكن لنكتب الآن برنامج بايثون يحسب لنا الناتج ويستعمل الحلقة for
:
➊ total = 0 ➋ for num in range(101): ➌ total = total + num ➍ print(total)
يفترض أن يكون الناتج 5,050. نضبط قيمة المتغير total
إلى 0 ➊ في بداية البرنامج، ثم نبدأ حلقة for ➋ التي ننفذ فيها total = total + num
➌ مئة مرة، وبعد أن تنتهي دورات التكرار المئة فسنكون قد جمعنا الأعداد الصحيحة من 0 إلى 100 في المتغير total
، ثم نطبق قيمة total
إلى الشاشة ➍. سيعمل برنامجنا بأجزاء من الثانية ويخبرنا بالناتج النهائي.
(اكتشف غاوس حينما أعطاه المدرس هذه الوظيفة حلها بطريقة ذكية: هنالك خمسون زوجًا من الأرقام التي يكون مجموعها 101 مثل 1 + 100 و 2 + 99 و 3 + 98 وهلمَّ جرًا، حتى يصل إلى 50 + 51. ولمّا كان جداء 50 × 101 هو 5,050 فسيكون مجموع جميع الأرقام من 0 إلى 100 هو 5,050. يا له من فتى ذكي!)
كتابة حلقة while تكافئ حلقة for
يمكنك عمليًا أن تكتب حلقة while
لتكافئ في عملها حلقة for
، وستجد أن كتابة حلقات for
مختصرة أكثر. لنعد كتابة المثال iveTimes.py
ليستعمل الحلقة while
:
print('My name is') i = 0 while i < 5: print('Hani Five Times (' + str(i) + ')') i = i + 1
إذا شغلت البرنامج فمن المفترض أن يكون الناتج مماثلًا تمامًا للمثال fiveTimes.py
الذي يستعمل حلقة for
. اعلم أنك تستطيع كتابة أمور كثيرة في البرمجة بأكثر من طريقة، لكن عليك اختيار الأداة الأنسب لأداء المهمة التي تريدها.
وسائط الدالة range(): البداية والنهاية والخطوة
يمكن أن تستدعى بعض الدوال مع عدّة وسائط arguments مفصولة بفاصلة، والدالة range() هي إحداها.
يسمح لك تمرير وسائط للدالة range() أن تغير سلوكها، فمثلًا يمكنك تحديد الرقم الذي يجب أن تبدأ منه الدالة range():
for i in range(12, 16): print(i)
يمثِّل أول وسيط من أين يجب أن تبدأ حلقة for
، ويمثل الوسيط الثاني أين يجب أن تتوقف (دون تضمين هذا الرقم):
12 13 14 15
يمكننا أيضًا استدعاء الدالة range() مع ثلاثة وسائط، ويكون أول وسيطين هما البداية والنهاية، أما الوسيط الثالث فسيكون «الخطوة» step، الذي يشير إلى مقدار زيادة قيمة المتغير عند كل دورة:
for i in range(0, 10, 2): print(i)
أي أن استدعاء range(0, 10, 2) سيعد من الصفر إلى الثمانية وبخطوة 2:
0 2 4 6 8
الدالة range() مرنة ويمكنك استخدامها لتوليد أي سلسلة أرقام، فمثلًا يمكنك استخدام رقم سالب كوسيط لقيمة الخطوة مما يؤدي إلى العد عكسيًا تنازليًا:
for i in range(5, -1, -1): print(i)
ستنتج حلقة for
السابقة الناتج الآتي:
5 4 3 2 1 0
نجد أن المجال range(5, -1, -1) مع حلقة التكرار for
سيؤدي إلى طباعة 5 أعداد تنازليًا من 5 إلى 0.
استيراد الوحدات
يمكن لجميع برامج بايثون أن تستدعي مجموعةً من الدوال الأساسية نسميها الدوال المضمنة في اللغة أو «الدوال المضمنة» built-in functions، والتي تتضمن الدوال التي تعرفت عليها سابقًا مثل print() و input() و len().
تأتي بايثون أيضًا مع مجموعة من الوحدات الأساسية modules التي نسميها بالمكتبة القياسية standard library. تتألف كل وحدة من عدد برامج بايثون التي فيها مجموعة من الدوال التي يمكنك استخدامها في برامجك.
فمثلًا تحتوي الوحدة math على مجموعة من الدوال المتعلقة بالعمليات الرياضية، بينما تضم الوحدة random مجموعة من الدوال التي تجري عمليات على الأرقام المولدة عشوائيًا، وهكذا.
قبل أن نستخدم الدوال الموجودة في إحدى تلك الوحدات في برامجنا، يجب علينا أولًا استيراد تلك الوحدة باستخدام العبارة import
. وتتألف عبارة import
مما يلي:
-
الكلمة المحجوزة
import
- اسم الوحدة التي نريد استيرادها
- واختياريًا أسماء وحدات أخرى نريد استيرادها على أن نفصل بينها بفاصلة
بعد أن تستورد إحدى الوحدات فيمكنك أن تستعمل جميع الدوال الرائعة الموجودة فيها، ولنضرب مثالًا الوحدة random
التي تمنحنا وصولًا إلى الدالة random.randint() حين استيرادها.
احفظ الشيفرة الآتية في ملف باسم printRandom.py
:
import random for i in range(5): print(random.randint(1, 10))
سيطبع البرنامج السابق ناتجًا يشبه الناتج الآتي حين تشغيله:
4 1 8 4 1
ستكون نتيجة استدعاء الدالة random.randint() هي عدد صحيح عشوائي يقع بين العددين الذين مررتهما إلى الدالة كوسيطين. ولمّا كانت الدالة randint() موجودةً في الوحدة random
، فعليك أن تكتب الكلمة random
أولًا قبل اسم الدالة لتخبر بايثون أنك تريد استخدام الدالة الموجودة في الوحدة random
، ونفصل بين اسم الوحدة واسم الدالة بنقطة.
هذا مثال لعبارة استيراد تستورد أربع وحدات في آنٍ واحد:
import random, sys, os, math
يمكننا الآن استخدام أي دالة موجودة في الوحدات الأربع السابقة، وسنتعلم المزيد عن تلك الوحدات لاحقًا في هذه السلسلة.
عبارة from import
هنالك شكل بديل لعبارة import
يتضمن الكلمة المحجوزة from
، والتي نتبعها باسم الوحدة، ثم الكلمة المحجوزة import
ثم نجمة *
؛ فمثلًا from random import *
.
وحين استيراد الوحدات بهذا الشكل فلا حاجة إلى وضع السابقة random.
قبل أسماء الدوال التي نريد استدعاءها؛ لكن في المقابل من الأفضل كتابة الاسم الكامل للدالة مع السابقة التي تشير إلى اسم الوحدة لزيادة مقروئية الشيفرة البرمجية.
إنهاء تنفيذ البرنامج حينما نشاء باستخدام الدالة sys.exit()
آخر مفهوم من مفاهيم بنى التحكم التي سنشرحها في هذا المقال هو آلية إنهاء تنفيذ البرنامج.
ينتهي تنفيذ البرامج دومًا حينما يصل التنفيذ إلى نهاية الملف، لكن يمكننا إنهاء تنفيذ البرنامج قبل آخر تعليمة برمجية باستخدام الدالة sys.exit(). ولمّا كانت هذه الدالة جزءًا من الوحدة sys
فعلينا أن نستورد تلك الوحدة في بداية البرنامج قبل استخدامها.
افتح محرر الشيفرات واكتب ما يلي واحفظه exitExample.py
:
import sys while True: print('Type exit to exit.') response = input() if response == 'exit': sys.exit() print('You typed ' + response + '.')
شغل البرنامج السابق وستجد أنك دخلت في حلقة تكرار لا نهائية دون وجود عبارة break
داخلها، والطريقة الوحيدة لكي ينتهي تنفيذ البرنامج هي الوصول إلى استدعاء الدالة sys.exit()، ولأن قيمة المتغير response
تساوي ما يدخله المستخدم عبر input()، فإذا أدخلت exit
فستتحقق العبارة الشرطية if
وسينتهي تنفيذ البرنامج.
برنامج قصير: احزر الرقم
جميع الأمثلة السابقة كانت بسيطة جدًا لكنها مناسبة لاستيعاب المفاهيم البرمجية الأساسية، لكن لنبني الآن برنامجًا متكاملًا نوظِّف فيه المعلومات التي تعلمناها. سنكتب في هذا القسم لعبة «احزر الرقم»، والتي ستبدو كما يلي حين تشغيلها:
I am thinking of a number between 1 and 20. Take a guess. 10 Your guess is too low. Take a guess. 15 Your guess is too low. Take a guess. 17 Your guess is too high. Take a guess. 16 Good job! You guessed my number in 4 guesses!
افتح محرر الشيفرات وأدخل الشيفرة الآتية واحفظها في ملف باسم guessTheNumber.py
:
# This is a guess the number game. import random secretNumber = random.randint(1, 20) print('I am thinking of a number between 1 and 20.') # Ask the player to guess 6 times. for guessesTaken in range(1, 7): print('Take a guess.') guess = int(input()) if guess < secretNumber: print('Your guess is too low.') elif guess > secretNumber: print('Your guess is too high.') else: break # This condition is the correct guess! if guess == secretNumber: print('Good job! You guessed my number in ' + str(guessesTaken) + ' guesses!') else: print('Nope. The number I was thinking of was ' + str(secretNumber))
لنقسم البرنامج إلى أقسام صغيرة ونناقشها كلًا على حدة، بدءًا من أعلى الملف:
# This is a guess the number game. import random secretNumber = random.randint(1, 20)
يبدأ البرنامج بتعليق في أول سطر فيه يشرح ماذا يفعل البرنامج، ثم يستورد الوحدة random
لكي نستطيع استخدام الدالة random.randint() لتوليد رقم ليحزره اللاعب، وسنخزن الرقم العشوائي الناتج في المتغير secretNumber
.
print('I am thinking of a number between 1 and 20.') # Ask the player to guess 6 times. for guessesTaken in range(1, 7): print('Take a guess.') guess = int(input())
سيخبر البرنامج اللاعب أنه قد «فكر» في رقم سري ويملك اللاعب ست محاولات ليحزره، وستكون الشيفرة التي تسمح للاعب بإدخال رقم والتحقق منه موجودة في حلقة for
التي ستنفذ ست مرات كحد أقصى.
أول ما تفعله حلقة التكرار هو طلب كتابة تخمين للرقم السري عبر input()، ولأن الدالة input() تعيد سلسلةً نصية وليس رقمًا صحيحًا فنمرر الناتج إلى الدالة int()، وثم يخزن الرقم الذي أدخله المستخدم في المتغير guess
.
if guess < secretNumber: print('Your guess is too low.') elif guess > secretNumber: print('Your guess is too high.')
تتحقق الشروط السابقة إن كان تخمين المستخدم أصغر أو أكبر من الرقم السري، وفي كلتي الحالتين سيوفر البرنامج تلميحًا لللاعب.
else: break # This condition is the correct guess!
إذا لم يكن تخمين اللاعب أصغر ولا أكبر من الرقم السري فهذا يعني أنه يساويه، وفي هذه الحالة سيخرج البرنامج من حلقة for
عبر break
.
if guess == secretNumber: print('Good job! You guessed my number in ' + str(guessesTaken) + ' guesses!') else: print('Nope. The number I was thinking of was ' + str(secretNumber))
بعد نهاية حلقة for سيتحقق البرنامج عبر عبارة if…else
أن اللاعب قد خمَّن الرقم السري الصحيح، ويعرض رسالة مناسبة لكل حالة. تذكر أن الشيفرات التي تقع بعد حلقة التكرار ستنفذ بعد انتهاء تنفيذ حلقة التكرار سواءً بإكمالها 6 مرات وعدم تخمين اللاعب للرقم الصحيح، أو بالخروج منها عبر break
حين تخمين الرقم السري الصحيح.
سيعرض برنامجنا رسالتين نصيتين فيهما متغير يحمل قيمةً عدديةً صحيحةً guessesTaken و secretNumber، ولأننا نحاول ضم عدد صحيح إلى سلسلة نصية فيجب أن نمرر الرقم إلى الدالة str() أولًا، ثم نضم السلاسل النصية عبر العامل + لتمريرها إلى الدالة print() لطباعتها على الشاشة.
برنامج قصير: حجرة ورقة مقص
لنستخدم المفاهيم البرمجية التي تعلمناها لإنشاء لعبة «حجرة ورقة مقص» الشهيرة. سيكون ناتج تشغيل اللعبة كما يلي:
ROCK, PAPER, SCISSORS 0 Wins, 0 Losses, 0 Ties Enter your move: (r)ock (p)aper (s)cissors or (q)uit p PAPER versus... PAPER It is a tie! 0 Wins, 1 Losses, 1 Ties Enter your move: (r)ock (p)aper (s)cissors or (q)uit s SCISSORS versus... PAPER You win! 1 Wins, 1 Losses, 1 Ties Enter your move: (r)ock (p)aper (s)cissors or (q)uit q
افتح نافذةً جديدةً في محرر الشيفرات وأدخل الشيفرة الآتية واحفظها في ملف باسم rpsGame.py
:
import random, sys print('ROCK, PAPER, SCISSORS')
ستتبّع هذه المتغيرات عدد مرات الربح والخسارة والتعادل
wins = 0 losses = 0 ties = 0 while True: # دورة اللعبة print('%s Wins, %s Losses, %s Ties' % (wins, losses, ties)) while True: # مدخلات المستخدم print('Enter your move: (r)ock (p)aper (s)cissors or (q)uit') playerMove = input() if playerMove == 'q': sys.exit() # الخروج من البرنامج if playerMove == 'r' or playerMove == 'p' or playerMove == 's': break # الخروج من حلقة مدخلات المستخدم print('Type one of r, p, s, or q.') # عرض ما اختاره اللاعب if playerMove == 'r': print('ROCK versus...') elif playerMove == 'p': print('PAPER versus...') elif playerMove == 's': print('SCISSORS versus...') # عرض ما اختاره الحاسوب randomNumber = random.randint(1, 3) if randomNumber == 1: computerMove = 'r' print('ROCK') elif randomNumber == 2: computerMove = 'p' print('PAPER') elif randomNumber == 3: computerMove = 's' print('SCISSORS') # عرض النتيجة الربح/الخسارة/التعادل if playerMove == computerMove: print('It is a tie!') ties = ties + 1 elif playerMove == 'r' and computerMove == 's': print('You win!') wins = wins + 1 elif playerMove == 'p' and computerMove == 'r': print('You win!') wins = wins + 1 elif playerMove == 's' and computerMove == 'p': print('You win!') wins = wins + 1 elif playerMove == 'r' and computerMove == 'p': print('You lose!') losses = losses + 1 elif playerMove == 'p' and computerMove == 's': print('You lose!') losses = losses + 1 elif playerMove == 's' and computerMove == 'r': print('You lose!') losses = losses + 1
لنمعن النظر إلى الشيفرة من بدايتها:
import random, sys print('ROCK, PAPER, SCISSORS') # ستتبّع هذه المتغيرات عدد مرات الربح والخسارة والتعادل wins = 0 losses = 0 ties = 0
سنستورد في البداية الوحدتين random
و sys
لكي نستطيع استدعاء الدالتين random.randint() و sys.exit()، ثم سنهيئ ثلاثة متغيرات لكي نتتبع عدد مرات ربح أو خسارة أو تعادل اللاعب.
while True: # دورة اللعبة print('%s Wins, %s Losses, %s Ties' % (wins, losses, ties)) while True: # مدخلات المستخدم print('Enter your move: (r)ock (p)aper (s)cissors or (q)uit') playerMove = input() if playerMove == 'q': sys.exit() # الخروج من البرنامج if playerMove == 'r' or playerMove == 'p' or playerMove == 's': break # الخروج من حلقة مدخلات المستخدم print('Type one of r, p, s, or q.')
يستعمل برنامجنا حلقة while
داخل حلقة while
، أول حلقة هي حلقة اللعبة الأساسية، وتمثل دورًا من لعبة «حجرة ورقة مقص» في كل مرة تنفذ فيها تلك الحلقة. أما حلقة التكرار الثانية فهي تطلب من اللاعب مدخلات، وستبقى تعمل حتى يدخل المستخدم r أو p أو s أو q التي ترمز إلى حجرة rock وورقة paper ومقص scissors على التوالي وبالترتيب، أما q فتعني أن اللاعب يريد إنهاء اللعبة quit، وفي تلك الحالة ستستدعى الدالة sys.exit() وسنتهي تنفيذ البرنامج.
إذا أدخل المستخدم r أو p أو s فسنخرج من حلقة التكرار الثانية عبر break
، وإلا فسيعود التنفيذ إلى بداية حلقة التكرار ويذكر البرنامج اللاعب أن عليه إدخال r أو p أو s أو q.
# عرض ما اختاره اللاعب if playerMove == 'r': print('ROCK versus...') elif playerMove == 'p': print('PAPER versus...') elif playerMove == 's': print('SCISSORS versus...')
يظهر البرنامج هنا ما اختاره اللاعب.
# عرض ما اختاره الحاسوب randomNumber = random.randint(1, 3) if randomNumber == 1: computerMove = 'r' print('ROCK') elif randomNumber == 2: computerMove = 'p' print('PAPER') elif randomNumber == 3: computerMove = 's' print('SCISSORS')
وهنا يظهر ما اختاره الحاسوب عشوائيًا.
ولمّا كانت الدالة random.randint() تعيد رقمًا عشوائيًا، فسنحتاج إلى تحويل الرقم الصحيح المخزن في المتغير randomNumber
إلى حجرة أو ورقة أو مقص عبر البنية الشرطية if
و elif
، وبالتالي سيخزن البرنامج ما اختاره الحاسوب في المتغير computerMove
ثم يطبع رسالة نصية فيها الحركة المختارة.
# عرض النتيجة الربح/الخسارة/التعادل if playerMove == computerMove: print('It is a tie!') ties = ties + 1 elif playerMove == 'r' and computerMove == 's': print('You win!') wins = wins + 1 elif playerMove == 'p' and computerMove == 'r': print('You win!') wins = wins + 1 elif playerMove == 's' and computerMove == 'p': print('You win!') wins = wins + 1 elif playerMove == 'r' and computerMove == 'p': print('You lose!') losses = losses + 1 elif playerMove == 'p' and computerMove == 's': print('You lose!') losses = losses + 1 elif playerMove == 's' and computerMove == 'r': print('You lose!') losses = losses + 1
وفي النهاية، سيوازن البرنامج بين السلسلتين النصيتين الموجودتين في المتغيرين playerMove
و computerMove
ويظهر الناتج على الشاشة، وسيزيد قيمة أحد المتغيرات wins
أو losses
أو ties
بما يناسب الحالة. بعد أن يصل تنفيذ البرنامج إلى النهاية فسيعود إلى بداية حلقة التكرار الرئيسية ونلعب دورًا جديدًا من اللعبة.
الخلاصة
بعد أن تعلمنا كيفية كتابة شروط أو عبارات تكون نتيجتها True
أو False
، أصبح بإمكاننا كتابة برامج تستطيع اتخاذ قرارات تحدد ما هي الشيفرات التي سينفذها البرنامج وأيها سيتخطاها.
أصبح تستطيع تنفيذ الشيفرات مرارًا وتكرارًا عبر حلقات التكرار، وستستفيد من العبارتين break
و continue
للخروج من حلقة التكرار أو العودة إلى بدايتها مباشرةً.
تسمح لنا بنى التحكم بكتابة برامج أكثر ذكاءً، وسنتعلم كتابة شيفرات أفضل عبر نوع جديد من بنى التحكم الذي سنتعرف عليه في مقال قادم، ألا وهو الدوال functions.
والآن هل تستطيع تجربة الآتي؟
كتابة شيفرة تطبع Hello إذا كانت القيمة 1 مخزنة في المتغير spam
، و World إذا كانت القيمة 2 في المتغير spam
، و Greetings
فيما عدا ذلك. كتابة برنامج قصير يطبع الأرقام من 1 إلى 10 باستخدام حلقة for
. ثم اكتب برنامجًا مكافئًا له يطبع الأرقام من 1 إلى 10 باستخدام حلقة while
.
ترجمة -وبتصرف- للفصل Flow Control من كتاب Automate the boring stuff with Python لصاحبه Al Sweigart.
اقرأ أيضًا
- المقال السابق: أساسيات لغة بايثون Python
- مصطلحات بايثون البرمجية
- أنواع البيانات والعمليات الأساسية في لغة بايثون
- تعلم لغة بايثون
- النسخة العربية الكاملة لكتاب البرمجة بلغة بايثون
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.