البرمجة بلغة بايثون · الفصل 1 — مقدمةמבוא · יסודות התכנות בשפת Python⌂📚🏠
الفصل 1

مقدمة

מבוא
· 10 ساعات تعليمية

قبل أن نكتب أمرا واحدا نسأل: ما الذي يعمله الحاسوب أصلا، وكيف نكلّمه؟ في هذا الفصل نتعرف إلى هندسة الحاسوب، نحلّل مهمة بسيطة، نشغّل أول برنامج، ثم نلتقي بأول كائن: سلحفاة ترسم على الشاشة بالأوامر التي نعطيها لها.

في هذا الفصل:
  • نرى كيف يحل الحاسوب مشكلات من مجالات مختلفة، وما الذي يجعل المشكلة تحديا حسابيا.
  • نحلّل مهمة بسيطة: المعطى، المطلوب والخطوات، ونكتب لها خوارزمية.
  • نكتب برنامجا ونشغّله، نفحصه ونصلح أخطاءه، في بيئة تطوير حقيقية.
  • نميّز بين الفئة والكائن، ونقرأ واجهة فئة جاهزة.
  • نرسم في المستوى بالفئة Turtle، وننشئ منها أكثر من كائن واحد.

1.1 هندسة الحاسوب وتحديات حسابية – הנדסת מחשבים ואתגרים חישוביים

هندسة الحاسوب (הנדסת מחשבים): المجال الذي يصمّم الأجهزة التي تحسب، ويكتب البرامج التي تشغّلها، ويجعل الاثنين يعملان معا. اللوحة الإلكترونية بلا برنامج لا تفعل شيئا، والبرنامج بلا جهاز يشغّله مجرد نص.

الحاسوب ليس فقط الجهاز الذي على الطاولة: يوجد حاسوب صغير في الهاتف، في السيارة، في الغسالة وفي إشارة المرور. نقول إن أمامنا تحديا حسابيا (אתגר חישובי) عندما يكون الحساب نفسه هو العقبة: المعطيات كثيرة جدا، أو الوقت قصير جدا، أو الإمكانات أكثر من أن يجرّبها إنسان. هكذا يدخل الحاسوب إلى مجالات لا علاقة لها في الظاهر بالإلكترونيات:

المجالالتحديما يحسبه الحاسوب
الطبمراقبة قلب مريض طوال اليوميحلّل الإشارة عيّنة بعد عيّنة، وينذر عند اضطراب النبض
النقلأسرع طريق في مدينة مزدحمةيقارن بين عدد هائل من الطرق، ويعيد الحساب كلما تغيّر الازدحام
الطاقةشبكة كهرباء فيها ألواح شمسيةيوازن لحظة بلحظة بين ما يُنتَج وما يُستهلَك
الصناعةفحص كل قطعة على خط إنتاجيقارن صورة كل قطعة بالنموذج خلال جزء من الثانية
مثال 1.1
جهاز تخطيط قلب يأخذ 500 عيّنة من الإشارة في الثانية. كم عيّنة يجمع في يوم كامل؟ ولماذا هذا تحدٍّ حسابي؟
الحل:
500 · 60 · 60 · 24 = 43200000

لا يستطيع طبيب أن ينظر إلى هذا العدد من القيم. البرنامج يمر عليها كلها، ويعرض عليه فقط اللحظات التي فيها شيء غير عادي. الطبيب يقرّر، والحاسوب يوفّر له ما يحتاج إليه كي يقرّر.

خطأ شائع: نقول أحيانا إن الحاسوب «ذكي» أو «فهم» ما نريد. الحقيقة أنه ينفّذ أوامر بسيطة بسرعة هائلة وبلا أي فهم. إذا كان الأمر خاطئا نفّذه بالسرعة نفسها. لذلك يبقى التفكير في الحل علينا.
نشاط: نختار جهازا من البيت أو من الشارع فيه حاسوب مخفي. نناقش في الصف: ما المعطيات التي يأخذها؟ ماذا يحسب؟ ماذا يحدث لو كان في برنامجه خطأ؟
سؤال 1.1: عدّاد كهرباء ذكي يرسل قراءة كل 15 دقيقة. كم قراءة يرسل في السنة؟ ولماذا تحتاج شركة الكهرباء إلى حاسوب كي تستفيد منها؟

1.2 مهام حسابية بسيطة – משימות חישוביות פשוטות

لا نبدأ بالشيفرة، بل بثلاثة أسئلة: ما المعطى؟ ما المطلوب؟ ما الخطوات التي توصلنا من المعطى إلى المطلوب؟ الإجابة عن السؤالين الأولين هي تحليل المهمة (ניתוח המשימה)، والإجابة عن الثالث هي صياغة الحل.

الخوارزمية (אלגוריתם): وصف مرتب لخطوات الحل، دقيق بحيث يصل كل من ينفّذه إلى النتيجة نفسها.
مثال 1.2
على المقاومة ثلاثة أشرطة ملوّنة، والشريط الرابع هو السماح ونتركه الآن. نجد قيمة مقاومة أشرطتها: بنّي، أسود، أحمر.
الحل:
أسودبنّيأحمربرتقاليأصفرأخضرأزرقبنفسجيرماديأبيض
0123456789

المعطى: ثلاثة ألوان، وجدول يحوّل كل لون إلى رقم. المطلوب: قيمة المقاومة بالأوم. الخطوات:

  1. نحوّل لون الشريط الأول إلى رقم. هذا رقم العشرات.
  2. نحوّل لون الشريط الثاني إلى رقم. هذا رقم الآحاد.
  3. نحوّل لون الشريط الثالث إلى رقم، ونسميه n.
  4. نضرب العدد الذي حصلنا عليه من الشريطين الأولين في 10n. الناتج هو القيمة بالأوم.

بنّي يعني 1، أسود يعني 0، فالعدد هو 10. أحمر يعني n = 2:

10 · 102 = 1000 Ω

قد تكون للمهمة نفسها أكثر من خوارزمية صحيحة، وبعضها أفضل من بعض.

مثال 1.3
سلسلة زينة فيها 16 مصباحا موصولة على التوالي. احترق مصباح واحد، فانطفأت كلها. نفصل السلسلة عن المصدر، ومعنا مقياس أوم يخبرنا هل يوصل مقطع منها أم لا. كيف نجد المصباح المحترق؟
الحل:

المعطى: 16 مصباحا، والمقطع الذي فيه المصباح المحترق لا يوصل. المطلوب: المصباح المحترق. نقارن بين خوارزميتين:

الخوارزميةالخطواتالفحوص في أسوأ حالة
واحدا بعد واحدنفحص المصباح الأول، ثم الثاني، وهكذا، حتى نجد الذي لا يوصل15، فإذا سلمت الخمسة عشر فالأخير هو المحترق
التنصيفنفحص نصف السلسلة. إذا وصل فالمحترق في النصف الآخر، وإلا فهو في هذا النصف. ثم ننصّف ما بقي، حتى يبقى مصباح واحد4: من 16 إلى 8، إلى 4، إلى 2، إلى 1

الخوارزميتان صحيحتان، لكن الثانية أوفر بكثير، وكلما طالت السلسلة زاد الفرق. سنعود إلى النجاعة (יעילות) في الفصل 4.

خطأ شائع: خطوة مثل «نقيس عدة مرات ونأخذ قيمة مناسبة» ليست خطوة في خوارزمية: كم مرة؟ وأي قيمة هي المناسبة؟ شخصان ينفّذانها يصلان إلى نتيجتين مختلفتين. الصياغة الصحيحة: «نقيس ثلاث مرات ونأخذ المتوسط».
سؤال 1.2: بطارية 9 V موصولة بمقاومتين على التوالي، 100 Ω و200 Ω. نريد أن نعرف التيار في الدائرة الكهربائية. نكتب المعطى والمطلوب والخطوات.

1.3 لغة البرمجة – שפת תכנות

المعالج لا يفهم إلا أوامر بسيطة جدا مكتوبة بأصفار وآحاد، ونحن لا نستطيع أن نكتب برامج طويلة بهذه الطريقة. كما أن العربية والعبرية لا تصلحان، لأن الجملة فيهما قد تحتمل أكثر من معنى. لغة البرمجة هي الحل الوسط بينهما.

لغة البرمجة (שפת תכנות): لغة صناعية لها كلمات محددة وقواعد صارمة، يكتبها الإنسان وتُترجَم إلى أوامر ينفّذها الحاسوب. قواعد الكتابة فيها تسمى النحو.

نكتب في هذا الكتاب بلغة بايثون Python. برنامج يسمى المفسّر (מפרש) يقرأ ما كتبنا، يفحص أولا صحة الكتابة، ثم ينفّذ الأوامر واحدا بعد واحد:

البرنامج الذي كتبناهالمفسّرأوامر للمعالج

لكل لغة كلماتها، لكن الفكرة واحدة. هذا الأمر نفسه، طباعة جملة على الشاشة، في ثلاث لغات:

اللغةأين نلتقيهاالأمر
Pythonهذا الكتاب، تحليل المعطيات، الاتصال بالأجهزةprint("Power on")
C++لوحة أردوينوSerial.println("Power on");
C#تطبيقات الحاسوبConsole.WriteLine("Power on");
خطأ شائع: لغة البرمجة لا تتسامح. نفهم نحن جملة فيها خطأ إملائي، أما المفسّر فلا: print وPrint كلمتان مختلفتان، لأن الحروف الكبيرة والصغيرة مختلفة.
سؤال 1.3: أي هذه الأسطر صحيح في بايثون؟
(أ) print("Ready")
(ب) Print("Ready")
(ج) print("Ready
(د) print "Ready"

1.4 البرنامج: قراءة، كتابة، تشغيل، فحص وتصحيح – התוכנית: קריאה, כתיבה, הרצה, בדיקה ותיקון

البرنامج (תוכנית): سلسلة أوامر مكتوبة بلغة برمجة، ينفّذها الحاسوب بالترتيب: من السطر الأول إلى الأخير.

العمل على برنامج ليس كتابة مرة واحدة ثم انتهينا، بل دورة نكررها حتى يصبح صحيحا. ونادرا ما يعمل البرنامج بشكل صحيح من المرة الأولى، وهذا عادي:

كتابةتشغيلفحصانتهيناقراءة الخطأ وتصحيحهصحيحخطأ

القراءة. نقرأ البرنامج من الأعلى إلى الأسفل، ونتوقع ماذا سيفعل قبل أن نشغّله. الدالة print تطبع على الشاشة ما بين القوسين. والسطر الذي يبدأ بالإشارة # هو تعليق (הערה): كتبناه لمن يقرأ، والمفسّر يتجاهله. والترتيب هو البرنامج: الأوامر نفسها بترتيب آخر تعطي مُخرَجا آخر.

print("Sensor test")
print("Reading:", 25)
# the next line runs last
print("Done")
المُخرَج
Sensor test
Reading: 25
Done
print("Done")
print("Sensor test")
print("Reading:", 25)
المُخرَج
Done
Sensor test
Reading: 25

الكتابة. نكتب أمرا واحدا في كل سطر، ونحفظ البرنامج في ملف نهاية اسمه .py.

خطأ شائع: في بايثون للمسافة في بداية السطر معنى، كما سنرى في الفصل 3. في البرامج التي نكتبها الآن يبدأ كل سطر من العمود الأول:
print("Start")
    print("End")
المُخرَج
IndentationError: unexpected indent

التشغيل. نطلب من المفسّر أن ينفّذ البرنامج، وما يطبعه هو المُخرَج (פלט). الفحص. نقارن المُخرَج بما توقعناه. التصحيح. إذا اختلفا نبحث عن السبب، نصلحه، ونشغّل من جديد.

مثال 1.4
نعود إلى الدائرة الكهربائية من السؤال 1.2 ونكتب برنامجا يطبع التيار فيها. نتابع ثلاث محاولات، وفي كل واحدة خطأ من نوع مختلف.
الحل:

المحاولة الأولى: نسينا علامة الاقتباس التي تغلق الجملة، فرفض المفسّر البرنامج كله، ولم يُطبع حتى السطر الأول. المحاولة الثانية: أغلقنا الجملة، لكننا كتبنا حرفا كبيرا. هذه المرة نُفّذ السطر الأول، وتوقف البرنامج عند الخطأ.

print("Battery check")
print("Voltage: 9 V)
المُخرَج
SyntaxError: unterminated string literal (detected at line 2)
print("Battery check")
Print("Voltage: 9 V")
المُخرَج
Battery check
NameError: name 'Print' is not defined

المحاولة الثالثة: لا رسالة خطأ. لكن هل المُخرَج صحيح؟ تيار يزيد على 200 A من بطارية صغيرة؟ مستحيل. الحاسوب قسم 9 على 100 أولا ثم أضاف 200، ونحن نريد أن يجمع المقاومتين قبل القسمة. نضيف قوسين، فنحصل على البرنامج الثاني:

print("Battery check")
print("Voltage: 9 V")
print("Current:", 9 / 100 + 200, "A")
المُخرَج
Battery check
Voltage: 9 V
Current: 200.09 A
print("Battery check")
print("Voltage: 9 V")
print("Current:", 9 / (100 + 200), "A")
المُخرَج
Battery check
Voltage: 9 V
Current: 0.03 A

الآن المُخرَج معقول، ويطابق ما نحسبه بأيدينا: 9 مقسومة على 300. وسنتعلم المعاملات الحسابية بالتفصيل في الفصل 2.

ملاحظة: المحاولة الثالثة هي الأخطر: البرنامج يعمل ولا يشكو. لذلك لا يكفي أن يعمل البرنامج، بل نفحصه دائما على مثال نعرف نتيجته.
سؤال 1.4: ماذا يطبع البرنامج التالي؟
print("A")
print()
print("B", "C")
print(2 + 3)
print("2 + 3")

1.5 بيئة التطوير وأول برنامج – סביבת הפיתוח ותוכנית ראשונה

بيئة التطوير (סביבת פיתוח): برنامج يجمع في مكان واحد كل ما نحتاج إليه كي نبرمج: محررا نكتب فيه، مفسّرا يشغّل ما كتبنا، ونافذة نرى فيها المُخرَج ورسائل الخطأ.

توصي خطة التعليم بأن نتعرف إلى بيئتين: بيئة على الإنترنت، وبيئة نثبّتها على الحاسوب. نتعرف هنا إلى Google Colab وإلى IDLE. توجد بيئات أخرى مثل Visual Studio Code وPyCharm، والبرنامج نفسه يعمل فيها كلها.

Google ColabIDLE
أين يعملفي المتصفح، والبرنامج يعمل على خادم بعيدعلى حاسوبنا
ما نحتاج إليهحساب Google واتصال بالإنترنتتثبيت بايثون من الموقع python.org، وIDLE يأتي معه
أين يُحفظ العملدفتر في Google Driveملف .py على الحاسوب
Turtleلا يعمل، فالخادم البعيد لا شاشة لهيعمل، وتُفتح له نافذة

في Google Colab:

  1. ندخل إلى colab.research.google.com ونختار دفترا جديدا.
  2. نكتب البرنامج في المربع الذي يظهر، وهو الخلية.
  3. نضغط زر التشغيل بجانب الخلية، أو Shift+Enter، فيظهر المُخرَج تحتها.

في IDLE:

  1. نفتح IDLE، فتظهر نافذة Shell.
  2. نختار File > New File، ونكتب البرنامج في النافذة الجديدة.
  3. نحفظ بواسطة File > Save باسم مثل first.py.
  4. نضغط F5، فيظهر المُخرَج في نافذة Shell.

أول برنامج لنا سطر واحد. الدالة print تطبع ما بين القوسين، وتنتقل إلى السطر التالي. والنص بين علامتي الاقتباس يُطبع حرفا بحرف. وإذا لم يكن بين القوسين شيء طُبع سطر فارغ، كما في البرنامج الثاني:

print("Hello from the lab")
المُخرَج
Hello from the lab
print("Measuring station")
print("Power on")
print()
print("Ready")
المُخرَج
Measuring station
Power on

Ready

ما بين علامتي الاقتباس يُطبع كما هو، وما ليس بينهما يُحسب أولا. وعندما نفصل بين القيم بفاصلة، تطبعها print في السطر نفسه مع مسافة بينها.

خطأ شائع: إذا نسخنا الشيفرة من Word أو من موقع، قد تصل علامات الاقتباس مائلة بدل المستقيمة. تبدو متشابهة لنا، لكنها حروف أخرى عند المفسّر، كما في البرنامج الثاني:
print("7 * 6")
print(7 * 6)
print("Seconds:", 24 * 60 * 60)
المُخرَج
7 * 6
42
Seconds: 86400
print(“Power on”)
المُخرَج
SyntaxError: invalid character '“' (U+201C)
سؤال 1.5: نكتب برنامجا يطبع أجزاء محطة قياس، كل جزء في سطر: Solar panel ، Battery ، Gauge
▶تجربة حية — مختبر البرنامج الأولنكتب في المحرر أوامر print ونشغّلها، ونجرّب أعطالا جاهزة ونقرأ رسائل الخطأ، وقد يظهر بعضها في المختبر بالعبرية. لا يوجد في المختبر import، ولذلك نشغّل برامج Turtle في IDLE.
⚠
المختبر غير متاح الآن. المادة في هذا الفصل كاملة من دونه — نواصل القراءة، ونعود إلى التجربة لاحقا أو نفتحها مباشرة من الرابط الذي تحت الإطار.
https://fahed-lab.com/electronics/python_basics#intro
نفتح المختبر في صفحة مستقلة ↗ fahed-lab.com/electronics/python_basics#intro

1.6 الكائن نسخة من فئة – העצם כמופע של מחלקה

نفتح خزانة المختبر فنجد اثني عشر مقياسا متعددا من الطراز نفسه. لها كلها الأزرار نفسها والقدرات نفسها، لأنها صُنعت حسب تصميم واحد. لكن كل مقياس شيء مستقل: هذا على مجال 20 V ويقرأ 11.9، وذاك مطفأ.

الفئة (מחלקה): وصف عام لنوع من الأشياء: ما الذي يحمله كل واحد منها، وما الذي يستطيع أن يفعله.
الكائن (עצם): شيء محدد صُنع حسب الفئة. نقول إنه نسخة من الفئة (מופע). قد نصنع من الفئة الواحدة كائنات كثيرة.

ما يحمله الكائن يسمى الصفات (תכונות)، وما يستطيع أن يفعله يسمى العمليّات (פעולות). الكائنات تشترك في أسماء الصفات وفي العمليّات، أما قيم الصفات فلكل كائن قيمه:

الفئة: مقياس متعددالصفات: المجال، القراءة، الشحنالعمليّات: تشغيل، اختيار المجال، قياسالكائن: المقياس 1المجال: ‎20 V‎القراءة: ‎11.9 V‎الشحن: ‎80%‎الكائن: المقياس 2المجال: ‎2 A‎القراءة: ‎0.5 A‎الشحن: ‎35%‎الكائن: المقياس 3المجال: ‎200 V‎القراءة: ‎0 V‎الشحن: ‎100%‎نسخة
فئة واحدة وثلاثة كائنات: العمليّات نفسها، وقيم الصفات مختلفة
الفئةكائنان منهاصفاتعمليّات
ثنائي باعث للضوءالأحمر الذي على اللوحة، والأخضر بجانبهاللون، مضاء أم لاإضاءة، إطفاء
بطاريةبطارية السيارة، وبطارية جهاز الإنذارالجهد، السعةشحن، تفريغ
هاتفهاتفي، وهاتف صديقيالرقم، الشحناتصال، إرسال رسالة
ملاحظة: في النص العربي الرسمي للامتحان تُكتب الفئة «قسم» والكائن «جسم». في هذا الكتاب نبقى مع «فئة» و«كائن»، وإذا رأينا الكلمة الأخرى في الامتحان عرفنا أن المعنى واحد.
خطأ شائع: لا نخلط بين الاثنين: الفئة لا تقيس شيئا، فهي التصميم فقط، والذي يقيس هو مقياس محدد. وعندما نغيّر مجال مقياس واحد لا يتغيّر مجال الآخر.
سؤال 1.6: نختار الفئة «مروحة». نكتب لها صفتين وعمليّتين، ونصف كائنين منها.

1.7 فئة جاهزة: Turtle – מחלקה קיימת: Turtle

تأتي مع بايثون فئات جاهزة كثيرة. نبدأ بفئة نرى عملها بأعيننا: Turtle، أي السلحفاة. نتخيل سلحفاة صغيرة تمشي على الشاشة وتجرّ قلما، فترسم خطا حيث تمشي. كائن من هذه الفئة يظهر كسهم صغير، ونعطيه الأوامر فيتحرك.

نافذة Turtle هي مستوى ثنائي الأبعاد (מישור דו-ממדי) له محوران. النقطة (0, 0) في وسط النافذة، x يكبر نحو اليمين، وy يكبر نحو الأعلى. كل نقطة تُكتب (x, y)، وx أولا دائما. يولد الكائن في (0, 0) واتجاهه نحو اليمين. الأمران forward وbackward يحرّكانه في اتجاهه الحالي، والأمران right وleft يديرانه في مكانه، بالدرجات.

xy-150-100-5050100150-100-5050100(100, 50)(-100, 50)(-50, -100)(0, 0)
المستوى: السهم في وضع البداية، وثلاث نقاط للتوضيح
forwardbackwardleft(90)right(90)
الأوامر الأربعة، بالنسبة إلى اتجاه السهم

برنامج Turtle الأول:

import turtle
pen = turtle.Turtle()
pen.forward(100)
print(pen.position())
turtle.done()
المُخرَج
(100.00,0.00)
50100
ما تعرضه النافذة بعد التشغيل
ملاحظة: الشبكة والأرقام في رسوم الكتاب أضفناها كي نقرأ الإحداثيات بسهولة. النافذة الحقيقية بيضاء، وفيها الخطوط والسهم فقط.
خطأ شائع: لا نسمّي ملف البرنامج turtle.py: عندها يجد import turtle ملفنا نحن بدل الوحدة الجاهزة، ويتوقف البرنامج. نسميه مثلا draw1.py. ولا نجرّب Turtle في Google Colab، بل نستعمل IDLE أو بيئة أخرى على الحاسوب.

الحركة والدوران:

الدوران نفسه لا يرسم شيئا ولا يغيّر الموقع: left تغيّر الاتجاه فقط، والتقدم بعدها يكون في الاتجاه الجديد. والأمر backward يعيد الكائن إلى الخلف على الخط نفسه من دون أن يدور، ولذلك يبقى السهم متجها نحو الأعلى:

import turtle
pen = turtle.Turtle()
pen.forward(100)
pen.left(90)
pen.forward(50)
pen.backward(20)
print(pen.position())
turtle.done()
المُخرَج
(100.00,30.00)
5010050
السهم يقف في (100, 30) واتجاهه نحو الأعلى
خطأ شائع: الاتجاهان right وleft هما بالنسبة إلى السهم، لا بالنسبة إلى الصفحة. إذا كان السهم متجها نحو الأسفل، فإن right(90) تديره نحو اليسار في الصفحة.
مثال 1.5
نرسم مربعا ضلعه 100.
الحل:

نتقدم وندور، أربع مرات:

import turtle
pen = turtle.Turtle()
pen.forward(100)
pen.right(90)
pen.forward(100)
pen.right(90)
pen.forward(100)
pen.right(90)
pen.forward(100)
pen.right(90)
turtle.done()
50100-100-50

هذا يعمل، لكننا كتبنا الزوج نفسه من الأوامر أربع مرات. ماذا لو أردنا شكلا له 20 ضلعا؟ في الفصل 4 نتعلم الحلقة، أي أن نقول للحاسوب «كرّر هذا»، فنكتب زوج الأوامر مرة واحدة فقط.

رفع القلم واللون:

الأمر penup يرفع القلم، فيتحرك الكائن بعده من دون أن يرسم، والأمر pendown يعيده إلى الورقة. ولهما اسمان أقصر: up وdown. والأمر color يغيّر لون القلم، واسم اللون جملة نصية بالإنجليزية بين علامتي اقتباس، ويسري على كل ما يُرسم بعده. نرسم بها تدريجا بلونين:

import turtle
pen = turtle.Turtle()
pen.color("green")
pen.forward(80)
pen.penup()
pen.forward(15)
pen.pendown()
pen.color("red")
pen.forward(40)
pen.up()
pen.forward(15)
pen.down()
pen.forward(40)
turtle.done()
50100150200
لونان وفراغان

الانتقال إلى نقطة:

الأمر goto(x, y) ينقل الكائن مباشرة إلى النقطة (x, y) في خط مستقيم، من دون أن يغيّر اتجاهه. وهو مريح عندما نعرف الإحداثيات، إذ لا نحتاج إلى حساب أي زاوية:

import turtle
pen = turtle.Turtle()
pen.goto(50, 50)
pen.goto(100, 0)
pen.goto(150, 50)
pen.goto(200, 0)
print(pen.position())
turtle.done()
المُخرَج
(200.00,0.00)
5010015020050
إشارة مثلثة، بلا أي زاوية
خطأ شائع: إذا كان القلم على الورقة فإن goto يرسم خطا في الطريق. وإذا أردنا الانتقال إلى مكان آخر بلا خط، نرفع القلم قبله ونعيده بعده.
سؤال 1.7: أين يقف الكائن في نهاية البرنامج؟ نجيب قبل التشغيل.
import turtle
pen = turtle.Turtle()
pen.forward(50)
pen.left(90)
pen.forward(30)
pen.backward(10)
print(pen.position())
turtle.done()

1.8 قراءة واجهة بسيطة لفئة – קריאת ממשק פשוט של מחלקה

كي نستعمل المقياس المتعدد لا نحتاج إلى أن نعرف ما في داخله. يكفي أن نعرف الأزرار والمآخذ. وهكذا الفئة الجاهزة.

الواجهة (ממשק): قائمة العمليّات التي تعرضها الفئة لمن يستعملها: اسم كل عمليّة، ما الذي تحتاج إليه بين القوسين، وما الذي تفعله أو تعيده.

ما تحتاج إليه العمليّة بين القوسين يسمى الوسيط (פרמטר)، ونحن نكتب هناك القيمة التي نعطيها له. هذه واجهة ما تعلمناه حتى الآن من الفئة Turtle:

العمليّةالوسائطعملها
Turtle()لا شيءتنشئ كائنا جديدا في (0, 0)، واتجاهه نحو اليمين
forward(d)عدد: مسافةيتقدم d في اتجاهه الحالي
backward(d)عدد: مسافةيتراجع d من دون أن يدور
right(a)عدد: زاوية بالدرجاتيدور في مكانه إلى يمينه
left(a)عدد: زاوية بالدرجاتيدور في مكانه إلى يساره
penup() , up()لا شيءيرفع القلم
pendown() , down()لا شيءيعيد القلم إلى الورقة
color(name)جملة نصية: اسم اللونيغيّر لون القلم
goto(x, y)عددان: إحداثيانينتقل إلى النقطة، ويرسم إذا كان القلم نازلا
position()لا شيءتعيد الموقع الحالي ولا تطبعه

نقرأ كل سطر بثلاثة أسئلة. كم وسيطا تحتاج العمليّة؟ من أي نوع؟ وهل تفعل شيئا أم تعيد قيمة؟ العمليّة forward تحرّك الكائن ولا تعيد لنا شيئا. والعمليّة position لا تحرّك شيئا، بل تعيد قيمة، وإذا لم نستعمل هذه القيمة ضاعت. لذلك لا يطبع السطر الرابع في البرنامج الأول أدناه شيئا، والذي يطبع هو الخامس.

خطأ شائع: الواجهة تُقرأ حرفيا. بلا قوسين لا تُستدعى العمليّة، والأسوأ أن المفسّر لا يشكو: البرنامج الثاني يعمل، والكائن لا يتحرك.
import turtle
pen = turtle.Turtle()
pen.forward(80)
pen.position()
print(pen.position())
turtle.done()
المُخرَج
(80.00,0.00)
import turtle
pen = turtle.Turtle()
pen.forward
print(pen.position())
turtle.done()
المُخرَج
(0.00,0.00)

واسم مختلف بحرف واحد، أو قيمة من نوع آخر نعطيها للوسيط، يوقفان البرنامج. العمليّة تطلب عددا، والجملة النصية "100" ليست عددا، ولذلك تبدأ رسالة الخطأ الثانية بالكلمة TypeError، أي خطأ في نوع القيمة، وبقيتها تصف الحساب الداخلي الذي فشل:

import turtle
pen = turtle.Turtle()
pen.Forward(100)
المُخرَج
AttributeError: 'Turtle' object has no attribute 'Forward'. Did you mean: 'forward'?
import turtle
pen = turtle.Turtle()
pen.forward("100")
المُخرَج
TypeError: can't multiply sequence by non-int of type 'float'

الفائدة الحقيقية من قراءة الواجهة أننا نستطيع أن نستعمل عمليّة لم نرها من قبل. هذه عمليّات أخرى من الواجهة نفسها:

العمليّةالوسائطعملها
circle(r)عدد: نصف قطريرسم دائرة، مركزها على بعد r إلى يسار السهم، ويعود إلى نقطة البداية
dot(size, color)عدد وجملة نصيةيرسم نقطة ممتلئة بالقطر واللون المطلوبين، حتى لو كان القلم مرفوعا
pensize(w)عدد: سماكةيغيّر سماكة الخط
write(text)جملة نصيةيكتب النص عند الموقع الحالي
hideturtle()لا شيءيخفي السهم، ويبقى الرسم
مثال 1.6
نرسم رمز المصباح: دائرة في داخلها خطان متقاطعان.
الحل:

نقرأ في الواجهة أن مركز circle(40) على بعد 40 إلى يسار السهم. السهم متجه نحو اليمين، إذن المركز هو (0, 40). نقاط الخطين نحسبها حول هذا المركز، ونرفع القلم قبل كل انتقال:

import turtle
pen = turtle.Turtle()
pen.pensize(2)
pen.circle(40)
pen.up()
pen.goto(-28, 12)
pen.down()
pen.goto(28, 68)
pen.up()
pen.goto(-28, 68)
pen.down()
pen.goto(28, 12)
pen.up()
pen.goto(50, 30)
pen.write("Lamp")
pen.hideturtle()
turtle.done()
-505010050100Lamp
رمز المصباح، من الواجهة فقط
ملاحظة: الواجهة الكاملة في توثيق بايثون، على الموقع docs.python.org، وفيها عمليّات كثيرة. ويمكن أن نكتب في نافذة Shell الأمر help(turtle.Turtle.forward) بعد import turtle، فتظهر هناك واجهة هذه العمليّة.
سؤال 1.8: فئة لثنائي باعث للضوء لها هذه الواجهة: on() بلا وسائط، off() بلا وسائط، brightness(percent) بوسيط عددي من 0 إلى 100، وis_on() تعيد True أو False. عندنا كائن اسمه led. نكتب أوامر تشغّله بنصف الإضاءة، ثم تطبع هل هو مضاء.

1.9 إنشاء كائنات جديدة – יצירת עצמים חדשים

في كل مرة نستدعي turtle.Turtle() تولد نسخة جديدة. ولكل كائن موقعه واتجاهه ولونه، فالأمر الذي نعطيه لكائن لا يؤثر في غيره. اسم الكائن قبل النقطة هو الذي يحدد من ينفّذ:

import turtle
pen_a = turtle.Turtle()
pen_b = turtle.Turtle()
pen_a.color("red")
pen_b.color("blue")
pen_a.forward(100)
pen_b.left(90)
pen_b.forward(60)
print(pen_a.position())
print(pen_b.position())
turtle.done()
المُخرَج
(100.00,0.00)
(0.00,60.00)
5010050
كائنان من الفئة نفسها
مثال 1.7
على شاشة محلل منطقي نرى إشارة الساعة وإشارة المعطيات، واحدة فوق الأخرى. نرسمهما بكائنين، لكل إشارة قلمها.
الحل:

ننشئ الكائن clock، نرفع قلمه، نكتب الاسم، ثم نرسم بواسطة goto. ثم ننشئ data ونفعل مثل ذلك:

import turtle
clock = turtle.Turtle()
clock.color("blue")
clock.up()
clock.goto(4, 68)
clock.write("CLK")
clock.goto(0, 60)
clock.down()
clock.goto(0, 90)
clock.goto(40, 90)
clock.goto(40, 60)
clock.goto(80, 60)
clock.goto(80, 90)
clock.goto(120, 90)
clock.goto(120, 60)
clock.goto(160, 60)
clock.hideturtle()
data = turtle.Turtle()
data.color("red")
data.up()
data.goto(4, 6)
data.write("DATA")
data.goto(0, 0)
data.down()
data.goto(80, 0)
data.goto(80, 30)
data.goto(160, 30)
data.hideturtle()
turtle.done()
5010015050100CLKDATA
إشارتان بكائنين: كل كائن يتذكر موقعه ولونه
خطأ شائع: السطر pen_b = pen_a لا يُنشئ كائنا: لا يوجد هنا Turtle()، بل اسمان لكائن واحد. لذلك يوجد في الرسم سهم واحد، وما نفعله بأحد الاسمين يحدث للكائن نفسه:
import turtle
pen_a = turtle.Turtle()
pen_b = pen_a
pen_a.forward(100)
pen_b.left(90)
pen_b.forward(50)
print(pen_a.position())
print(pen_b.position())
turtle.done()
المُخرَج
(100.00,50.00)
(100.00,50.00)
5010050
اسمان، كائن واحد، خط واحد
سؤال 1.9: ماذا يطبع البرنامج؟ نلاحظ أن goto لا يغيّر اتجاه الكائن.
import turtle
pen_a = turtle.Turtle()
pen_b = turtle.Turtle()
pen_a.goto(40, 40)
pen_b.backward(30)
pen_a.forward(10)
print(pen_a.position())
print(pen_b.position())
turtle.done()
مشروع الكتاب: محطة القياس · المرحلة 1 — المحطة مرسومة

يرافقنا في هذا الكتاب مشروع واحد ينمو من فصل إلى فصل: محطة قياس تعمل ببطارية ولوح شمسي. في الفصل 2 تقرأ قياساتها، وفي الفصل 3 تقرّر، وفي الفصل 6 تتذكّر، وفي الفصل 10 تتصل بلوحة أردوينو حقيقية. نبدأ بما نستطيعه الآن: نرسم مخططها، وفيه اللوح الشمسي، البطارية والمبيّن. لكل جزء كائن خاص به، ولكل كائن لونه.

import turtle

panel = turtle.Turtle()
panel.color("blue")
panel.pensize(2)
panel.up()
panel.goto(-200, 125)
panel.write("PANEL")
panel.goto(-200, 60)
panel.down()
panel.goto(-100, 60)
panel.goto(-100, 120)
panel.goto(-200, 120)
panel.goto(-200, 60)
panel.up()
panel.goto(-150, 60)
panel.down()
panel.goto(-150, 120)
panel.hideturtle()

wire = turtle.Turtle()
wire.up()
wire.goto(-100, 90)
wire.down()
wire.goto(120, 90)
wire.up()
wire.goto(-150, 60)
wire.down()
wire.goto(-150, -30)
wire.goto(150, -30)
wire.goto(150, 60)
wire.up()
wire.goto(0, 90)
wire.dot(8)
wire.down()
wire.goto(0, 35)
wire.up()
wire.goto(0, -30)
wire.dot(8)
wire.down()
wire.goto(0, 25)
wire.hideturtle()

cell = turtle.Turtle()
cell.color("red")
cell.pensize(3)
cell.up()
cell.goto(-25, 35)
cell.down()
cell.goto(25, 35)
cell.up()
cell.goto(-12, 25)
cell.down()
cell.goto(12, 25)
cell.up()
cell.goto(32, 24)
cell.write("BATTERY")
cell.hideturtle()

gauge = turtle.Turtle()
gauge.color("green")
gauge.pensize(2)
gauge.up()
gauge.goto(150, 60)
gauge.down()
gauge.circle(30)
gauge.up()
gauge.goto(150, 90)
gauge.down()
gauge.goto(168, 110)
gauge.up()
gauge.goto(125, 126)
gauge.write("GAUGE")
gauge.hideturtle()

turtle.done()
-200-150-100-5050100150200-5050100150PANELBATTERYGAUGE
مخطط المحطة: من رسم أربعة كائنات من الفئة Turtle

البرنامج طويل، لأننا نكرر الأوامر نفسها مرة بعد مرة. لا بأس: في الفصلين 4 و7 نتعلم كيف نختصره. نجرّب بأنفسنا: نضيف إلى الخط السفلي مقاومة حمل على شكل مستطيل صغير، ونسأل: أين يجب أن نرفع القلم؟

أهمّ أفكار الفصل:

ملخّص أوامر الفصل:

الأمرعمله
print("text", 2 + 3)الطباعة على الشاشة
# commentتعليق يتجاهله المفسّر
import turtleجلب الوحدة الجاهزة
pen = turtle.Turtle()إنشاء كائن جديد واسمه pen
pen.forward(d) pen.backward(d)الحركة في الاتجاه الحالي
pen.right(a) pen.left(a)الدوران في المكان
pen.penup() pen.pendown()رفع القلم وإنزاله
pen.up() pen.down()اسمان أقصر للأمرين السابقين
pen.color("red")لون القلم
pen.goto(x, y)الانتقال إلى نقطة
pen.position()الموقع الحالي، قيمة تعود إلينا
turtle.done()إبقاء النافذة مفتوحة

قاموس المصطلحات – מילון מונחים:

بالعربيةبالعبرية (كما تظهر في الامتحان)English
هندسة الحاسوبהנדסת מחשביםComputer engineering
تحدٍّ حسابيאתגר חישוביComputational challenge
الخوارزميةאלגוריתםAlgorithm
تحليل المهمةניתוח המשימהTask analysis
لغة البرمجةשפת תכנותProgramming language
النحوתחבירSyntax
المفسّرמפרשInterpreter
البرنامجתוכניתProgram
التعليقהערהComment
المُخرَجפלטOutput
بيئة التطويرסביבת פיתוחDevelopment environment (IDE)
الفئةמחלקהClass
الكائنעצםObject
النسخةמופעInstance
الصفةתכונהAttribute
العمليّةפעולהMethod
الوسيطפרמטרParameter
الواجهةממשקInterface
الإجابات النهائية لأسئلة الفصل
1.1 في الساعة 4 قراءات، وفي السنة 35040 قراءة من كل عدّاد. وعندما يكون في المدينة مئات آلاف العدّادات لا يستطيع إنسان أن يقرأها، أما البرنامج فيجمعها ويكشف الأعطال والاستهلاك غير العادي.
1.2 المعطى: الجهد والمقاومتان. المطلوب: التيار. الخطوات: نجمع المقاومتين، ثم نقسم الجهد على المجموع. سنشغّل هذا الحساب في البند 1.4.
1.3 السطر (أ) فقط. في (ب) حرف كبير، في (ج) تنقص علامة الاقتباس والقوس، وفي (د) تنقص الأقواس.
1.4 A ، سطر فارغ ، B C , 5 , 2 + 3
1.5
print("Solar panel")
print("Battery")
print("Gauge")
1.6 مثلا: الصفتان: السرعة، الجهد. العمليّتان: تشغيل، تغيير السرعة. الكائن الأول: مروحة الصندوق، سرعتها منخفضة، 12 V. الكائن الثاني: مروحة الحاسوب، سرعتها عالية، 5 V.
1.7 (50.00,20.00)
1.8 led.on() ، led.brightness(50) ، print(led.is_on())
1.9 (50.00,40.00) , (-30.00,0.00)

أسئلة للتمرين:

المستوى الأول — أساسي
1.
ماذا يطبع البرنامج؟
print("9 * 9")
print(9 * 9)
print()
print("Done", 9 + 9)
الإجابات: 9 * 9 , 81 ، سطر فارغ ، Done 18
2.
في البرنامج التالي ثلاثة أخطاء. نجدها ونصلحها، ونقول: في أي ترتيب يخبرنا المفسّر عنها؟
Print("Lab 3")
print("Voltage: 5 V)
    print("End")
الإجابات: يخبرنا أولا عن علامة الاقتباس الناقصة، ثم عن المسافة في بداية السطر الأخير، لأنهما من أخطاء النحو ويُفحصان قبل التشغيل. وأخيرا عن الحرف الكبير في Print، لأن هذا لا يُكتشف إلا عند التنفيذ.
print("Lab 3")
print("Voltage: 5 V")
print("End")
3.
ماذا يُرسم؟ وأين يقف الكائن في النهاية؟ نرسم باليد قبل أن نقرأ الجواب.
import turtle
pen = turtle.Turtle()
pen.forward(80)
pen.left(90)
pen.forward(40)
pen.right(90)
pen.forward(80)
pen.right(90)
pen.forward(40)
print(pen.position())
turtle.done()
الإجابات: يقف الكائن في (160.00,0.00).
5010015050
4.
نكتب برنامجا يرسم مستطيلا عرضه 120 وارتفاعه 60، باستعمال forward وleft فقط.
الإجابات:
import turtle
pen = turtle.Turtle()
pen.forward(120)
pen.left(90)
pen.forward(60)
pen.left(90)
pen.forward(120)
pen.left(90)
pen.forward(60)
turtle.done()
5010050
المستوى الثاني — متوسط
5.
نستعمل خوارزمية البند 1.2 كي نجد قيمة مقاومة أشرطتها: أصفر، بنفسجي، برتقالي.
الإجابات: أصفر يعني 4، بنفسجي يعني 7، فالعدد 47. برتقالي يعني n = 3. القيمة: 47000 أوم.
6.
نكتب برنامجا يرسم خطا متقطعا عموديا نحو الأعلى: ثلاثة مقاطع طول كل منها 30، وبينها فراغان طول كل منهما 20. ثم نطبع الموقع.
الإجابات:
import turtle
pen = turtle.Turtle()
pen.left(90)
pen.forward(30)
pen.up()
pen.forward(20)
pen.down()
pen.forward(30)
pen.up()
pen.forward(20)
pen.down()
pen.forward(30)
print(pen.position())
turtle.done()
50100150
يطبع: (0.00,130.00)
7.
نستعين بواجهة البند 1.8 ونرسم ثلاثة مصابيح بيان، كل منها نقطة قطرها 30: أحمر، برتقالي وأخضر، وبين كل مصباحين مسافة 50، بلا أي خط بينها.
الإجابات:
import turtle
pen = turtle.Turtle()
pen.up()
pen.dot(30, "red")
pen.forward(50)
pen.dot(30, "orange")
pen.forward(50)
pen.dot(30, "green")
pen.hideturtle()
turtle.done()
50100
المستوى الثالث — تحدٍّ
8.
طرفا بطارية يوصلان إلى مصباح: السلك الأحمر plus يبدأ من (0, 40)، ويصل إلى (120, 25). والسلك الأسود minus يبدأ من (0, 0)، ويصل إلى (120, 15). نرسم السلكين بكائنين، بزوايا قائمة فقط، ونطبع موقع النهاية لكل منهما.
الإجابات:
import turtle
plus = turtle.Turtle()
minus = turtle.Turtle()
plus.color("red")
minus.color("black")
plus.up()
plus.goto(0, 40)
plus.down()
plus.goto(120, 40)
plus.goto(120, 25)
minus.goto(120, 0)
minus.goto(120, 15)
print(plus.position())
print(minus.position())
turtle.done()
5010050
يطبع: (120.00,25.00) , (120.00,15.00)
9.
شاشة سبع قطع تعرض الرقم 2 بخمس قطع متصلة. نرسمه بخط سميك، عرضه 50 وارتفاعه 100، من دون أن نرسم أي قطعة مرتين، ونخفي السهم.
الإجابات:
import turtle
pen = turtle.Turtle()
pen.pensize(4)
pen.up()
pen.goto(0, 100)
pen.down()
pen.goto(50, 100)
pen.goto(50, 50)
pen.goto(0, 50)
pen.goto(0, 0)
pen.goto(50, 0)
pen.hideturtle()
turtle.done()
5050100
10.
نرسم مسدسا منتظما ضلعه 60. زاوية الدوران لمضلع منتظم له n أضلاع هي 360 مقسومة على n. كم أمرا نحتاج إليه للأضلاع والدوران؟ وكم أمرا كنا سنحتاج إليه لمضلع له 100 ضلع؟
الإجابات: الزاوية هي 60 درجة، ونحتاج إلى 12 أمرا: أمرين لكل ضلع. ولمضلع له 100 ضلع نحتاج إلى 200 أمر، ولذلك نحتاج إلى الحلقة في الفصل 4.
import turtle
pen = turtle.Turtle()
pen.forward(60)
pen.left(60)
pen.forward(60)
pen.left(60)
pen.forward(60)
pen.left(60)
pen.forward(60)
pen.left(60)
pen.forward(60)
pen.left(60)
pen.forward(60)
pen.left(60)
turtle.done()
-505010050100