<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; &#x639;&#x627;&#x645;&#x629; &#x62D;&#x648;&#x644; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;</title><link>https://academy.hsoub.com/programming/general/page/10/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; &#x639;&#x627;&#x645;&#x629; &#x62D;&#x648;&#x644; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;</description><language>ar</language><item><title>&#x62A;&#x639;&#x644;&#x645; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x628;&#x644;&#x63A;&#x629; Awk &#x639;&#x628;&#x631; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x644;&#x639;&#x628;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-awk-%D8%B9%D8%A8%D8%B1-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-r1390/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_12/61ae010d634d2_07___Awk__-0-0-0-0-0-0-0-0.png.8dc74c985b7a42a679730c2a0c014efb.png" /></p>
<p>
	تتشارك أغلب لغات البرمجة في العديد من المزايا. من أفضل الطرق لتعلم لغة برمجة جديدة هي كتابة برنامج مألوف. في هذا المقال، سنتعلم كيف ننشئ لعبة "احزر الرقم" <a href="https://academy.hsoub.com/devops/linux/%d9%83%d9%8a%d9%81%d9%8a%d8%a9-%d8%a7%d8%b3%d8%aa%d8%ae%d8%af%d8%a7%d9%85-%d9%84%d8%ba%d8%a9-awk-%d9%84%d9%84%d8%aa%d8%b9%d8%a7%d9%85%d9%84-%d9%85%d8%b9-%d8%a7%d9%84%d9%86%d8%b5%d9%88%d8%b5-%d9%81%d9%8a-%d9%84%d9%8a%d9%86%d9%83%d8%b3-r133/" rel="">باستخدام لغة البرمجة Awk</a> لنشرح من خلالها مفاهيم مألوفة.
</p>

<p>
	عند <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a> بلغة برمجة جديدة، من المهم التركيز على أكثر المفاهيم التي تشترك بها لغات البرمجة:
</p>

<ul>
	<li>
		المتغيرات: مكان يُخزن فيه المعلومات.
	</li>
	<li>
		التعابير: طرق لحساب الأشياء.
	</li>
	<li>
		الصياغات: طرق التعبير عن تغير الحالة داخل البرنامج.
	</li>
</ul>

<p>
	هذه المفاهيم هي أساس معظم لغات البرمجة.
</p>

<p>
	حالما تستوعب جيدا تلك المفاهيم، ستكون قادرًا على استيعاب البقية منها. مثلا أغلب لغات البرمجة تمتلك "طريقة لفعل الأشياء" مدعومة بطريقة تصميم اللغة، وهذه الطرق تختلف من برنامج لآخر. هذه الطرق تتضمن إنشاء الوحدات (تجميع العمليات المتقاربة مع بعضها)، الصيغة التصريحية وصيغة الأمر، والتوجه الغرضي، والمزايا النحوية عالية ومنخفضة المستوى، وما إلى ذلك. مثال يألفه العديد من المبرمجين وهو "المراسم" ويعني كمية التحضيرات اللازمة قبل البدء بحل المشكلة. <a href="https://academy.hsoub.com/programming/java/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-java-%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%D8%9F-r371/" rel="">لغة جافا</a> تتطلب كمية مراسم كبيرة، متجذرة في تصميمها، والذي يتطلب أن تكون كل الشيفرات معرفة ضمن أصناف.
</p>

<p>
	بالرجوع إلى الأساسيات. لغات البرمجة تتشارك بعدة تشابهات. حالما تتعرف على لغة برمجة واحدة، ابدأ بتعلم أساسيات لغة برمجة أخرى وستجد نفسك تقدّر الاختلافات في تلك اللغة الجديدة.
</p>

<p>
	طريقة جيدة للبدء تكون في إنشاء برنامج اختبار بسيط. أحد تلك البرامج قد يكون برنامج "احزر الرقم". يقوم الحاسب باختيار رقم بين واحد ومئة ويسألك أن تحزر ذلك الرقم. يعيد البرنامج الكرّة إلى أن تحزر الرقم.
</p>

<p>
	برنامج "احزر الرقم" سيُدربك على عدة مفاهيم في لغات البرمجة:
</p>

<ul>
	<li>
		المتغيرات.
	</li>
	<li>
		الدخل.
	</li>
	<li>
		الخرج.
	</li>
	<li>
		التقييم الشرطي.
	</li>
	<li>
		الحلقات التكرارية.
	</li>
</ul>

<p>
	هذا مثال عملي تجريبي رائع لتعلم لغة برمجة جديدة.
</p>

<h2>
	احزر الرقم باستخدام awk
</h2>

<p>
	لنبدأ بكتابة لعبة "احزر الرقم" كبرنامج في Awk.
</p>

<p>
	Awk لغة برمجة نصية ديناميكية النوع موجهة لتحويل البيانات، ولديها دعم جيد من ناحية الاستخدام التفاعلي. Awk موجودة منذ عام 1970، بدأت كقسم من نظام يونكس. إذا كنت لا تعلم عن Awk ولكنك تحب جداول البيانات فهذه فأنت في المكان الصحيح للتعرف عليها.
</p>

<p>
	يمكنك بدء الاستكشاف عبر كتابة نسخة من لعبة "احزر الرقم". التالي تضمين للعبة (مع ترقيم الأسطر حتى نتمكن من الإشارة إليها لاحقًا):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4455_8" style=""><span class="lit">1</span><span class="pln">    BEGIN </span><span class="pun">{</span><span class="pln">
</span><span class="lit">2</span><span class="pln">        srand</span><span class="pun">(</span><span class="lit">42</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span><span class="pln">        randomNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">int</span><span class="pun">(</span><span class="pln">rand</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="lit">4</span><span class="pln">        print </span><span class="str">"random number is"</span><span class="pun">,</span><span class="pln">randomNumber
</span><span class="lit">5</span><span class="pln">        printf </span><span class="str">"guess a number between 1 and 100\n"</span><span class="pln">
</span><span class="lit">6</span><span class="pln">    </span><span class="pun">}</span><span class="pln">
</span><span class="lit">7</span><span class="pln">    </span><span class="pun">{</span><span class="pln">
</span><span class="lit">8</span><span class="pln">        guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">int</span><span class="pun">(</span><span class="pln">$0</span><span class="pun">)</span><span class="pln">
</span><span class="lit">9</span><span class="pln">        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">guess </span><span class="pun">&lt;</span><span class="pln"> randomNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">10</span><span class="pln">            printf </span><span class="str">"too low, try again:"</span><span class="pln">
</span><span class="lit">11</span><span class="pln">        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">guess </span><span class="pun">&gt;</span><span class="pln"> randomNumber</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">12</span><span class="pln">            printf </span><span class="str">"too high, try again:"</span><span class="pln">
</span><span class="lit">13</span><span class="pln">        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">14</span><span class="pln">            printf </span><span class="str">"that's right\n"</span><span class="pln">
</span><span class="lit">15</span><span class="pln">            exit
</span><span class="lit">16</span><span class="pln">        </span><span class="pun">}</span><span class="pln">
</span><span class="lit">17</span><span class="pln">    </span><span class="pun">}</span></pre>

<p>
	يمكن الملاحظة مباشرة التشابه بين بنى التحكم في Awk ومثيلاتها في لغات أخرى مثل <a href="https://academy.hsoub.com/programming/c/" rel="">سي C</a> و<a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%83%D8%AA%D8%A8-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC%D9%83-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D8%A8%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-r372/" rel="">جافا JAVA</a>، ولا تشبه تلك التي في <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a>. في التعابير مثل <code>if-then-else</code> أو <code>while</code>، يمكن أن تأخذ تعبيرًا واحدًا أو مجموعة من التعابير محاطة بقوسين معقوصين <code>{</code> و <code>}</code>. ومع ذلك يوجد فرق واحد كبير في Awk يجب فهمه منذ البداية:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		لغة Awk بتصميمها مبنية حول قنوات أو أنابيب البيانات.
	</p>
</blockquote>

<p>
	ماذا يعني ذلك؟ معظم برامج Awk هي مقاطع من الشيفرات التي تتلقى دخل، تقوم بعمل ما على البيانات، ثم تكتبها إلى الخرج. لغة Awk توفر افتراضيًا كل احتياجات التحويل والتوصيل لذلك. لنستكشف ذلك معا من خلال البرنامج السابق ونسأل السؤال التالي: أين بنية "القراءة من الطرفية"؟
</p>

<p>
	الجواب أنها مبنية في داخل اللغة نفسها. تحديدا في الأسطر 7 - 17 نخبر Awk ماذا يفعل بكل سطر من الدخل. سيصبح واضحا أن الأسطر 1 - 6 تنفذ قبل أن يتم قراءة أي شيء.
</p>

<p>
	تحديدا الكلمة المفتاحية <code>BEGIN</code> في السطر الأول هي نمط مكرر، في حالتنا هذه فإنها تخبر Awk قبل قراءة أي شيء أن ينفذ ما بين القوسين <code>{...}</code>. ومثلها الكلمة المفتاحية <code>END</code>، لم نستخدمها هنا لكنها تدل Awk على التعليمات التي يجب أن ينفذها بعد أن يتم قراءة كل شيء.
</p>

<p>
	بالعودة للأسطر 7 - 17، فهي تمثل كتلة واحدة ستنفذ معًا، لكن لا يوجد قبلها كلمة مفتاحية. لذا يقوم Awk بتنفيذ هذه الأسطر على كل سطر يتم تلقيه من الدخل وفي حالتنا هذه هي محاولات المستخدم لحزر الرقم.
</p>

<p>
	لنلق الآن نظرة على الشيفرة التي تنفذ، بدايةً هناك المقدمة التي تنفذ قبل كل قراءة للدخل.
</p>

<p>
	في السطر 2، نعرّف رقما عشوائيا من واحد إلى 42. السطر 3 يقوم بحساب رقم بين 1 و 100، السطر 4 يطبع هذه الرقم لنا فقط للتأكد من وجود أي خطأ. السطر 5 يسأل المستخدم أن يحزر رقمًا. لاحظ هنا استخدمنا التابع <code>printf</code> وليس <code>print</code> فهو مثل التابع الموجود في C، ويأخذ أول معامل ويكون قالب نصي يستخدم لتنسيق الخرج.
</p>

<p>
	الآن بعد أن تم سؤال المستخدم البرنامج ينتظر الإدخال، بعد أن يدخل المستخدم تخمينه، يمرر Awk ذلك الادخال الى الاسطر 7 - 17، كما ذكرنا سابقًا. السطر 1 يحول الدخل الى نوع عدد صحيح؛ <code>0$</code> تعني سجل الدخل كاملًا، بينما <code>1$</code> تعني أول حقل من سجل الدخل <code>2$</code> تعني الحقل الثاني، وهكذا. يقوم Awk بتقسيم الدخل إلى حقول تلقائيا مستخدمًا الفاصل المحدد مسبقًا، والذي تكون قيمته الافتراضية المساحة الفارغة. الأسطر 9 - 15 تقارن جواب المستخدم مع العدد العشوائي المخزن سابقًا، ويطبع الجواب المناسب. إذا كان الجواب صحيحًا، السطر 15 سيخرج من البرنامج وينهي سلسلة معالجة الدخل، بهذه البساطة.
</p>

<p>
	بالأخذ بالحسبان بنية Awk الغريبة التي يتميز بها، فهو يتكون من مقاطع برمجية تتجاوب مع أسطر دخل بإعدادات معينة وتقوم بفعل الأشياء بها، لننظر الآن إلى بنية مختلفة لنرى كيف يعمل قسم التصفية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4455_12" style=""><span class="lit">1</span><span class="pln">    BEGIN </span><span class="pun">{</span><span class="pln">
</span><span class="lit">2</span><span class="pln">        srand</span><span class="pun">(</span><span class="lit">42</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span><span class="pln">        randomNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">int</span><span class="pun">(</span><span class="pln">rand</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="lit">4</span><span class="pln">        print </span><span class="str">"random number is"</span><span class="pun">,</span><span class="pln">randomNumber
</span><span class="lit">5</span><span class="pln">        printf </span><span class="str">"guess a number between 1 and 100\n"</span><span class="pln">
</span><span class="lit">6</span><span class="pln">    </span><span class="pun">}</span><span class="pln">
</span><span class="lit">7</span><span class="pln">    </span><span class="typ">int</span><span class="pun">(</span><span class="pln">$0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> randomNumber </span><span class="pun">{</span><span class="pln">
</span><span class="lit">8</span><span class="pln">        printf </span><span class="str">"too low, try again: "</span><span class="pln">
</span><span class="lit">9</span><span class="pln">    </span><span class="pun">}</span><span class="pln">
</span><span class="lit">10</span><span class="pln">    </span><span class="typ">int</span><span class="pun">(</span><span class="pln">$0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> randomNumber </span><span class="pun">{</span><span class="pln">
</span><span class="lit">11</span><span class="pln">        printf </span><span class="str">"too high, try again: "</span><span class="pln">
</span><span class="lit">12</span><span class="pln">    </span><span class="pun">}</span><span class="pln">
</span><span class="lit">13</span><span class="pln">    </span><span class="typ">int</span><span class="pun">(</span><span class="pln">$0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> randomNumber </span><span class="pun">{</span><span class="pln">
</span><span class="lit">14</span><span class="pln">        printf </span><span class="str">"that's right\n"</span><span class="pln">
</span><span class="lit">15</span><span class="pln">        exit
</span><span class="lit">16</span><span class="pln">    </span><span class="pun">}</span></pre>

<p>
	الأسطر 1 - 6 لم تتغير عن البرنامج السابق لكن نلاحظ أن الشيفرة في الأسطر 7 - 9 ستنفذ في حال كان جواب المستخدم أقل من الرقم العشوائي الذي يحاول تخمينه، والأسطر 10 - 12 كذلك ستنفذ في حال كان جواب المستخدم أكبر من الرقم العشوائي الذي يحاول المستخدم تخمينه، والشيفرة في الأسطر 13 - 16 ستنفذ في حال كان جواب المستخدم مساويًا لذلك الرقم.
</p>

<p>
	قد يبدو ذلك غريبًا، لماذا نقوم بتكرار حساب <code>int($0)‎</code> عند كل تحقق؟ فهي طريقة غريبة لحل المشكلة. لكن هذه الأنماط هي طريقة رائعة لفصل معالجة التحقق من الإجابة حيث يمكن توظيف استخدام التعابير النظامية أو أي بنية مدعومة من قبل Awk عند كل كتلة من كتل التحقق تلك بشكل منفصل.
</p>

<p>
	يمكننا أيضا استخراج الحسابات المتكررة وفصلها بمكان واحد، عن أماكن التحقق منها للحالات المختلفة، التالي نسخة ثالثة من البرنامج توضح ذلك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4455_14" style=""><span class="lit">1</span><span class="pln">    BEGIN </span><span class="pun">{</span><span class="pln">
</span><span class="lit">2</span><span class="pln">        srand</span><span class="pun">(</span><span class="lit">42</span><span class="pun">)</span><span class="pln">
</span><span class="lit">3</span><span class="pln">        randomNumber </span><span class="pun">=</span><span class="pln"> </span><span class="typ">int</span><span class="pun">(</span><span class="pln">rand</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="lit">4</span><span class="pln">        print </span><span class="str">"random number is"</span><span class="pun">,</span><span class="pln">randomNumber
</span><span class="lit">5</span><span class="pln">        printf </span><span class="str">"guess a number between 1 and 100\n"</span><span class="pln">
</span><span class="lit">6</span><span class="pln">    </span><span class="pun">}</span><span class="pln">
</span><span class="lit">7</span><span class="pln">    </span><span class="pun">{</span><span class="pln">
</span><span class="lit">8</span><span class="pln">        guess </span><span class="pun">=</span><span class="pln"> </span><span class="typ">int</span><span class="pun">(</span><span class="pln">$0</span><span class="pun">)</span><span class="pln">
</span><span class="lit">9</span><span class="pln">    </span><span class="pun">}</span><span class="pln">
</span><span class="lit">10</span><span class="pln">    guess </span><span class="pun">&lt;</span><span class="pln"> randomNumber </span><span class="pun">{</span><span class="pln">
</span><span class="lit">11</span><span class="pln">        printf </span><span class="str">"too low, try again: "</span><span class="pln">
</span><span class="lit">12</span><span class="pln">    </span><span class="pun">}</span><span class="pln">
</span><span class="lit">13</span><span class="pln">    guess </span><span class="pun">&gt;</span><span class="pln"> randomNumber </span><span class="pun">{</span><span class="pln">
</span><span class="lit">14</span><span class="pln">        printf </span><span class="str">"too high, try again: "</span><span class="pln">
</span><span class="lit">15</span><span class="pln">    </span><span class="pun">}</span><span class="pln">
</span><span class="lit">16</span><span class="pln">    guess </span><span class="pun">==</span><span class="pln"> randomNumber </span><span class="pun">{</span><span class="pln">
</span><span class="lit">17</span><span class="pln">        printf </span><span class="str">"that's right\n"</span><span class="pln">
</span><span class="lit">18</span><span class="pln">        exit
</span><span class="lit">19</span><span class="pln">    </span><span class="pun">}</span></pre>

<p>
	لاحظ أنه مهما كانت القيمة المدخلة من قبل المستخدم، يجب تحويلها إلى عدد صحيح، تم إضافة الأسطر 7 - 9 لفعل ذلك. الآن الثلاث مجموعات من الأسطر 10 - 12، 13 - 15 و 16 - 19، تشير إلى متغير معرّف مسبقًا باسم <code>guess</code> بدلًا من تحويل الدخل عندها في كل مرة.
</p>

<p>
	لنقم بمراجعة لما كنا قد نوينا تعلمه سابقًا:
</p>

<ul>
	<li>
		المتغيرات: Awk يحتوي عليها؛ يمكننا الملاحظة أن بيانات الدخل تأتي إلى البرنامج على شكل نص ولكن يمكننا تحويلها إلى قيمة عددية عند الحاجة.
	</li>
	<li>
		الدخل: يقوم Awk بإرسال الدخل عبر طريقته "سلسلة معالجة البيانات" لقراءة الدخل.
	</li>
	<li>
		الخرج: قمنا باستخدام توابع Awk الإجرائية التالية <code>print</code> و <code>printf</code> لكتابة الأشياء إلى الخرج.
	</li>
	<li>
		التقييم الشرطي: تعلمنا عن كتلة <code>if-then-else</code> في Awk وتصفية الدخل التي تتجاوب مع إعدادات مختلفة لأسطر الدخل.
	</li>
	<li>
		الحلقات: لم نحتج إلى الحلقات في مثالنا هذا، لكن بفضل طريقة Awk في معالجة البيانات عبر "سلسلة معالجة البيانات" فإن الحلقات موجودة من طبيعة تصميم اللغة نفسها. لكن يمكن للمستخدم الخروج من تلك السلسلة في أي وقت عبر إرسال إشارة "نهاية الملف" إلى Awk (بالضغط على <code>Ctrl+D</code> عند استعمال <a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B7%D8%B1%D9%81%D9%8A%D9%91%D8%A9-%D9%84%D9%8A%D9%86%D9%83%D8%B3-linux-terminal-r18/" rel="">طرفية لينكس</a>).
	</li>
</ul>

<p>
	من المهم ملاحظة عدم حاجتنا للحلقات لمعالجة الدخل. أحد أهم الأسباب التي جعلت Awk يبقى طويلًا هي أن برامجه تكون عادةً قصيرة، وأحد أسباب كونها قصيرة هي أنه لا يوجد شيفرة متداولة مكررة كثيرا وضرورية للقراءة من الطرفية أو من ملف مثلًا.
</p>

<p>
	لننفذ البرنامج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4455_17" style=""><span class="pln">$ awk </span><span class="pun">-</span><span class="pln">f guess</span><span class="pun">.</span><span class="pln">awk
random number is </span><span class="lit">25</span><span class="pln">
guess a number between </span><span class="lit">1</span><span class="pln"> and </span><span class="lit">100</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pln">
too high</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> again</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
too high</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> again</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
too low</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">try</span><span class="pln"> again</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25</span><span class="pln">
that</span><span class="str">'</span><span class="pln">s right
$</span></pre>

<p>
	من الأشياء التي لم نذكرها هي التعليقات. التعليق في Awk يبدأ بمحرف المربع (<code>#</code>) وينتهي عند نهاية سطر التعليق.
</p>

<h2>
	الختام
</h2>

<p>
	Awk لغة قوية ومثالنا السابق "لعبة احزر الرقم" هو بداية جيدة لبدء <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a> بتلك اللغة. وهي البداية وليست نهاية طريق تعلمك لها، يمكنك أيضا القراءة عن <a href="https://www.gnu.org/software/gawk/manual/html_node/History.html" rel="external nofollow">تاريخ لغة Awk و Gawk (إصدار awk لجنو)</a>، وهي إصدار موسع من Awk وعلى الأغلب هو الإصدار المتواجد على حاسبك إذا كنت تعمل على نظام لينكس، أو يمكنك.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://opensource.com/article/21/1/learn-awk" rel="external nofollow">Learn awk by coding a "guess the number" game</a> لصاحبه Chris Hermansen.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/general/%D8%A3%D9%81%D8%B6%D9%84-5-%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D9%80-devops-r416/" rel="">أفضل 5 لغات برمجة لـ DevOps</a>
	</li>
	<li>
		تعرف على أشهر <a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">لغات برمجة الألعاب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%d9%83%d9%8a%d9%81-%d8%aa%d8%aa%d8%b9%d9%84%d9%85-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d8%a9-r17/" rel="">كيف تتعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">ما هي البرمجة ومتطلبات تعلمها؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1390</guid><pubDate>Sat, 04 Dec 2021 16:01:00 +0000</pubDate></item><item><title>&#x645;&#x641;&#x647;&#x648;&#x645; &#x627;&#x644;&#x62A;&#x639;&#x627;&#x648;&#x62F;&#x64A;&#x629; Recursion</title><link>https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF%D9%8A%D8%A9-recursion-r1387/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_12/61a70c05d11a8_----Recursion.png.6345c4fc4756823e6c8f585a85e7f1a4.png" /></p>
<p>
	قد لا نحتاج إلى هذا المقال في أغلب التطبيقات التي نكتبها، إذ إنه موضوع متقدم في البرمجة (خصوصًا في مراحل <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a> الأولى)، وسنعرضه هنا لمجرد الدراسة واحتمال احتياجه في مشروع ما، ولا تقلق إذا وجدت أن عناصره صعبة الفهم.
</p>

<p>
	سنشرح في هذا المقال ما يلي:
</p>

<ul>
	<li>
		تعريف التعاودية، وكيفية عملها.
	</li>
	<li>
		كيف تساعد التعاودية في تبسيط بعض المشاكل الصعبة.
	</li>
</ul>

<h2>
	تعريف التعاودية
</h2>

<p>
	رغم قولنا سابقًا إن <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1306/" rel="">الحلقات التكرارية</a> loops هي إحدى ركائز البرمجة، إلا أنه يمكننا كتابة برامج كاملة دون استخدام صريح لهذه البنية، بل إن بعض اللغات مثل Scheme لا تحوي بنية حلقة تكرارية صريحةً مثل <code>For</code> و<code>While</code> وغيرهما، وإنما تستخدم تقنيةً تسمى التعاودية، وقد تبين أن هذه التقنية قوية للغاية في حل بعض أنواع المشاكل، وهي تعني تطبيق دالة كجزء من تعريف نفس الدالة، ولننظر مثالًا على ذلك أحد الاختصارات التعاودية المشهورة في الكلمات، وهو أحد أساليب التلاعب بالاختصارات يحتوي الاختصار نفسه على كلمة تطابق حروف الاختصار، مثل <a href="https://academy.hsoub.com/devops/linux/%d8%a7%d9%84%d8%af%d9%84%d9%8a%d9%84-%d8%a7%d9%84%d9%86%d9%87%d8%a7%d8%a6%d9%8a-%d9%84%d8%a7%d8%ae%d8%aa%d9%8a%d8%a7%d8%b1-%d8%aa%d9%88%d8%b2%d9%8a%d8%b9%d8%a9-%d9%84%d9%8a%d9%86%d9%83%d8%b3-r48/" rel="">مشروع GNU</a> مثلًا -وهو أحد أهم المشاريع في البرمجيات مفتوحة المصدر- والذي تشير حروف كلمته إلى "نظام GNU ليس يونكس" أو GNU's Not UNIX، فتكون اختصارًا تعاوديًا لأن <a href="https://academy.hsoub.com/devops/linux/%d8%a3%d9%84%d9%81-%d8%a8%d8%a7%d8%a1-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-%d8%a7%d9%84%d8%aa%d8%b9%d8%a7%d9%85%d9%84-%d9%85%d8%b9-%d9%84%d9%8a%d9%86%d9%83%d8%b3-r61/" rel="">كلمة GNU</a> التي في الاختصار هي نفسها كلمة GNU المختصرة كلها، أما معنى الكلمة الحرفي فهو حيوان الثور الإفريقي.
</p>

<p>
	ويجب أن يوجد في الدالة شرط إنهاء، بحيث تتفرع الدالة إلى حل غير تعاودي عند نقطة ما، على عكس مثال GNU الذي ليس فيه هذا الشرط ويظل يتعاود إلى ما لا نهاية، وهو ما نطلق عليه الحلقة اللانهائية infinite loop.
</p>

<p>
	لننظر هنا في مثال بسيط، تُعرَّف فيه دالة المضروب الرياضي factorial function المشار إليها بعلامة التعجب بعد العدد <code>n!‎</code>، على أنها ناتج ضرب جميع الأعداد من الواحد حتى العدد المطلوب -بما في ذلك العدد نفسه-، ومضروب الصفر هو الواحد، فإذا أردنا التعبير عن هذا المثال بطريقة أخرى فسنقول إن مضروب N يساوي (N(N-1، وعليه سيكون:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6898_14" style=""><span class="lit">1</span><span class="pun">!</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
  </span><span class="lit">2</span><span class="pun">!</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> x </span><span class="lit">2</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
  </span><span class="lit">3</span><span class="pun">!</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> x </span><span class="lit">2</span><span class="pln"> x </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">!</span><span class="pln"> x </span><span class="lit">3</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
  N</span><span class="pun">!</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> x </span><span class="lit">2</span><span class="pln"> x </span><span class="lit">3</span><span class="pln"> x </span><span class="pun">....</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N</span><span class="pun">-</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> x </span><span class="pun">(</span><span class="pln">N</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> x N </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)!</span><span class="pln"> x N</span></pre>

<p>
	ويمكن التعبير عن ذلك في <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6898_19" style=""><span class="kwd">def</span><span class="pln"> factorial</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> n </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> n </span><span class="pun">*</span><span class="pln"> factorial</span><span class="pun">(</span><span class="pln">n</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span></pre>

<p>
	يجب أن تنتهي الدالة بما أننا نقلل قيمة N في كل مرة ونتحقق هل تساوي 1 أم لا، لكن ثمة مشكلة بسيطة في هذا التعريف، إذ سيدخل في حلقة لا نهائية إذا استدعيناه برقم سالب، ولحل هذا نضيف اختبارًا للتحقق من أن <code>n</code> أقل من صفر، ويعيد <code>None</code> إذا كان كذلك لأن مضروب العدد السالب غير معرَّف undefined.
</p>

<p>
	يظهر هذا مدى سهولة ارتكاب أخطاء في شروط الإنهاء، وهي أشهر حالة <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">للزلات البرمجية bugs</a> في الدوال التعاودية، إذ يجب أن نتأكد من اختبار جميع القيم حول حالة الإنتهاء لضمان التنفيذ الصحيح.
</p>

<p>
	لنرى الآن كيف يكون هذا عند تنفيذه، لاحظ أن تعليمة الإعادة تعيد <code>* n </code>(نتيجة استدعاء المضروب التالي)، فنحصل على ما يلي:
</p>

<pre class="ipsCode">factorial(4) = 4 * factorial(3)
factorial(3) = 3 * factorial(2)
factorial(2) = 2 * factorial(1)
factorial(1) = 1
</pre>

<p>
	وتعود بايثون أدراجها لتستبدل القيم كما يلي:
</p>

<pre class="ipsCode">factorial(2) = 2 * 1 = 2
factorial(3) = 3 * 2 = 6
factorial(4) = 4 * 6 = 24
</pre>

<p>
	ليس من الصعب كتابة دالة مضروب دون استخدام التعاودية، ويمكنك تجريب هذا، إذ يجب أن تمر على جميع الأعداد حتى N؛ وتنفذ عمليات ضرب أثناء ذلك المرور التكراري، لكن قد يصعب كتابة بعض الدوال دون التعاودية، كما سنرى أدناه.
</p>

<h2>
	التعاودية على القوائم
</h2>

<p>
	إحدى الحالات التي تكون التعاودية مفيدةً فيها هي معالجة القوائم Lists، بشرط أن نستطيع التحقق من فراغ القائمة، وتوليد قائمة دون عنصرها الأول، ونفعل هذا في بايثون باستخدام تقنية تسمى <a href="https://wiki.hsoub.com/Python/slice" rel="external">التشريح Slicing</a>، لكن كل ما يجب معرفته في هذا الفصل هو أن استخدام فهرس <code>[‎1:‎]</code> يعيد جميع العناصر من العنصر ذي الفهرس 1 حتى نهاية القائمة، لذا نكتب ما يلي لنصل إلى العنصر الأول من قائمة اسمها L:
</p>

<pre class="ipsCode">first = L[0] # استخدم الفهرسة العادية
</pre>

<p>
	وللوصول إلى بقية القائمة:
</p>

<pre class="ipsCode"># استخدم التشريح للوصول إلى العناصر 1،2،3 وما بعدها
butfirst = L[1:] 
</pre>

<p>
	لنجرب ذلك في محث بايثون، لنتأكد أنه يعمل:
</p>

<pre class="ipsCode">&gt;&gt;&gt; L =[1,2,3,4,5]
&gt;&gt;&gt; print( L[0] )
1
&gt;&gt;&gt; print( L[1:] )
[2,3,4,5]
</pre>

<p>
	نعود الآن إلى استخدام التعاودية لطبع القوائم، ولنفرض حالةً نطبع فيها كل عنصر من قائمة سلاسل نصية باستخدام الدالة <code>printList</code>:
</p>

<pre class="ipsCode">def printList(L):
    if L:
        print( L[0] )
        printList(L[1:])
</pre>

<p>
	إذا تحققت L -أي كانت true ولم تكن فارغةً- فسنطبع العنصر الأول، ثم نعالج بقية القائمة كما يلي:
</p>

<pre class="ipsCode"># شيفرة وهمية ليست بايثون
PrintList([1,2,3])
   prints [1,2,3][0] =&gt; 1
   runs printList([1,2,3][1:]) =&gt; printList([2,3])
   =&gt; we're now in printList([2,3])
         prints [2,3][0] =&gt; 2
         runs printList([2,3][1:]) =&gt; printList([3])
         =&gt; we are now in printList([3])
               prints [3][0] =&gt; 3
               runs printList([3][1:]) =&gt; printList([])
               =&gt; we are now in printList([])
                     "if L" is false for an empty list, so we return None
         =&gt; we are back in printList([3])
               it reaches the end of the function and returns None
   =&gt; we are back in printList([2,3])
         it reaches the end of the function and returns None
=&gt; we are back in printList([1,2,3])
   it reaches the end of the function and returns None
</pre>

<p>
	لاحظ أن الشرح أعلاه مأخوذ من شرح في نشرة تعليم <a href="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">بايثون</a> البريدية بواسطة Zak Arnston بتاريخ يوليو 2003.
</p>

<p>
	يسهل تنفيذ هذا الأمر لقائمة بسيطة باستخدام حلقة for، لكن ماذا لو كانت القائمة معقدةً وتحتوي قوائم أخرى فيها، فإذا استطعنا التحقق من كون عنصر ما قائمةً باستخدام دالة <code>type()‎</code> المضمنة وكان قائمة حقًا؛ فسنستدعي <code>printList()‎</code> تعاوديًا، أما إن لم يكن قائمةً فنطبعه:
</p>

<pre class="ipsCode">def printList(L):
    # لا تفعل شيًا إن كانت فارغة
    if not L: return
    # على العنصر الأول printList إذا كانت قائمة فاستدع
    if type(L[0]) == list:
        printList(L[0])
    else: # لا توجد قوائم لذا نطبع هنا 
        print( L[0] ) # L نعالج بقية عناصر  
    printList( L[1:] )
</pre>

<p>
	سيصعب تنفيذ ذلك باستخدام الحلقة التكرارية العادية، ويظهر الفرق مع استخدام التعاودية في تسهيل ذلك التنفيذ، لكن ثمة مشكلة هنا، فالتعاودية على بنى البيانات الكبيرة يستهلك الذاكرة كثيرًا، لذا عند وجود ذاكرة صغيرة أو بنى بيانات كبيرة لمعالجتها، فيجب تفضيل الشيفرة المعتادة للأمان، وبسبب مشكلة الذاكرة تلك واحتمال أن يتعطل المفسر interpreter بسببها فقد وضعت بايثون حدًا لعدد مستويات التعاودية التي تسمح بها، فإذا تجاوزنا ذلك الحد فسيُنهى برنامجنا مع خطأ <code>RecusrionError</code>، والذي نلتقطه باستخدام <code>try/except</code>:
</p>

<pre class="ipsCode">  &gt;&gt;&gt; def f(n): return f(n+1)
</pre>

<p>
	نلاحظ أن سبب هذه الحالة هو عدم وجود شرط إنهاء، لكن يجب أن تكون مجموعةً كبيرةً من بيانات الدخل كافيةً لإطلاقها حتى في الدوال المكتوبة بإتقان، وهنا يكون الحل الوحيد هو إعادة الكتابة مرةً أخرى باستخدام الحلقات التكرارية المعتادة، وهذا ممكن دومًا مهما بدا صعبًا.
</p>

<h2>
	جافاسكربت ولغة VBScript
</h2>

<p>
	تدعم كل من <a href="https://wiki.hsoub.com/JavaScript" rel="external">لغة جافاسكربت</a> ولغة VBScript التعاودية، لكن بما أننا ذكرنا كل شيء تقريبًا فسنتركك مع نسخة تعاودية من دالة المضروب للغتين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6898_24" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Function</span><span class="pln"> factorial</span><span class="pun">(</span><span class="pln">N</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> N </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="typ">Then</span><span class="pln">
      </span><span class="typ">Factorial</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">   </span><span class="str">'</span><span class="pln">a negative result is </span><span class="str">"impossible"</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="typ">Then</span><span class="pln">
      </span><span class="typ">Factorial</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   </span><span class="typ">Else</span><span class="pln">
      </span><span class="typ">Factorial</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> N </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Factorial</span><span class="pun">(</span><span class="pln">N</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
   </span><span class="typ">End</span><span class="pln"> </span><span class="typ">If</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">Function</span><span class="pln">

</span><span class="typ">Document</span><span class="pun">.</span><span class="typ">Write</span><span class="pln"> </span><span class="str">"7! = "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">CStr</span><span class="pun">(</span><span class="typ">Factorial</span><span class="pun">(</span><span class="lit">7</span><span class="pun">))</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> factorial</span><span class="pun">(</span><span class="pln">n</span><span class="pun">){</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">NaN</span><span class="pln">  </span><span class="com">// NaN - Not a Number - يعني أنه غير صالح </span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> n </span><span class="pun">*</span><span class="pln"> factorial</span><span class="pun">(</span><span class="pln">n</span><span class="pun">-</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"6! = "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> factorial</span><span class="pun">(</span><span class="lit">6</span><span class="pun">));</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لننظر الآن في البرمجة الدالية Functional Programming (أو البرمجة الوظيفية) في الفصل التالي.
</p>

<h2>
	خاتمة
</h2>

<p>
	نأمل بنهاية هذا الفصل أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		تستدعي الدوال التعاودية نفسها من داخل تعريفها.
	</li>
	<li>
		يجب أن تحتوي الدوال التعاودية على شرط إنهاء غير تعاودي نصل إليه في النهاية، وإلا فسنقع في حلقة لا نهائية من التكرار.
	</li>
	<li>
		التعاودية مستهلكة للذاكرة عادةً، لكن ليس في كل الحالات.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutrecur.htm" rel="external nofollow">للفصل العشرين: Recursion, or doing it to yourself</a>، من كتاب Learn To Program لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-functional-programming-r1391/" rel="">مقدمة إلى البرمجة الوظيفية Functional Programming</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-tkinter-r1378/" rel="">برمجة الواجهات الرسومية باستخدام Tkinter</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-recursion-%D9%88%D8%A7%D9%84%D9%85%D9%83%D8%AF%D8%B3-stack-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r870/" rel="">التعاود recursion والمكدس stack في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-recursion-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1361/" rel="">التعاود recursion في جافا</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/cpp/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-recursion-%D9%88%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%82%D8%A7%D8%A8%D9%84%D8%A9-%D9%84%D9%84%D8%A7%D8%B3%D8%AA%D8%AF%D8%B9%D8%A7%D8%A1-callable-objects-%D9%81%D9%8A-cpp-r1183/" rel="">مفهوم التعاود (Recursion) والكائنات القابلة للاستدعاء (Callable Objects) في Cpp</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1387</guid><pubDate>Wed, 01 Dec 2021 16:08:00 +0000</pubDate></item><item><title>&#x62A;&#x634;&#x63A;&#x64A;&#x644; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x627;&#x644;&#x62A;&#x642;&#x62F;&#x645;&#x64A;&#x629; PWA &#x641;&#x64A; &#x648;&#x636;&#x639; &#x627;&#x646;&#x642;&#x637;&#x627;&#x639; &#x627;&#x644;&#x627;&#x62A;&#x635;&#x627;&#x644;</title><link>https://academy.hsoub.com/programming/general/%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D9%81%D9%8A-%D9%88%D8%B6%D8%B9-%D8%A7%D9%86%D9%82%D8%B7%D8%A7%D8%B9-%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-r1386/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/61a161e2e494c_----------------Android-Apps-Progressive-Web-Apps-offline-fallback-page.png.f762444b53487fcf13e0180e29821375.png" /></p>

<p>
	تشترك معظم التطبيقات الشهيرة مثل مُساعد جوجل Google Assistant وتطبيق الدردشة سلاك Slack وتطبيق اللقاءات الافتراضية زووم Zoom بأنها تُقدّم خدمات محدودة جدًا في وضع انقطاع الاتصال، أي أنه يُمكن تشغيلها والدخول إليها ومعاينة بعض الواجهات فيها على الرغم من انقطاع الاتصال.
</p>

<p>
	تُبين اللقطات التالية أن تطبيقات المنصات الخاصة تعرض شيئًا ما في وضع انقطاع الاتصال. مثلًا اللقطة التالية للمُساعد Google Assistant:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83465" href="https://academy.hsoub.com/uploads/monthly_2021_11/001Google.jpg.fc857b2094741c586ff33a925972f945.jpg" rel=""><img alt="001Google.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="83465" data-unique="zaz3vleuy" src="https://academy.hsoub.com/uploads/monthly_2021_11/001Google.thumb.jpg.b1c223b352e3137b52789922e4c60416.jpg"></a>
</p>

<p>
	أما اللقطة التالية لتطبيق سلاك Slack:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83466" href="https://academy.hsoub.com/uploads/monthly_2021_11/002Slack.jpg.8931af9e857bcc79369cf5934fa9b05b.jpg" rel=""><img alt="002Slack.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="83466" data-unique="c1p8k5ia5" src="https://academy.hsoub.com/uploads/monthly_2021_11/002Slack.thumb.jpg.7e1d8d7d6ca0c9954674e6835c2ef794.jpg"></a>
</p>

<p>
	واللقطة التالية لتطبيق زووم Zoom:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83467" href="https://academy.hsoub.com/uploads/monthly_2021_11/003Zoom.jpg.47772f46ac726880f93ff33862cf43fc.jpg" rel=""><img alt="003Zoom.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="83467" data-unique="df3g9gy1y" src="https://academy.hsoub.com/uploads/monthly_2021_11/003Zoom.thumb.jpg.df19cae384f25dce72f4fd1a7fc29aa6.jpg" style=""></a>
</p>

<p>
	على النقيض من ذلك، لا نحصل على شيء على الويب عند انقطاع الاتصال. مثلًا، قد يُظهر المتصفح Chrome اللعبة البسيطة dino على <a href="https://academy.hsoub.com/apps/ios/" rel="">أنظمة التشغيل iOS</a>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83468" href="https://academy.hsoub.com/uploads/monthly_2021_11/004iOS.png.618a396f7406f0f3a4d3863c6b9516c3.png" rel=""><img alt="004iOS.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83468" data-unique="ku2s7ea5d" src="https://academy.hsoub.com/uploads/monthly_2021_11/004iOS.thumb.png.a9fb5fd6b7616633caa5b940ba1c44f1.png" style=""></a>
</p>

<p>
	وعلى أنظمة <a href="https://academy.hsoub.com/apps/macos/" rel="">التشغيل macOS</a>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83469" href="https://academy.hsoub.com/uploads/monthly_2021_11/005macOS.png.7e486023a87eb0fd949b9b5aa8031ddc.png" rel=""><img alt="005macOS.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83469" data-unique="sjqav2qin" src="https://academy.hsoub.com/uploads/monthly_2021_11/005macOS.thumb.png.8cd18ebc45958780cc6e123d62f1d67e.png" style=""></a>
</p>

<p>
	سنتعلم في هذا المقال كيفية إنشاء صفحة احتياطية لوضع انقطاع الاتصال وإضافتها إلى <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيقات الويب التقدمية PWA</a>.
</p>

<h2>
	إنشاء صفحة احتياطية باستخدام عامل خدمة مخصص
</h2>

<p>
	من المناسب تخصيص سلوك صفحات الويب التقدميّة في حال انقطاع الاتصال لاسيما أنه أصبح بالإمكان توفير تجربة استخدام مخصصة باستخدام <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-service-worker-%D9%88%D8%AA%D8%A3%D8%AB%D9%8A%D8%B1%D9%87-%D9%81%D9%8A-%D8%A3%D8%AF%D8%A7%D8%A1-%D9%88%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r833/" rel="">عامل خدمة</a> service worker وواجهة برمجة التطبيقات ذات التخزين المؤقت <a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage" rel="external nofollow">Cache Storage <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> . يُمكن عادًة إنشاء صفحة احتياطية بسيطة تُبين للمستخدم أنه في وضع انقطاع الاتصال، إلا أنه يُمكن أيضًا إيجاد حلول إبداعية أجمل. لنلقي نظرة مثلًا على موقع الحجز <a href="https://www.trivago.com/offline" rel="external nofollow">trivago</a> والذي يوفر في صفحته الاحتياطية لعبة متاهة مسلية للمستخدم خلال انقطاع الاتصال مع زر لتجريب إعادة الاتصال Reconnect وعدّاد تنازلي لإظهار الزمن المتبقي لإعادة محاولة الاتصال تلقائيًا كما يُبين الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83470" href="https://academy.hsoub.com/uploads/monthly_2021_11/006trivago.png.6bdbf8ab5790ffb11852bfc408c02351.png" rel=""><img alt="006trivago.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83470" data-unique="xxja37xj8" src="https://academy.hsoub.com/uploads/monthly_2021_11/006trivago.thumb.png.42e09794fcb90993c924914c9c0d12b4.png" style=""></a>
</p>

<h3>
	تسجيل عامل الخدمة
</h3>

<p>
	لإنشاء الصفحة الاحتياطية، يجب أولًا تسجيل عامل خدمة في الصفحة الأساسية كما تُبين الشيفرة التالية والتي تُنفّذ عند تحميل التطبيق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9967_8" style="">
<span class="pln">window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"load"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="str">"serviceWorker"</span><span class="pln"> in navigator</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    navigator</span><span class="pun">.</span><span class="pln">serviceWorker</span><span class="pun">.</span><span class="kwd">register</span><span class="pun">(</span><span class="str">"service-worker.js"</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></pre>

<h3>
	شيفرة عامل الخدمة
</h3>

<p>
	نعرض فيما يلي مثالًا عن شيفرة عامل الخدمة والتي قد تبدو للوهلة الأولى معقدة قليلًا ولذا أُضيفت بعض التعليقات المُساعدّة. تكمن الفكرة بالتخزين المؤقت المسبق لملف ندعوه <code>offline.html</code> والذي يعرضه المتصفح في حال فشل طلبات التنقل navigation فقط، وفي بقية الحالات يتابع المتصفح معالجاته الاعتيادية.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9967_15" style="">
<span class="com">/* معلومات رخصة الاستخدام
Copyright 2015, 2019, 2020, 2021 Google LLC. All Rights Reserved.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/</span><span class="pln">

</span><span class="com">// (1)</span><span class="pln">
</span><span class="com">// يُمكن إضافة أي تعليق مناسب لمنقح الصياغة</span><span class="pln">
</span><span class="com">// eslint-disable-next-line no-unused-vars</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> OFFLINE_VERSION </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> CACHE_NAME </span><span class="pun">=</span><span class="pln"> </span><span class="str">"offline"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">يُمكن</span><span class="pln"> </span><span class="pun">تخصيص</span><span class="pln"> </span><span class="pun">مُحدّد</span><span class="pln"> </span><span class="pun">موارد</span><span class="pln"> URL </span><span class="pun">مختلف</span><span class="pln"> </span><span class="pun">إذا</span><span class="pln"> </span><span class="pun">دعت</span><span class="pln"> </span><span class="pun">الحاجة</span><span class="pln"> </span><span class="com">//</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> OFFLINE_URL </span><span class="pun">=</span><span class="pln"> </span><span class="str">"offline.html"</span><span class="pun">;</span><span class="pln">

self</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"install"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  event</span><span class="pun">.</span><span class="pln">waitUntil</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">(</span><span class="pln">async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> cache </span><span class="pun">=</span><span class="pln"> await caches</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="pln">CACHE_NAME</span><span class="pun">);</span><span class="pln">
      </span><span class="com">// (2) </span><span class="pln">
      await cache</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Request</span><span class="pun">(</span><span class="pln">OFFLINE_URL</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> cache</span><span class="pun">:</span><span class="pln"> </span><span class="str">"reload"</span><span class="pln"> </span><span class="pun">}));</span><span class="pln">
    </span><span class="pun">})()</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">
 </span><span class="pun">إرغام</span><span class="pln"> </span><span class="pun">عامل</span><span class="pln"> </span><span class="pun">الخدمة</span><span class="pln"> </span><span class="pun">المنتظر</span><span class="pln"> </span><span class="pun">ليصبح</span><span class="pln"> </span><span class="pun">العامل</span><span class="pln"> </span><span class="pun">النشط</span><span class="pln"> </span><span class="com">//</span><span class="pln">
  self</span><span class="pun">.</span><span class="pln">skipWaiting</span><span class="pun">();</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

self</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"activate"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  event</span><span class="pun">.</span><span class="pln">waitUntil</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">(</span><span class="pln">async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// السماح بالتنقل قبل التحميل إذا كان ذلك مدعومًا</span><span class="pln">
      </span><span class="com">// See https://developers.google.com/web/updates/2017/02/navigation-preload</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="str">"navigationPreload"</span><span class="pln"> in self</span><span class="pun">.</span><span class="pln">registration</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        await self</span><span class="pun">.</span><span class="pln">registration</span><span class="pun">.</span><span class="pln">navigationPreload</span><span class="pun">.</span><span class="pln">enable</span><span class="pun">();</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">})()</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">

  </span><span class="com">// الطلب من عامل الخدمة أن يتحكم بالصفحة فورًا</span><span class="pln">
  self</span><span class="pun">.</span><span class="pln">clients</span><span class="pun">.</span><span class="pln">claim</span><span class="pun">();</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

self</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"fetch"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 </span><span class="pun">إذا</span><span class="pln"> </span><span class="pun">كان</span><span class="pln"> </span><span class="pun">الطلب</span><span class="pln"> </span><span class="pun">لصفحة</span><span class="pln"> HTML </span><span class="pun">نستدعي</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">respondWith</span><span class="com">//</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">request</span><span class="pun">.</span><span class="pln">mode </span><span class="pun">===</span><span class="pln"> </span><span class="str">"navigate"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">respondWith</span><span class="pun">(</span><span class="pln">
      </span><span class="pun">(</span><span class="pln">async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
         </span><span class="pun">نحاول</span><span class="pln"> </span><span class="pun">أولًا</span><span class="pln"> </span><span class="pun">استخدام</span><span class="pln"> </span><span class="pun">جواب</span><span class="pln"> </span><span class="pun">التنقل</span><span class="pln"> </span><span class="pun">قبل</span><span class="pln"> </span><span class="pun">التحميل</span><span class="pln"> </span><span class="pun">إذا</span><span class="pln"> </span><span class="pun">كان</span><span class="pln"> </span><span class="pun">مدعومًا</span><span class="pln"> </span><span class="com">//        </span><span class="pln">
          </span><span class="kwd">const</span><span class="pln"> preloadResponse </span><span class="pun">=</span><span class="pln"> await event</span><span class="pun">.</span><span class="pln">preloadResponse</span><span class="pun">;</span><span class="pln">
          </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">preloadResponse</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> preloadResponse</span><span class="pun">;</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">

          </span><span class="pun">تجريب</span><span class="pln"> </span><span class="pun">الشبكة</span><span class="pln"> </span><span class="pun">أولًا</span><span class="pln"> </span><span class="com">//        </span><span class="pln">
          </span><span class="kwd">const</span><span class="pln"> networkResponse </span><span class="pun">=</span><span class="pln"> await fetch</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">request</span><span class="pun">);</span><span class="pln">
          </span><span class="kwd">return</span><span class="pln"> networkResponse</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="com">// (3)</span><span class="pln">
          console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"Fetch failed; returning offline page instead."</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">);</span><span class="pln">

          </span><span class="kwd">const</span><span class="pln"> cache </span><span class="pun">=</span><span class="pln"> await caches</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="pln">CACHE_NAME</span><span class="pun">);</span><span class="pln">
          </span><span class="kwd">const</span><span class="pln"> cachedResponse </span><span class="pun">=</span><span class="pln"> await cache</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="pln">OFFLINE_URL</span><span class="pun">);</span><span class="pln">
          </span><span class="kwd">return</span><span class="pln"> cachedResponse</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">})()</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">

  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// (4)</span><span class="pln">
</span><span class="pun">});</span></pre>

<ul>
<li>
		(1) تؤدي زيادة قيمة المتغير <code>OFFLINE_VERSION</code> إلى تنشيط حدث التثبيت وتحديث الموارد المخبئة سابقًا عبر الشبكة، المتغير مُعرّف عمدًا مع أنه غير مستخدم.
	</li>
	<li>
		(2) يؤدي ضبط {cache: 'reload'‎} في الطلب الجديد إلى استيفاء الطلب HTTP من الشبكة وليس من الذاكرة المؤقتة.
	</li>
	<li>
		(3) رُفع استثناء يُنشّط الالتقاط catch والذي يكون على الأغلب بسبب خطأ في الشبكة، ولن تُستدعى catch إذا أعادت <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84%D8%A7%D8%AA-%D9%85%D8%AA%D9%82%D8%AF%D9%85%D8%A9-%D9%84%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-fetch-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1297/" rel="">fetch </a>جواب HTTP صالح، مع كود الجواب محصور بين
	</li>
	<li>
		4xx - 5xx. (4) إذا كان شرط التعليمة if خاطئًا فلن يقاطع معالج الجلب fetch الطلب، يُمكن أن يُستدعى التابع event.respondWith في حال وجود معالجات جلب أخرى مسجلة، إذا لم يستدع أي معالج جلب التابع event.respondWith فعندها يعالج المتصفح الطلب كما لو أنه لا يوجد عامل خدمة.
	</li>
</ul>
<h2>
	الصفحة الاحتياطية لوضع انقطاع الاتصال
</h2>

<p>
	يُعدّ ملف الصفحة الاحتياطية <code>offline.html</code> المكان المناسب لإظهار بعض الإبداع لجذب المستخدم وإبراز العلامة التجارية للمنتج مثلًا، حيث يُمكن تكييف هذا الملف مع الاحتياجات المطلوبة. يُبين المثال التالي الحد الأدنى الممكن القيام به كإظهار زر إعادة التحميل، إضافًة لمحاولات إعادة التحميل الآلية والتي تعتمد على حدث الاتصال <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event" rel="external nofollow"><code>online</code></a> وعلى اقتراع خادم منتظم regular server polling.
</p>

<p>
	يجب تخزين جميع الموارد التي تتطلبها الصفحة الاحتياطية لوضع انقطاع الاتصال. من الحلول المُمكنة لذلك تضمين كل شيء وبذا تُصبح الصفحة الاحتياطية حاوية لنفسها، وهو ما يُبينه المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9967_18" style="">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"en"</span><span class="tag">&gt;</span><span class="pln">
 </span><span class="tag">&lt;head&gt;</span><span class="pln">
   </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"utf-8"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
   </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">"X-UA-Compatible"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"IE=edge"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
   </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"viewport"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"width=device-width, initial-scale=1"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

   </span><span class="tag">&lt;title&gt;</span><span class="pln">You are offline</span><span class="tag">&lt;/title&gt;</span><span class="pln">

   </span><span class="com">&lt;!-- Inline the page's stylesheet. --&gt;</span><span class="pln">
   </span><span class="tag">&lt;style&gt;</span><span class="pln">
     body </span><span class="pun">{</span><span class="pln">
       font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> helvetica</span><span class="pun">,</span><span class="pln"> arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
       margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2em</span><span class="pun">;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">

     h1 </span><span class="pun">{</span><span class="pln">
       font</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> italic</span><span class="pun">;</span><span class="pln">
       color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#373fff;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">

     p </span><span class="pun">{</span><span class="pln">
       margin</span><span class="pun">-</span><span class="pln">block</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">

     button </span><span class="pun">{</span><span class="pln">
       display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
   </span><span class="tag">&lt;/style&gt;</span><span class="pln">
 </span><span class="tag">&lt;/head&gt;</span><span class="pln">
 </span><span class="tag">&lt;body&gt;</span><span class="pln">
   </span><span class="tag">&lt;h1&gt;</span><span class="pln">You are offline</span><span class="tag">&lt;/h1&gt;</span><span class="pln">

   </span><span class="tag">&lt;p&gt;</span><span class="pln">Click the button below to try reloading.</span><span class="tag">&lt;/p&gt;</span><span class="pln">
   </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="tag">&gt;</span><span class="pln">⤾ Reload</span><span class="tag">&lt;/button&gt;</span><span class="pln">

   </span><span class="com">&lt;!-- Inline the page's JavaScript file. --&gt;</span><span class="pln">
   </span><span class="tag">&lt;script&gt;</span><span class="pln">
     </span><span class="com">//  ميزة إعادة التحميل اليدوي</span><span class="pln">
     document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"button"</span><span class="pun">).</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       window</span><span class="pun">.</span><span class="pln">location</span><span class="pun">.</span><span class="pln">reload</span><span class="pun">();</span><span class="pln">
     </span><span class="pun">});</span><span class="pln">
     </span><span class="com">//(1)</span><span class="pln">
     window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'online'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       window</span><span class="pun">.</span><span class="pln">location</span><span class="pun">.</span><span class="pln">reload</span><span class="pun">();</span><span class="pln">
     </span><span class="pun">});</span><span class="pln">
</span><span class="com">//(2)</span><span class="pln">

     async </span><span class="kwd">function</span><span class="pln"> checkNetworkAndReload</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
         </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> await fetch</span><span class="pun">(</span><span class="str">'.'</span><span class="pun">);</span><span class="pln">
          </span><span class="com">// التحقق من الحصول على جواب صالح من الخادم</span><span class="pln">
         </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">status </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">200</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">status </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">500</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           window</span><span class="pun">.</span><span class="pln">location</span><span class="pun">.</span><span class="pln">reload</span><span class="pun">();</span><span class="pln">
           </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
         </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">// تجاهل إذ لا يُمكن الاتصال مع الخادم</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       window</span><span class="pun">.</span><span class="pln">setTimeout</span><span class="pun">(</span><span class="pln">checkNetworkAndReload</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2500</span><span class="pun">);</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">

     checkNetworkAndReload</span><span class="pun">();</span><span class="pln">
   </span><span class="tag">&lt;/script&gt;</span><span class="pln">
 </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	حيث أن:
</p>

<ul>
<li>
		(1) متابعة تغييرات حالة الشبكة وإعادة التحميل عند انقطاع الاتصال حيث ينشط المعالج التالي في حالة انقطاع الاتصال كليًا.
	</li>
	<li>
		(2) إعادة تحميل الصفحة إذا كان الخادم متجاوبًا حيث ينشط المعالج التالي في حال انقطاع الاتصال عن الجهاز أو عدم تجاوب الخادم بشكل صحيح.
	</li>
</ul>
<h3>
	مثال توضيحي
</h3>

<p>
	يُمكن معاينة الصفحة الاحتياطية في <a href="https://offline-fallback-demo.glitch.me/index.html" rel="external nofollow">المثال</a> والموضح لقطة منه أدناه. كما يُمكن الحصول على <a href="https://glitch.com/edit/#!/offline-fallback-demo" rel="external nofollow">الشيفرة</a> المصدرية الموافقة من المستودع Glitch.
</p>

<p style="text-align: center;">
	<img alt="007Demo.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83471" data-unique="1d4hxubq0" src="https://academy.hsoub.com/uploads/monthly_2021_11/007Demo.png.c8a854f2e568dd280d236ad4d3dd65dc.png" style="width: 700px; height: auto;"></p>

<p>
	يُمكن، بعد الانتهاء من إنشاء الصفحة الاحتياطية لوضع عدم الاتصال، تحقيق إمكانية تثبيت التطبيق بإضافة <a href="https://academy.hsoub.com/programming/general/%D8%B4%D8%B1%D8%AD-%D9%85%D9%84%D9%81-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86-manifest-%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1385/" rel="">بيان تطبيق الويب</a> واختيار استراتيجية التثبيت. كما يُمكن، للسهولة، استخدام مكتبات <a href="https://developers.google.com/web/tools/workbox" rel="external nofollow">Workbox.js</a> والتي توفر الشيفرة اللازمة لإنشاء الصفحة الاحتياطية.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://web.dev/offline-fallback-page/" rel="external nofollow">Create an offline fallback page</a> للمؤلفين: Thomas Steiner و Pete LePage.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/design/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-%D9%88%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D8%AC%D8%A8-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D9%85%D8%B5%D9%85%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A7%D9%87%D8%AA%D9%85%D8%A7%D9%85-%D8%A8%D9%87%D8%A7%D8%9F-r450/" rel="">ما هي تطبيقات الويب التقدمية ولماذا يجب على المصممين الاهتمام بها؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D8%B3%D8%AA%D8%A6%D9%86%D8%A7%D9%81-%D8%B1%D9%81%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%A8%D8%B9%D8%AF-%D9%81%D9%82%D8%AF%D8%A7%D9%86-%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1300/" rel="">استئناف رفع الملفات بعد فقدان الاتصال في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/apps/web/wordpress/3-%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D8%B9%D9%86%D8%AF-%D8%B1%D9%81%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-ftp-%D9%88%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D8%B5%D9%84%D8%A7%D8%AD%D9%87%D8%A7-r116/" rel="">3 أخطاء شائعة عند رفع الملفات باستخدام بروتوكول FTP وكيفية إصلاحها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">أنظمة التشغيل للمبرمجين</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1386</guid><pubDate>Mon, 29 Nov 2021 16:05:00 +0000</pubDate></item><item><title>&#x628;&#x631;&#x645;&#x62C;&#x629; &#x627;&#x644;&#x648;&#x627;&#x62C;&#x647;&#x627;&#x62A; &#x627;&#x644;&#x631;&#x633;&#x648;&#x645;&#x64A;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Tkinter</title><link>https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-tkinter-r1378/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/61a50eabb0f14_----Tkinter.png.7b7c2fee986ca5f4dd23cd9967968bd0.png" /></p>
<p>
	سنلقي في هذا المقال نظرةً عامةً على كيفية تجميع برنامج رسومي بشرح المفاهيم الأساسية لبناء <a href="https://academy.hsoub.com/programming/java/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A9-gui-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1070/" rel="">الواجهات الرسومية</a>، ثم كيفية تنفيذه باستخدام صندوق أدوات Tkinter الرسومي الخاص <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">ببايثون</a>، لكن لن يكون هذا الشرح مرجعًا لصندوق Tkinter بحال من الأحوال، إذ يحتوي موقع بايثون على شرح مفصل له، مع ملاحظة أن ذلك الشرح يستخدم الإصدار الثاني من بايثون الذي يحتوي على أسماء مختلفة للوحدات، لذا يجب التحقق من قائمة وحدات بايثون للحصول على الأسماء الصحيحة للوحدات المستوردة، أما شرحنا فيستعرض أساسيات برمجة الواجهات الرسومية، ويشرح بعض المكونات الأساسية للواجهات وكيفية استخدامها، كما ينظر في كيفية استخدام <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">البرمجة الكائنية التوجه</a> في تنظيم <a href="https://academy.hsoub.com/design/general/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D8%B4%D9%87%D8%B1-%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D8%B5%D9%88%D8%B1-%D9%88%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A7%D8%AA-r540/" rel="">تطبيق رسومي</a>، وبهذا تكون العناصر الأساسية لهذا المقال هي:
</p>

<ul>
	<li>
		مفاهيم بناء الواجهات الرسومية البسيطة.
	</li>
	<li>
		الوِدجات البسيطة.
	</li>
	<li>
		هيكل برنامج Tkinter بسيط.
	</li>
	<li>
		الواجهات الرسومية والبرمجة الكائنية التوجه، تطابق مثالي.
	</li>
	<li>
		wxPython بديل Tkinter.
	</li>
</ul>

<h2>
	مبادئ الواجهات الرسومية
</h2>

<p>
	لن نتعرض لمفاهيم برمجية جديدة هنا، فبرمجة الواجهات الرسومية تشبه أي نوع آخر من البرمجة، إذ تحوي تسلسلات sequences، ووحدات modules، وفروعًا branches، وحلقات تكراريةً loops، أما الأمر الإضافي فيها فهو استخدام صندوق أدوات Toolkit، واتباعنا نمطًا معينًا في تصميم البرمجيات يحدده من كتب صندوق الأدوات ذاك، لذا يكون لكل صندوق أدوات مجموعته الخاصة من الوحدات والأصناف والدوال، والتي تعرف باسم <a href="https://www.bing.com/search?q=site%3Aacademy.hsoub.com+%D9%88%D8%A7%D8%AC%D9%87%D8%A9+%D8%A8%D8%B1%D9%85%D8%AC%D8%A9+%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA+Application+Programming+Interface&amp;go=Rechercher&amp;qs=ds&amp;form=QBRE" rel="external nofollow">واجهة برمجة التطبيقات Application Programming Interface</a>، واختصارًا <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>، كما يحتوي صندوق الأدوات على مجموعة من قواعد التصميم، وعلينا -نحن المبرمجون- أن نتعلم واجهة برمجة التطبيقات وقواعد التصميم معًا، ولهذا يحاول أغلبنا اعتماد صناديق أدوات قليلةً تكون متاحةً في عدة لغات برمجة، لأن تعلم استخدام صندوق الأدوات أصعب من <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم لغة البرمجة</a> نفسها.
</p>

<h3>
	صناديق أدوات الواجهات الرسومية
</h3>

<p>
	تأتي أغلب لغات برمجة نظام التشغيل ويندوز مع صندوق أدوات مضمن فيها، ويكون طبقةً خفيفةً فوق صندوق الأدوات البدائي المضمن في نظام النوافذ نفسه، ويوجد في لغات مثل Visual Basic وDelphi وVisual <a href="https://academy.hsoub.com/programming/cpp/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B5%D8%B1%D9%8A%D9%81-%D9%88%D8%A8%D9%86%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D9%88%D8%A8%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-cpp-r1189/" rel="">C++</a>/<a href="https://academy.hsoub.com/programming/c-sharp/dotnet/%D9%84%D9%85%D8%AD%D8%A9-%D8%B9%D9%86-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-net-core-r998/" rel="">.NET</a>، أما <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-java-r599/" rel="">جافا</a> فتختلف عن لغات ويندوز في أنها تحتوي على صندوق أدوات الرسوم الخاص بها، بل أكثر من صندوق واحد في الواقع، وتعمل هذه الصناديق على أي منصة تعمل عليها جافا، وهذا يعني جميع المنصات تقريبًا، وتوجد صناديق أدوات أخرى يمكن الحصول عليها بشكل مستقل وتُستخدم في أي <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">نظام تشغيل</a> سواء كان <a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%A7-%D9%87%D9%88-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%8A%D9%86%D9%83%D8%B3%D8%9F-r451/" rel="">لينكس</a> أو ويندوز أو ماك، وتحتوي محولات adapters لتسمح للغات المختلفة باستخدامها، وبعض تلك الصناديق تجاري مدفوع، وبعضها مجاني أو حر، والأمثلة على هذه الصناديق تشمل GTK وQt وTk وwxWidegets، ولها جميعًا مواقع وتدعم ويندوز وماك ولينكس:
</p>

<ul>
	<li>
		<a href="http://www.wxpython.org/" rel="external nofollow">wxPython</a>: النسخة الخاصة ببايثون من <a href="http://www.wxwidgets.org/" rel="external nofollow">wxWidgets</a>، وهو مكتوب بلغة <code>C++‎</code>، وتسمى رابطة بايثون إلى wxWidgets باسم WxPython.
	</li>
	<li>
		<a href="https://www1.qt.io/developers/" rel="external nofollow">PyQt, the Qt toolkit</a>: يحتوي على روابط لأغلب لغات البرمجة، وتُعرف روابط بايثون إلى Qt باسم PyQt.
	</li>
	<li>
		<a href="https://www.gtk.org/" rel="external nofollow">GTK+</a>‎: مجموعة من العناصر والأدوات لإنشاء واجهات رسومية، ورابطة بايثون فيه اسمها PyGTk.
	</li>
</ul>

<p>
	تُكتب أغلب برامج لينكس باستخدام Qt وGTk، وكلاهما مجاني للاستخدامات غير التجارية، ويوفر Qt رخصةً تجاريةً لمن شاء، في حين أن رخصة GTk هي رخصة Gnu GPL التي لها شروطها الخاصة بها.
</p>

<p>
	صندوق الأدوات الرسومي الخاص ببايثون والذي يأتي افتراضيًا مع اللغة هو Tkinter، المبني على Tk، وهو صندوق أدوات قديم متعدد نظم التشغيل، وسندرسه هنا، حيث توجد منه إصدارات للغات Tcl وHaskell و<a href="https://wiki.hsoub.com/Ruby" rel="external">Ruby</a> وPerl وبايثون، وتختلف المبادئ المستخدمة في Tk عن صناديق الأدوات الأخرى قليلًا، لذا سنذكر باختصار نظرةً على صندوق أدوات رسومي آخر <a href="https://wiki.hsoub.com/Python" rel="external">لبايثون</a> و C و C++‎، يكون تقليديًا في منظوره العام، لكن سنتعرف أولًا على بعض المفاهيم العامة.
</p>

<h3>
	عناصر الواجهات الرسومية الأساسية
</h3>

<p>
	ذكرنا سابقًا أن التطبيقات الرسومية ذات طبيعة حدَثية -مدفوعة بالأحداث event-driven- في الغالب، ويمكن الرجوع للمقال السابق، للاطلاع على هذا المفهوم، وسنفترض أنك مستخدم معتاد على التعامل مع الواجهات الرسومية، وسنركز على كيفية عمل البرامج الرسومية من منظور المبرمج، ولن ندخل في تفاصيل كيفية كتابة واجهات رسومية معقدة وكبيرة لها نوافذ متعددة أو واجهات MDI أو غيرها، بل سنكتفي بأساسيات إنشاء تطبيق وحيد النافذة فيه بعض العناوين والأزرار والحقول النصية وصناديق الرسائل.
</p>

<p>
	نحتاج أولًا إلى التحقق من المصطلحات التي سنستخدمها، فلبرمجة الواجهات مجموعتها الخاصة من المصطلحات البرمجية، وأكثر المصطلحات استخدامًا فيها هي:
</p>

<h4>
	النافذة window
</h4>

<p>
	جزء من الشاشة يتحكم فيه التطبيق، وتكون النوافذ مربعةً في العادة، لكن قد تسمح بعض البيئات الرسومية بأشكال أخرى، وقد تحتوي النوافذ على نوافذ أخرى داخلها، ويُعامل كل متحكم رسومي GUI control على أنه نافذة بذاته.
</p>

<h4>
	المتحكم Control
</h4>

<p>
	كائن رسومي يُستخدم للتحكم في التطبيق، وتحتوي المتحكمات على خصائص properties، وتولّد أحداثًا events، وتستجيب عادةً لكائنات على مستوى التطبيق، حيث تُرفَق الأحداث بتوابع الكائن الموافق corresponding object، فإذا وقع الحدث نفّذ الكائن أحد توابعه، وتوفر الواجهة الرسومية آليات لربط الأحداث بالتوابع.
</p>

<h4>
	الودجِت Widget
</h4>

<p>
	متحكم مقيَّد عادةً بالمتحكمات المرئية، إذ يمكن ربط بعض المتحكمات -مثل المؤقتات timers- بنافذة ما، لكن دون أن تكون مرئيةً، أما الودجات فهي فئة مرئية فرعية من المتحكمات، ويمكن للمستخدم أو المبرمج أن يعدل فيها.
</p>

<p>
	سنغطي في هذا المقال الودجات Frame وLabel وButton وText Entry وMessage box، كما سنتعرض لاحقًا للودجات Text box وRadio Button، أما الودجات التي لن نذكرها مطلقًا فهي Canvas الخاصة بالرسم، وCheck button الخاصة بالاختيار المتعدد، وImage الخاص بعرض صور BMP وGIF وJPEG وPNG، وListbox للقوائم، و Menu/MenuButton لبناء القوائم المنسدلة menus، وScale/Scrollbar التي توضح الموضع.
</p>

<h4>
	الإطار Frame
</h4>

<p>
	نوع من الودجات يُستخدم لدمج ودجات أخرى معًا، ويُستخدم عادةً لتمثيل النافذة ككل، ويمكن دمج إطارات أخرى فيه.
</p>

<h4>
	التخطيط Layout
</h4>

<p>
	توضع المتحكمات في إطار وفقًا لمجموعة محددة من القواعد أو الإرشادات، وتشكل تلك القواعد ما يعرف بالتخطيط، وقد يُحدَّد بعدة طرق، مثل استخدام إحداثيات محددة بالبكسل على الشاشة، أو باستخدام مواضع نسبية لمكونات أخرى (مثل اليسار، الأعلى)، أو باستخدام شبكة أو جدول. ومن السهل فهم نظام الإحداثيات، لكن تصعب إدارته عند تعديل حجم النوافذ مثلًا، ويُنصح المبتدئون باستخدام نوافذ لا يمكن تغيير حجمها إذا استخدموا تخطيطات مبنيةً على إحداثيات.
</p>

<h4>
	الأب/الابن Parent/Child
</h4>

<p>
	تميل التطبيقات الرسومية لأن تتكون من تسلسل هرمي من المتحكمات أو الودجات، حيث يحتوي إطار المستوى الأعلى الذي يشغل نافذة التطبيق على إطارات فرعية تحتوي على إطارات أو متحكمات أخرى، وينظر إلى تلك المتحكمات على أنها هيكل شجري يحتوي كل متحكم فيه على أب واحد وعدة أبناء، بل يُخزَّن هذا الهيكل عادةً بصراحة بواسطة ودجات، ليستطيع المبرمج -أو البيئة الرسومية نفسها غالبًا- تنفيذ بعض الإجراءات الشائعة لمتحكم ما وجميع أبنائه، فإغلاق الودجت العليا ينتج عنه إغلاق جميع الودجات الفرعية.
</p>

<h3>
	شجرة الاحتواء Containment tree
</h3>

<p>
	من المفاهيم التي يجب استيعابها في برمجة الواجهات الرسومية هرمية الاحتواء containment hierarchy، حيث تُحتوى الودجات داخل هيكل شجري تتحكم فيه ودجت المستوى الأعلى بالواجهة كلها، ويكون لذلك الهيكل ودجات فرعية يمكن أن تحتوي بدورها على ودجات أخرى فرعية خاصة بها، وتصل الأحداث إلى ودجت فرعية تمرر الحدث -إذا لم تستطع معالجته- إلى الودجت الرئيسية (الأب) لها، وهكذا إلى أن نصل إلى ودجت المستوى الأعلى، وإذا أُعطي أمر لرسم ودجت ما فسيرسَل الأمر إلى الودجات الفرعية، وعليه فإن أمر الرسم إلى ودجت المستوى الأعلى قد يعيد رسم التطبيق كله، في حين أن أمر الرسم المرسَل إلى زر ما لن يعيد إلا رسم الزر فقط.
</p>

<p>
	ومفهوم صعود الأحداث إلى أعلى الشجرة ودفع الأوامر إلى الأسفل ضروري لفهم كيفية عمل الواجهات الرسومية بالنسبة للمبرمج، وهو السبب في أننا نحتاج إلى تحديد أب للودجت عند إنشائها، لتعرف الودجت مكانها في شجرة الاحتواء. وتُرسم شجرة الاحتواء لتطبيق بسيط سننشئه لاحقًا في هذا الموضوع كما يلي:
</p>

<p style="text-align: center;">
	<img alt="guitree.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83336" data-unique="o0wj804bx" src="https://academy.hsoub.com/uploads/monthly_2021_11/guitree.png.7affe396fc84aafec6546507c66d8c7f.png">
</p>

<p>
	توضح الصورة أعلاه ودجت المستوى الأعلى التي تحتوي على إطار <code>Frame</code> واحد يمثل الحد border الخارجي للنافذة، والذي يحتوي بدوره على إطارين آخرين، في الأول منهما ودجت <code>Text Entry</code>، وفي الثاني زران <code>Buttons</code> يُستخدمان للتحكم في التطبيق، وسنشير إلى هذا المخطط لاحقًا حين نأتي لبناء الواجهة الرسومية.
</p>

<h2>
	نظرة على بعض الودجات الشائعة
</h2>

<p>
	سنستخدم محث بايثون التفاعلي في هذا القسم لإنشاء بعض النوافذ والودجات البسيطة، ورغم أن IDLE نفسه ما هو إلا تطبيق Tkinter لكن لا يُمكن الاعتماد عليه في تشغيل تطبيقات Tkinter داخله، وإنما نستطيع إنشاء الملفات باستخدامه مثل محرر، ثم نشغلها في بيئة التطوير IDE كالمعتاد، رغم احتمال حدوث أشياء غير متوقعة هنا، فإذا وقعت تصرفات غريبة فيجب أن نشغل التطبيق من سطر أوامر النظام قبل أن نجرب شيئًا آخر، فربما تكون المشكلة تعارضًا بين إطار Tkinter الداخلي لبيئة IDLE وبين نسخته لبرنامجنا، فإذا لم تُحل المشكلة فسنبحث عن الزلات البرمجية bugs في شيفرة البرنامج. أما مستخدمو Pythonwin فيستطيعون تشغيل تطبيقات Tkinter مباشرةً دون مشاكل، لأن Pythonwin لا تستخدم Tkinter داخليًا، لكن حتى هنا قد تحدث سلوكيات غير متوقعة في تطبيقات Tkinter، ولهذا نستخدم محث بايثون الأساسي من نافذة نظام التشغيل الطرفية دومًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_17" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> tkinter </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span></pre>

<p>
	هذا أول متطلبات أي برنامج Tkinter، وهو استيراد أسماء الودجات، يجب أن نستورد الوحدة، لكننا لا نريد كتابة <code>tkinter</code> قبل كل اسم مكون، لذا نستخدم الاسم البديل <code>tk</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_19" style=""><span class="pln"> </span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> tkinter </span><span class="kwd">as</span><span class="pln"> tk</span></pre>

<p>
	وهذا يعني أننا نحتاج إلى سبق الأسماء بـ <code>tk.‎</code> فقط، لكن بما أننا نجرب هنا فمن الأسهل استيراد كل شيء:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_21" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> top </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Tk</span><span class="pun">()</span></pre>

<p>
	ينشئ هذا ودجت المستوى الأعلى في هرمية الودجات، ونلاحظ حالة الأحرف في <code>Tk</code>، حيث كان اسم الوحدة بالأحرف الصغيرة، لكن اسم الودجت بأحرف كبيرة، وتُنشأ جميع الودجات الأخرى فروعًا لودجت <code>top</code>.
</p>

<p>
	يعتمد ما يحدث هنا على المكان الذي نكتب البرنامج فيه، فإذا كنا نستخدم بايثون من محث النظام فيجب أن تظهر نافذة جديدة كاملة بشريط عنوان فارغ مع شعار Tk أيقونةً، وأزرار التحكم المعتادة من التكبير والتصغير وغيرها، أما إذا كنا نستخدم بيئة تطوير IDE فقد لا نرى شيئًا، وقد لا تظهر النافذة إلا عند إكمال واجهة المستخدم الرسومية والبدء بتشغيل حلقة الحدث الرئيسية.
</p>

<p>
	سنضيف المكونات إلى هذه النافذة أثناء بنائنا للتطبيق، ولننظر الآن إلى ما لدينا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_23" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> dir</span><span class="pun">(</span><span class="pln">top</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[....</span><span class="pln">lots of stuff</span><span class="pun">!...]</span></pre>

<p>
	توضح دالة <code>dir()‎</code> الأسماء المعروفة للوسيط، ونستطيع استخدامها على <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-r1333/" rel="">الوحدات</a> لكننا ننظر هنا إلى المكونات الداخلية للكائن <code>top</code>، وهو نسخة من الصنف <code>Tk</code>، حيث نلاحظ وجود سمات كثيرة للكائن <code>top</code>، نخص بالذكر منها <code>children</code> و<code>master</code> اللتان تمثلان روابط إلى شجرة احتواء الودجت، كما نلاحظ سمة <code>_tclCommands_</code>، لأن Tkinter بُني على صندوق أدوات من Tcl اسمه Tk.
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_7006_26" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> F </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">top</span><span class="pun">)</span></pre>

<p>
	لننشئ ودجت إطار <code>Frame</code> هنا تحتوي المتحكمات/الودجات الفرعية التي نستخدمها، ويحدد <code>Frame</code> كائن <code>top</code> على أنه معامله الأول -والوحيد في هذه الحالة-، وعليه فإن <code>F</code> ستكون ودجت فرعيةً للكائن <code>top</code>، ,يمكن التحقق من هذا بسهولة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_28" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> top</span><span class="pun">.</span><span class="pln">children
</span><span class="pun">{</span><span class="str">'!frame'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">tkinter</span><span class="pun">.</span><span class="typ">Frame</span><span class="pln"> object </span><span class="pun">.!</span><span class="pln">frame</span><span class="pun">&gt;}</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> F</span><span class="pun">.</span><span class="pln">master
</span><span class="pun">&lt;</span><span class="pln">tkinter</span><span class="pun">.</span><span class="typ">Tk</span><span class="pln"> object </span><span class="pun">.&gt;</span><span class="pln"> </span></pre>

<p>
	نرى هنا أن <code>top.children</code> ما هو إلا قاموس يربط اسمًا غريبًا قليلًا هو <code>‎'!frame'‎</code> بمرجع كائن object reference، وهذه التسمية الغريبة خاصة بـ Tcl/Tk وانتقلت إلى Tkinter، كما أن <code>F.master</code> ما هو إلا مرجع إلى <code>top</code>، وننصحك هنا بالتدرب على السمتين <code>master</code> و<code>children</code> لودجاتنا، مما يسهل عليك فهم الصلة بين الودجات وشجرة الاحتواء التي ذكرناها من قبل.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_30" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> F</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span></pre>

<p>
	لاحظ الآن تقلص نافذة Tk -إذا كانت مرئيةً- إلى حجم ودجت الإطار المضاف، وهي صغيرة للغاية لأن الودجت فارغة، لكن ينبغي أن نكون قادرين على تغيير حجمها بالفأرة وأزرار التصغير والتكبير في شريط عنوانها.
</p>

<p>
	يستدعي التابع <code>pack()‎</code> مدير تخطيط يُعرف باسم المحزِّم Packer، وهو سهل الاستخدام في التخطيطات البسيطة، لكنه يصبح صعبًا كلما زاد تعقيد التخطيط، وسنستخدمه الآن لسهولته، حيث يكدس هذا المحزِّم الودجات بعضها فوق بعض، ونلاحظ أن الودجات لن تكون مرئيةً في تطبيقنا حتى نحزمها أو نستخدم تابع مدير تخطيط آخر، وسنتحدث عن مدراء التخطيطات لاحقًا، بعد إنهاء هذا البرنامج.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_32" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> lHello </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Label</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Hello world"</span><span class="pun">)</span></pre>

<p>
	ننشئ هنا كائنًا جديدًا هو <code>lHello</code>، وهو نسخة من الصنف <code>Label</code> مع ودجت أب هي <code>F</code>، وسمة <code>text</code> قيمتها "Hello World"، نلاحظ أنه من المعتاد استخدام تقنية المعامِل المسمى بتمرير الوسائط إلى كائنات Tkinter بسبب ميل منشئات كائنات Tkinter لامتلاك عدة معامِلات لكل منها قيمته الافتراضية، كما نلاحظ أن الكائن ليس مرئيًا بعد لأننا لم نحزّمه.
</p>

<p>
	كما نلاحظ استخدام اصطلاح تسمية هنا، وهو حرف <code>l</code> الذي يشير إلى كلمة <code>Label</code> قبل الاسم <code>Hello</code> الذي يذكرنا بالغرض منه، ومسألة اصطلاحات التسمية هذه هي في الحقيقة أمور شخصية، لكنها مفيدة لهذا الغرض الذي ذكرناه.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_34" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> lHello</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span></pre>

<p>
	نستطيع الآن أن نراها، وينبغي أن تكون النافذة التي أنشأتها لديك شبيهة بهذه:
</p>

<p style="text-align: center;">
	<img alt="tk-hello.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83340" data-unique="moab87nkq" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-hello.png.1c27806fff2a63f5e7fa481d8450d072.png">
</p>

<p>
	تُحدَّد خصائص <code>Label</code> -مثل الخط واللون- باستخدام معامِلات منشئ الكائن أيضًا، ونستطيع الوصول إلى الخصائص الموافقة corresponding باستخدام التابع <code>configure</code> الخاص بودجات Tkinter كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_36" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> lHello</span><span class="pun">.</span><span class="pln">configure</span><span class="pun">(</span><span class="pln">text</span><span class="pun">=</span><span class="str">"Goodbye"</span><span class="pun">)</span></pre>

<p>
	لقد تغيرت الرسالة هنا، لذا نرى أن تقنية <code>configure</code> ممتازة عند تغيير عدة خصائص مرةً واحدةً لتمريرها جميعًا على أنها وسطاء، لكن إذا أردنا تغيير خاصية واحدة فقط في كل مرة كما فعلنا أعلاه فيمكن معاملة الكائن على أنه قاموس، وهذا أقصر وأسهل في الفهم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_38" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> lHello</span><span class="pun">[</span><span class="str">'text'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Hello again"</span></pre>

<p>
	إن ودجات العناوين مملة، ولا تعرض إلا نصوصًا قابلة للقراءة فقط، وإن كانت بألوان وخطوط مختلفة، رغم إمكانية استخدامها لعرض رسوم بسيطة، لكننا لن نتطرق إلى هذا هنا، نقول هذا لننظر في نوع كائن آخر، لكن ثمة شيء نفعله وهو إعداد عنوان النافذة، وذلك باستخدام تابع من ودجت المستوى الأعلى <code>top</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_40" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> F</span><span class="pun">.</span><span class="pln">master</span><span class="pun">.</span><span class="pln">title</span><span class="pun">(</span><span class="str">"Hello"</span><span class="pun">)</span></pre>

<p>
	كان بإمكاننا استخدام <code>top</code> مباشرةً، لكن الوصول من خلال الخاصية الرئيسية للإطار مفيد، كما سنرى لاحقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_42" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> bQuit </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Quit"</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">F</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">)</span></pre>

<p>
	ننشئ هنا ودجت جديدةً هي زر له عنوان <code>Quit</code>، ويرتبط بالأمر <code>F.quit</code>، لاحظ أننا نمرر اسم التابع ولا نستدعيه بإضافة أقواس بعده، وهذا يعني أننا يجب أن نمرر كائن دالة وفقًا لبايثون، سواء كان تابعًا مضمنًا في Tkinter -كما ف حالتنا- أو أي دالة أخرى نعرّفها.
</p>

<p>
	يجب ألا تأخذ الدالة أو التابع أي وسطاء، ويُعرَّف التابع <code>quit</code> في صنف أساسي -وكذلك التابع <code>pack</code>- وترثه جميع ودجات Tkinter، لكنه يُستعدى في الغالب في مستوى النافذة العليا للتطبيق.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_44" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> bQuit</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span></pre>

<p>
	يجعل التابع <code>pack</code> الزر مرئيًا مرةً أخرى هنا، رغم أنك قد تحتاج إلى تغيير حجم النافذة لتراه وفقًا لإعدادات نظام التشغيل لديك، فلن يحدث شيء إذا ضغطت عليه، لأننا لا نملك حلقة أحداث تعمل الآن لتلتقط حدث ضغط الزر وتعالجه.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_46" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> top</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<p>
	وأخيرًا نبدأ حلقة حدث Tkinter، لاحظ اختفاء محث بايثون <code>‎&gt;&gt;&gt;‎</code>، وهذا يخبرنا أن Tkinter هو المتحكم الآن، فإذا ضغطنا زر <code>Quit</code> فسيعود المحث ليثبت لنا أن خيار <code>command</code> يعمل، لا تتوقع أن تنغلق النافذة، فلا زال مفسر بايثون يعمل ولم نرد إلا الخروج من دالة <code>mainloop</code>، فإذا خرجنا من بايثون فستُدمَّر الودجات الموجودة، ويكون هذا -في البرامج الحقيقية- بعد انتهاء mainloop مباشرة.
</p>

<p>
	ونلاحظ أنه إذا شغلنا هذا من IDLE أو Pythonwin فلم نكن لنرى شيئًا إلى الآن، ولحصلنا على نتيجة مختلفة قليلًا، وإذا حدث هذا معك فاكتب الأوامر التي كتبناها إلى الآن في سكربت بايثون ثم شغلها من سطر أوامر النظام، ومن المناسب الآن أن تجرب ذلك على أي حال بما أنه الكيفية التي ستشغل بها برامج Tkinter في الممارسة العملية، واستخدم الأوامر الأساسية التي شرحناها حتى الآن وكما وضحنا، واستخدم نمط الاستيراد المفضل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_48" style=""><span class="kwd">import</span><span class="pln"> tkinter </span><span class="kwd">as</span><span class="pln"> tk

</span><span class="com"># إعداد النافذة ذاتها</span><span class="pln">
top </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Tk</span><span class="pun">()</span><span class="pln">
F </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">top</span><span class="pun">)</span><span class="pln">
F</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span><span class="pln">

</span><span class="com"># إضافة الودجات</span><span class="pln">
lHello </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Hello"</span><span class="pun">)</span><span class="pln">
lHello</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span><span class="pln">
bQuit </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Quit"</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">F</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">)</span><span class="pln">
bQuit</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span><span class="pln">

</span><span class="com"># تشغيل الحلقة التكرارية</span><span class="pln">
top</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<p>
	يبدأ استدعاء التابع <code>top.mainloop</code> حلقة حدث Tkinter لتوليد الأحداث، والحدث الوحيد الذي نلتقطه في هذه الحالة سيكون حدث ضغط الزر المتصل بالتابع <code>F.quit</code>، وينهي الأخير التطبيق وستنغلق النافذة هذه المرة لأن بايثون قد خرجت هي الأخرى، جربها بنفسك الآن، ينبغي أن تبدو كما يلي:
</p>

<p style="text-align: center;">
	<img alt="tk-hellbut.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83339" data-unique="c86a129kn" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-hellbut.png.864aa41ffe23fb1198098d1a68dbb99d.png">
</p>

<p>
	لاحظ أننا نسينا السطر الذي يغير عنوان النافذة، جرب إضافة ذلك السطر بنفسك وتحقق من نجاح ذلك.
</p>

<h2>
	استكشاف التخطيط
</h2>

<p>
	سنبدأ من الآن بإعطاء الأمثلة في ملفات سكربتات بايثون بدلًا من أوامر في محث <code>‎&gt;&gt;&gt;‎</code>، وسنوفر مقتطفات من الشيفرات في الغالب لتكتب أنت الاستدعاءات إلى <code>Tk()‎</code> و<code>mainloop()‎</code> بنفسك، فاستخدم البرنامج السابق قالبًا، وسننظر في هذا القسم في توضع الودجات في النافذة في Tkinter، وقد رأينا ودجات <code>Frame</code> و<code>Label</code> و<code>Button</code> من قبل، وهي كل ما نحتاج إليه في هذا القسم، وقد استخدمنا التابع <code>pack</code> الخاص بالودجت في المثال السابق لتحديد موقعها في الودجت الأب لها، والواقع أن ما نفعله هو استدعاء مدير تخطيط المحزِّم الخاص بـ Tk، ويطلق عليه أحيانًا اسم المدير الهندسي Geometry Manager، ووظيفته تحديد أفضل تخطيط للودجات بناءً على الإرشادات التي يوفرها المبرمج، إضافةً إلى القيود مثل حجم النافذة التي يتحكم بها المستخدم، ويستخدم بعض مدراء التخطيطات نفس المواقع داخل النافذة محددةً بالبكسل، وهذا أمر شائع في بيئات ويندوز مثل Visual Basic.
</p>

<p>
	ويحتوي Tkinter على مدير تخطيط واضع placer layout manager يستطيع تنفيذ ذلك من خلال تابع <code>place</code>، ولن ننظر فيه لوجود خيارات أخرى أفضل وأكثر ذكاءً للمدراء، لأنها توفر علينا التفكير -نحن المبرمجين- في ما يحدث عند تغيير حجم نافذة ما، وأبسط مدير تخطيط في Tkinter هو برنامج التحزيم الذي كنا نستخدمه، وهو يكدس الودجات بعضها فوق بعض، ويمكن تغيير هذا السلوك لتكديس الودجات يسارًا ويمينًا لكن هذا محدود للغاية، ونادرًا ما نريد ذلك من الودجات العادية، لكن إذا أردنا بناء تطبيقاتنا من إطارات <code>Frames</code> فيجب أن نكدس الإطارات فوق بعضها، ثم نستطيع وضع الودجات الأخرى في الإطارات باستخدام المحزِّم أو مدير تخطيط آخر داخل كل إطار حسب الحاجة، ويمكن أن يكون لكل إطار مدير التخطيط الخاص به، لكننا لا نستطيع الجمع بين المدراء في إطار واحد.
</p>

<p>
	يوفر المحزِّم -وإن كان بسيطًا- عدة خيارات، إذ نستطيع ترتيب ودجاتنا رأسيًا أو أفقيًا، ونستطيع تعديل أحجامها وتعديل الفواصل بينها والإطار التي تحاذيه، لننظر في المثال التالي على التحزيم الأفقي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_50" style=""><span class="pln">lHello </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Hello"</span><span class="pun">)</span><span class="pln">
lHello</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">)</span><span class="pln">
bQuit </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Quit"</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">F</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">)</span><span class="pln">
bQuit</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">)</span></pre>

<p>
	سيؤدي هذا إلى إجبار الودجات على الانتقال إلى اليسار، لذا ستظهر الودجت الأولى -وهي العنوان- في أقصى اليسار، متبوعةً بالودجت التالية -الزر-، فإذا عدّلنا الأسطر في المثال أعلاه فسيبدو كما يلي:
</p>

<p style="text-align: center;">
	<img alt="tk-leftpack.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83342" data-unique="nutsz952h" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-leftpack.png.af8bc064f902ef74e5ebb5f9b7814b3e.png">
</p>

<p>
	وإذا غيرنا <code>"left"</code> إلى <code>"right"</code> فسيظهر العنوان على أقصى اليمين، وسيظهر الزر على يساره، كما يلي:
</p>

<p style="text-align: center;">
	<img alt="tk-rightpack.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83345" data-unique="8pe5zbkt9" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-rightpack.png.bd82201b0e4503f458d07883000366f3.png">
</p>

<p>
	يجب أن نلاحظ أن الشكل غير لطيف، لأن الودجات مضغوطة إلى جانب بعضها البعض، ويزودنا المحزِّم ببعض المعامِلات للتعامل مع ذلك، لعل أسهلها الحشو padding الذي يُحدَّد بحشو أفقي <code>padx</code> ورأسي <code>pady</code>، وتُكتب تلك القيم بالبكسل، لنضف حشوًا أفقيًا إلى مثالنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_52" style=""><span class="pln">lHello</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
bQuit</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">'left'</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span></pre>

<p>
	يجب أن يبدو كما يلي:
</p>

<p style="text-align: center;">
	<img alt="tk-padx.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83344" data-unique="1s05668i4" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-padx.png.44a55a0bda7af17518b020c951927cf8.png">
</p>

<p>
	إذا حاولنا تغيير عرض النافذة فسنرى أن الودجات تحافظ على مواضعها النسبية، لكنها ستظل في مركز النافذة، لأننا -رغم إضافتنا الحشو إلى اليسار- حزمنا الودجات في إطار Frame؛ وحزّمنا الإطار نفسه دون جانب side، لذا فإن موضعه يكون إلى الأعلى والمنتصف، وهو الافتراضي للمحزِّمات، فإذا أردنا أن تبقى الودجات في الجانب الصحيح من النافذة فيجب أن نحزم الإطار إلى الجانب الصحيح كذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_54" style=""><span class="pln">F</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">'left'</span><span class="pun">)</span></pre>

<p>
	نلاحظ هنا أن الودجات تظل في المنتصف إذا غيرنا حجم النافذة الرأسي، وهذا هو السلوك الافتراضي للمحزِّمات أيضًا، سنترك لك تجربة تغيير <code>padx</code> و<code>pady</code> لترى تأثير القيم المختلفة عليها. وتسمح <code>side</code> و<code>padx/pady</code> بمرونة كبيرة في تحديد مواضع الودجات باستخدام المحزِّم، وتوجد خيارات أخرى يضيف كل منها شكلًا خفيفًا من أشكال التحكم، يُرجَع فيها إلى توثيق Tkinter.
</p>

<p>
	يوجد عدة مدراء تخطيطات آخرين في Tkinter مثل الشبكة grid والواضع placer، إضافةً إلى وحدة <code>Tix</code> التي تعزز Tkinter وتوفر مدير التخطيط <code>Form</code>، لكننا لن نشرح هذه الوحدة هنا لأنها أُهملت في المكتبة القياسية رسميًا.
</p>

<p>
	نستخدم <code>grid()‎</code> إذا أردنا استخدام مدير الشبكة grid manager، بدلًا من <code>pack()‎</code> التي استخدمناها أعلاه، أما في الواضع placer فنستدعي <code>place()‎</code> بدلًا من <code>pack()‎</code>، ولكل منها مجموعة خيارات خاصة، وبما أننا سنشرح المحزِّم فقط هنا فيُرجَع إلى توثيق Tkinter لمزيد من التفاصيل عن هؤلاء المدراء، لكن النقاط الأساسية التي نريد الإشارة إليها هنا هي ما يلي:
</p>

<ul>
	<li>
		تنظم الشبكة المكونات في "شبكة" داخل النافذة، وهذا مفيد في الصناديق الحوارية التي تحوي صناديق إدخال نصيةً مرتبةً مثلًا، ويفضل العديد من مستخدمي Tkinter استخدام الشبكة على المحزِّم، لكن قد يحتاج المبتدئ وقتًا حتى يتعلمها، خاصةً عندما يريد أن يشغل مكون عدة خلايا من الشبكة.
	</li>
	<li>
		يستخدم الواضع إحداثيات ثابتةً بالبكسل أو إحداثيات نسبيةً داخل النافذة، وتسمح الأخيرة بتغيير حجم المكونات مع تغير حجم النافذة، كأن تظل المساحة التي تشغلها 75% من المساحة الرأسية للنافذة مثلًا، لكن قد يبدو مظهر الأزرار غريبًا إذا زاد عرضها كثيرًا، وتظهر فائدة هذا في التصاميم المعقدة للنوافذ، لكنها تحتاج إلى كثير من التخطيط المسبق، لذا يُنصح باستخدام الورق والقلم!
	</li>
</ul>

<h2>
	التحكم في المظهر باستخدام الإطارات والمحزم
</h2>

<p>
	تحتوي ودجت الإطار Frame على العديد من الخصائص المفيدة التي يمكن استخدامها، فمن الجميل أن يكون لدينا إطار منطقي غير مرئي حول المكونات، لكننا قد نرغب في رؤيته، خاصةً عند جمع عدة متحكمات مثل أزرار الانتقاء radio buttons أو صناديق الاختيار check boxes، ويحل الإطار هذه المشكلة بتوفير حد يُعرف بخاصية المساعدة relief property، على غرار العديد من ودجات Tkinter الأخرى، يمكن أن تأخذ <code>Relief</code> إحدى القيم التالية:
</p>

<ul>
	<li>
		<code>sunken</code>: غائر.
	</li>
	<li>
		<code>raised</code>: مرتفع.
	</li>
	<li>
		<code>groove</code>: محفور.
	</li>
	<li>
		<code>ridge</code>: مشطوف.
	</li>
	<li>
		<code>flat</code>: مسطح.
	</li>
</ul>

<p>
	لنستخدم القيمة <code>sunken</code> على صندوق حوارنا البسيط، بتغيير سطر إنشاء الإطار <code>Frame</code> إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_56" style=""><span class="pln"> F </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">top</span><span class="pun">,</span><span class="pln"> relief</span><span class="pun">=</span><span class="str">"sunken"</span><span class="pun">,</span><span class="pln"> border</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span></pre>

<p>
	لاحظ أن عليك وضع حد border أيضًا، فإن لم تفعل فسيكون الإطار غاطسًا لكنه سيكون مخفيًا لأن حدوده غير مرئية، فلن ترى فرقًا إذا لم تضف الحد، ولا تضع حجم الحد بين علامتي اقتباس، وهذا أحد الأمور المربكة في برمجة Tk، أي معرفة متى نستخدم علامات الاقتباس حول خيار ما ومتى لا نستخدمها، لكن القاعدة العامة هي أنه يمكن ترك علامات الاقتباس إذا كانت القيمة عدديةً، أما إذا كانت مزيجًا بين الأرقام والحروف أو سلسلةً نصيةً فيجب وضع علامات الاقتباس، يمكن قول ذلك على حالة الأحرف التي يجب استخدامها، لكن للأسف لا توجد طريقة سهلة لمعرفة ذلك هنا، بل يجب أن نتعلمها بالخبرة، وتعطيك بايثون عادةً قائمةً من الخيارات الصالحة في رسائل الخطأ الخاصة بها.
</p>

<p>
	ومما يجب ملاحظته أيضًا أن الإطار لا يملأ النافذة، ونستطيع إصلاح ذلك بخيار محزِّم آخر هو <code>fill</code>، فنفعل ما يلي عند تحزيم الإطار:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_58" style=""><span class="pln">F</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">fill</span><span class="pun">=</span><span class="str">"x"</span><span class="pun">)</span></pre>

<p>
	ستُملأ النافذة عرضيًا كما هو واضح من الإحداثي x، فإذا أردنا ملأها كلها فنستخدم <code>fill='y'‎</code> أيضًا، ويوجد خيار ملء خاص هو <code>both</code> بسبب شيوع هذه العملية:
</p>

<pre class="ipsCode">F.pack(fill="both")
</pre>

<p>
	ينبغي أن تكون النتيجة النهائية بعد تشغيل السكربت كما يلي:
</p>

<p style="text-align: center;">
	<img alt="tk-sunken.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83346" data-unique="epiewsm70" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-sunken.png.f99fd972ddc80ef0e4d8392aba363a29.png">
</p>

<h2>
	إضافة ودجات أخرى
</h2>

<p>
	لننظر الآن في الودجت <code>Entry</code>، وهو السطر الواحد ذو الشكل المألوف لصندوق الإدخال النصي، والذي يتشارك الكثيرَ من التوابع مع ودجت النص متعدد الأسطر الذي استخدمناه في <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AD%D8%AF%D8%AB%D9%8A%D8%A9-event-driven-programming-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D9%82%D8%A9-%D8%A8%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-r1376/" rel="">المقال السابق</a>، كما سنستخدمه في مقال لاحق، وسنستخدم <code>Entry</code> لالتقاط النص الذي يكتبه المستخدم، ولمحو ذلك النص عند الحاجة.
</p>

<p>
	بالعودة إلى مثال Hello World، سنضيف ودجت إدخال نصي داخل إطار خاص به، ثم نضع زرًا في إطار ثانٍ يستطيع مسح ذلك النص الذي نكتبه داخل خانة الكتابة، ثم نضيف زرًا آخر للخروج من التطبيق، وهذا يوضح كيفية إنشاء واستخدام ودجت الإدخال، وكيفية تعريف دوال معالجة الأحداث الخاصة بنا وتوصيلها بالودجات.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_62" style=""><span class="kwd">import</span><span class="pln"> tkinter </span><span class="kwd">as</span><span class="pln"> tk

</span><span class="com"># أنشئ معالج الحدث لمسح النص</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> evClear</span><span class="pun">():</span><span class="pln">
   eHello</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">END</span><span class="pun">)</span><span class="pln">

</span><span class="com"># أنشئ نافذة/إطار المستوى الأعلى</span><span class="pln">
top </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Tk</span><span class="pun">()</span><span class="pln">
F </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">top</span><span class="pun">)</span><span class="pln">
F</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">fill</span><span class="pun">=</span><span class="str">"both"</span><span class="pun">)</span><span class="pln">

</span><span class="com"># والآن الإطار الذي فيه الإدخال النصي</span><span class="pln">
fEntry </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> border</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
eHello </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Entry</span><span class="pun">(</span><span class="pln">fEntry</span><span class="pun">)</span><span class="pln">
fEntry</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"top"</span><span class="pun">)</span><span class="pln">
eHello</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">)</span><span class="pln">

</span><span class="com"># وأخيرًا الإطار الذي فيه الأزرار </span><span class="pln">
</span><span class="com"># سنجعل هذا غاطسًا لنبرزه</span><span class="pln">
fButtons </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> relief</span><span class="pun">=</span><span class="str">"sunken"</span><span class="pun">,</span><span class="pln"> border</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
bClear </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">fButtons</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Clear Text"</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">evClear</span><span class="pun">)</span><span class="pln">
bClear</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
bQuit </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">fButtons</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Quit"</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">F</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">)</span><span class="pln">
bQuit</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
fButtons</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"top"</span><span class="pun">,</span><span class="pln"> fill</span><span class="pun">=</span><span class="str">"x"</span><span class="pun">)</span><span class="pln">

</span><span class="com"># والآن شغل حلقة الحدث</span><span class="pln">
F</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<p>
	نلاحظ هنا أننا عرّفنا معالج الحدث مثل أي دالة أخرى، وبما أننا نريد إسنادها إلى حدث الأمر command event لزر فنعرف أنها يجب ألا تحتوي على معامِلات، رغم أن بعض معالجات الأحداث -مثل أحداث الفأرة- قد تأخذ معامِلات، لكن يجب التحقق من التوثيق لمعرفة المطلوب للحدث.
</p>

<p>
	لاحظ أيضًا أننا نمرر أسماء معالجات الأحداث <code>evClear</code> و<code>F.quit</code> -دون أقواس- قيمًا للمعامل <code>command</code> للأزرار، ولاحظ استخدام اصطلاح التسمية evXXX لربط معالج الحدث بالودجت XXX الموافقة له، لذا سيكون <code>evClear</code> هو معالج الحدث لودجت <code>bClear</code>.
</p>

<p>
	يستدعي معالج الحدث التابع <code>delete</code> الخاص بالودجت <code>Entry</code>، ورغم أن نظام الفهرسة المستخدم للوسطاء معقد قليلًا إلا أننا نستطيع في هذا المستوى أن نقول بأنه يمسح النص من الموضع <code>0</code> -أي من البداية- إلى الموضع <code>tk.END</code> -آخر موضع-، ولاحظ أن <code>tk.END</code> ثابت معرَّف في tkinter، ويوجد غيره مما يمكن استخدامه بدلًا من السلاسل الاختيارية <code>right</code> و<code>left</code> و<code>top</code> وغيرها، وذلك راجع لما يفضله كل منا، وبتشغيل البرنامج نحصل على النتيجة التالية:
</p>

<p style="text-align: center;">
	<img alt="tk-entry.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83337" data-unique="ymnwayz9u" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-entry.png.6bc23be18a1deb717644f01d2c970d5e.png">
</p>

<p>
	فإذا كتبت شيئًا في صندوق الإدخال النصي فاضغط Clear Text لمسحه مرةً أخرى.
</p>

<p>
	لاحظ أننا بنينا الواجهة الرسومية التي رسمها مخطط الاحتواء في بداية هذا المقال، فللودجت العليا إطار <code>Frame</code> تحتها، وفيه إطاران تحته، واحد فيه ودجت إدخال والآخر فيه زران، وهذا ما نراه في المخطط بالضبط.
</p>

<p>
	ولا توجد فائدة تذكر من وجود ودجت إدخال إلا إذا كنا نستطيع الوصول إلى النص الذي فيها، ونفعل ذلك باستخدام التابع <code>get</code> الخاص بالودجت، وسنوضح هذا بنسخ النص من الودجت إلى عنوان label قبل مسحه، لنستطيع رؤية النص الأخير الذي كان في الودجت، ولفعل ذلك نحتاج إلى إضافة ودجت عنوان تحت ودجت الإدخال، وتوسيع معالج الحدث evClear لينسخ النص، وسنلون نص العنوان بلون أزرق فاتح لإبرازه.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_64" style=""><span class="kwd">import</span><span class="pln"> tkinter </span><span class="kwd">as</span><span class="pln"> tk

</span><span class="com"># أنشئ معالج الحدث لمسح النص</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> evClear</span><span class="pun">():</span><span class="pln">
  lHistory</span><span class="pun">[</span><span class="str">'text'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> eHello</span><span class="pun">.</span><span class="pln">get</span><span class="pun">()</span><span class="pln">
  eHello</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">END</span><span class="pun">)</span><span class="pln">

</span><span class="com"># أنشئ نافذة/إطار المستوى الأعلى</span><span class="pln">
top </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Tk</span><span class="pun">()</span><span class="pln">
F </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">top</span><span class="pun">)</span><span class="pln">
F</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">fill</span><span class="pun">=</span><span class="str">"both"</span><span class="pun">)</span><span class="pln">

</span><span class="com"># والآن الإطار الذي فيه الإدخال النصي</span><span class="pln">
fEntry </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> border</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
eHello </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Entry</span><span class="pun">(</span><span class="pln">fEntry</span><span class="pun">)</span><span class="pln">
eHello</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">)</span><span class="pln">
lHistory </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">(</span><span class="pln">fEntry</span><span class="pun">,</span><span class="pln"> foreground</span><span class="pun">=</span><span class="str">"steelblue"</span><span class="pun">)</span><span class="pln">
lHistory</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"bottom"</span><span class="pun">,</span><span class="pln"> fill</span><span class="pun">=</span><span class="str">"x"</span><span class="pun">)</span><span class="pln">
fEntry</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"top"</span><span class="pun">)</span><span class="pln">

</span><span class="com"># وأخيرًا الإطار الذي فيه الأزرار </span><span class="pln">
</span><span class="com"># سنجعل هذا غائرًا لنبرزه</span><span class="pln">
fButtons </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">F</span><span class="pun">,</span><span class="pln"> relief</span><span class="pun">=</span><span class="str">"sunken"</span><span class="pun">,</span><span class="pln"> border</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
bClear </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">fButtons</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Clear Text"</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">evClear</span><span class="pun">)</span><span class="pln">
bClear</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
bQuit </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">fButtons</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Quit"</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">F</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">)</span><span class="pln">
bQuit</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
fButtons</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"top"</span><span class="pun">,</span><span class="pln"> fill</span><span class="pun">=</span><span class="str">"x"</span><span class="pun">)</span><span class="pln">

</span><span class="com"># والآن شغل حلقة الحدث</span><span class="pln">
F</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<p>
	نرى هنا أننا أضفنا السطر التالي عند إنشاء معالج الحدث الذي يمسح النص:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_66" style=""><span class="pln">  lHistory</span><span class="pun">[</span><span class="str">'text'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> eHello</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">()</span></pre>

<p>
	كما أضفنا الأسطر التالية في الإطار الذي يحتوي على إدخال نصي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_68" style=""><span class="pln">lHistory </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">(</span><span class="pln">fEntry</span><span class="pun">,</span><span class="pln"> foreground</span><span class="pun">=</span><span class="str">"steelblue"</span><span class="pun">)</span><span class="pln">
lHistory</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"bottom"</span><span class="pun">,</span><span class="pln"> fill</span><span class="pun">=</span><span class="str">"x"</span><span class="pun">)</span></pre>

<p>
	من الممكن إسناد النص إلى متغير بايثون عادي لنستخدمه لاحقًا في برنامجنا، رغم أننا أسندناه مباشرةً إلى خاصية <code>Label</code> هنا.
</p>

<h2>
	أحداث الربط: من الودجات إلى الشيفرة
</h2>

<p>
	لقد استخدمنا الخاصية command للأزرار إلى الآن لربط دوال بايثون مع أحداث الواجهة الرسومية، لكننا قد نريد تحكمًا أكثر من هذا أحيانًا، لالتقاط تجميعة مفاتيح معينة مثلًا، ونفعل ذلك باستخدام دالة <code>bind</code> لربط حدث ما مع دالة بايثون صراحةً.
</p>

<p>
	سنعرِّف الآن مفتاحًا ساخنًا مثل CTRL+C لحذف النص في المثال أعلاه، سنحتاج هنا أن نربط تجميعة المفاتيح CTRL+C بنفس معالج الحدث الخاص بزر Clear، لكننا سنواجه مشكلةً غير متوقعة هنا، إذ يجب ألا تأخذ الدالة المحددة أي وسطاء عند استخدامنا للخيار command، أما حين نستخدم دالة الربط bind لأداء نفس الوظيفة فيجب أن تأخذ الدالة المحددة وسيطًا واحدًا، لذا نحتاج إلى إنشاء دالة جديدة ذات معامِل وحيد تستدعي <code>evClear</code>، أضف الشيفرة التالية بعد تعريف <code>evClear</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_74" style=""><span class="kwd">def</span><span class="pln"> evHotKey</span><span class="pun">(</span><span class="pln">event</span><span class="pun">):</span><span class="pln">
    evClear</span><span class="pun">()</span></pre>

<p>
	ثم أضف السطر التالي مباشرةً بعد تعريف ودجت الإدخال <code>eHello</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_76" style=""><span class="pln">eHello</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="str">"&lt;Control-c&gt;"</span><span class="pun">,</span><span class="pln">evHotKey</span><span class="pun">)</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">تعريف</span><span class="pln"> </span><span class="pun">المفتاح</span><span class="pln"> </span><span class="pun">حساس</span><span class="pln"> </span><span class="pun">لحالة</span><span class="pln"> </span><span class="pun">الأحرف</span></pre>

<p>
	شغّل البرنامج الآن مرةً أخرى، ستستطيع مسح النص الآن بضغط الزر أو باستخدام تجميعة المفاتيح CTRL+C، ويمكن استخدام الربط لالتقاط نقرات الفأرة أو فقدان تركيز النافذة Focus -أي كونها نشطةً أو غير نشطة-، أو حتى كون النافذة مرئيةً أم لا، ويُرجَع في هذا إلى توثيق Tkinter لمزيد من المعلومات، وسيكون الجزء الأصعب هو معرفة صيغة وصف الحدث.
</p>

<h2>
	الرسالة القصيرة
</h2>

<p>
	من الممكن إبلاغ رسائل قصيرة للمستخدمين باستخدام MessageBox، وهذا سهل للغاية في Tk ويمكن تنفيذه باستخدام دوال وحدة <code>messagebox</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_78" style=""><span class="pln">from tkinter </span><span class="kwd">import</span><span class="pln"> messagebox
messagebox</span><span class="pun">.</span><span class="pln">showinfo</span><span class="pun">(</span><span class="str">"Window Text"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"A short message"</span><span class="pun">)</span><span class="pln"> </span></pre>

<p>
	هناك أيضًا صناديق الخطأ والتحذير وصناديق نعم ولا Yes/No وموافق وإلغاء Ok/Cancel التي يمكن استخدامها من خلال دوال <code>showXXX</code> المختلفة، ويمكن تمييزها بأيقوناتها وأزرارها المختلفة، ويستخدم الصندوقان الأخيران <code>askxxx</code> بدلًا من <code>showxxx</code>، ويعيد قيمةً لتوضيح على أي زر ضغط المستخدم، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_80" style=""><span class="pln">res </span><span class="pun">=</span><span class="pln"> messagebox</span><span class="pun">.</span><span class="pln">askokcancel</span><span class="pun">(</span><span class="str">"Which?"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Ready to stop?"</span><span class="pun">)</span><span class="pln">
print res</span></pre>

<p>
	فيما يلي بعض الأمثلة لصناديق الرسائل في Tkinter:
</p>

<p style="text-align: center;">
	<img alt="tk-info.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83341" data-unique="574mqei6z" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-info.png.d81efa4a4fcba02a508f53b09135ac8f.png">
</p>

<p style="text-align: center;">
	<img alt="tk-error.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83338" data-unique="scsijx9va" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-error.png.c041f007af9dc642a371cb743366246e.png">
</p>

<p style="text-align: center;">
	<img alt="tk-yesno.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83347" data-unique="chyto6wjt" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-yesno.png.1da0bf28644bb54d836f003f09410b60.png">
</p>

<p>
	وهذا شبيه بصناديق <code>alert</code> و<code>MsgBox</code> التي استخدمناها في برامج الويب من جافاسكربت وVBScript في دروسنا الأولى.
</p>

<p>
	كما توجد صناديق حوارية قياسية يمكن استخدامها للحصول على أسماء الملفات أو المجلدات من المستخدم، تشبه صناديق "Open File" أو "Save File"، ولن نشرحها هنا لكن يمكن الاطلاع على أمثلة عنها في صفحات Tkinter المرجعية، تحت قسم <a href="http://effbot.org/tkinterbook/tkinter-standard-dialogs.htm" rel="external nofollow">Standard Dialogs</a>.
</p>

<h2>
	تغليف التطبيقات مثل الكائنات
</h2>

<p>
	من الشائع في برمجة الواجهات الرسومية أن نغلف التطبيق كله مثل صنف واحد، وهذا يطرح سؤال كيف نلائم ودجات تطبيق Tkinter في هيكل هذا الصنف؟
</p>

<p>
	لدينا خياران هنا، فإما أن نقرر جعل التطبيق نفسه صنفًا فرعيًا من إطار Tkinter، وإما أن نجعل أحد الحقول الأعضاء (الخاصيات) يخزن مرجعًا إلى نافذة المستوى الأعلى، ويُستخدم المنظور الثاني بكثرة في صناديق الأدوات الأخرى لذا سنتبعه، أما المنظور الأول فيمكن رؤيته في المقال السابق، الذي يحوي أيضًا توضيحًا لاستخدام بسيط لودجت النص الخاصة بـ Tkinter، إضافةً إلى مثال آخر لاستخدام <code>bind</code>.
</p>

<p>
	سنحول المثال أعلاه إلى هيكل كائني التوجه باستخدام حقل إدخال وزر Clear وزر Quit، لكننا سننشئ أولًا صنف تطبيق، ونجمّع الأجزاء المرئية للواجهة الرسومية داخل الباني Constructor، ثم نسند الإطار الناتج إلى <code>self.mainWindow</code>، سامحين بهذا للتوابع الأخرى للصنف بالوصول إلى إطار المستوى الأعلى، وتُسنَد الودجات الأخرى التي قد نحتاج إلى الوصول إليها -مثل حقل الإدخال- إلى متغيرات أعضاء member variables للتطبيق.
</p>

<p>
	تصبح معالجات الأحداث توابعًا لصنف التطبيق باستخدام هذه التقنية، ويكون لها وصول إلى أي أعضاء بيانات data members لتطبيق -رغم عدم وجود أي منها في حالتنا هنا- من خلال مرجع <code>self</code>، مما يوفر تكاملًا سلسًا للواجهة الرسومية مع كائنات التطبيق الأساسية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7006_82" style=""><span class="kwd">import</span><span class="pln"> tkinter as tk

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">معالج</span><span class="pln"> </span><span class="pun">الحدث</span><span class="pln"> </span><span class="pun">لمسح</span><span class="pln"> </span><span class="pun">النص</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ClearApp</span><span class="pun">:</span><span class="pln">
    def __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> parent</span><span class="pun">):</span><span class="pln">
        </span><span class="pun">#</span><span class="pln"> create the top level window</span><span class="pun">/</span><span class="pln">frame
        self</span><span class="pun">.</span><span class="pln">mainWindow </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">parent</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">eHello </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Entry</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">mainWindow</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">eHello</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="str">"Hello world"</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">eHello</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">fill</span><span class="pun">=</span><span class="str">"x"</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">5</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">eHello</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="str">"&lt;Control-c&gt;"</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">evHotKey</span><span class="pun">)</span><span class="pln">

        </span><span class="pun">#</span><span class="pln"> </span><span class="pun">والآن</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">الإطار</span><span class="pln"> </span><span class="pun">ذا</span><span class="pln"> </span><span class="pun">الأزرار.</span><span class="pln"> 
        fButtons </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">mainWindow</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">bClear </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">fButtons</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Clear"</span><span class="pun">,</span><span class="pln">
                             width</span><span class="pun">=</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln">command</span><span class="pun">=</span><span class="pln">self</span><span class="pun">.</span><span class="pln">evClear</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">bQuit  </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">fButtons</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Quit"</span><span class="pun">,</span><span class="pln">
                             width</span><span class="pun">=</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> command</span><span class="pun">=</span><span class="pln">self</span><span class="pun">.</span><span class="pln">mainWindow</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">bClear</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">15</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">bQuit</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"right"</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">15</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        fButtons</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"top"</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> fill</span><span class="pun">=</span><span class="str">"x"</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">mainWindow</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">mainWindow</span><span class="pun">.</span><span class="pln">master</span><span class="pun">.</span><span class="pln">title</span><span class="pun">(</span><span class="str">"Clear"</span><span class="pun">)</span><span class="pln">

    def evClear</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">eHello</span><span class="pun">.</span><span class="kwd">delete</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">END</span><span class="pun">)</span><span class="pln">

    def evHotKey</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> event</span><span class="pun">):</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">evClear</span><span class="pun">()</span><span class="pln">

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">والآن</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">التطبيق</span><span class="pln"> </span><span class="pun">وشغل</span><span class="pln"> </span><span class="pun">حلقة</span><span class="pln"> </span><span class="pun">الحدث</span><span class="pln">
top </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="pln">k</span><span class="pun">()</span><span class="pln">
app </span><span class="pun">=</span><span class="pln"> </span><span class="typ">ClearApp</span><span class="pun">(</span><span class="pln">top</span><span class="pun">)</span><span class="pln">
top</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<p>
	ستكون النتيجة كما يلي:
</p>

<p style="text-align: center;">
	<img alt="tk-oopentry.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83343" data-unique="6h0yb6iyd" src="https://academy.hsoub.com/uploads/monthly_2021_11/tk-oopentry.png.f128990c53e1f9f6197ddd3979c1fc88.png">
</p>

<p>
	تبدو النتيجة مشابهةً للصورة السابقة، رغم أننا عدلنا بعض الإعدادات وخيارات التحزيم لتبدو أشبه بمثال wxPython أدناه.
</p>

<p>
	لا شك أننا نستطيع إنشاء صنف مبني على إطار يحتوي مجموعةً قياسيةً من الأزرار، ونعيد استخدامه في بناء نوافذ حوارية مثلًا، فليس التطبيق الرئيسي وحده هو الذي يمكن تغليفه مثل كائن، بل يمكن إنشاء صناديق كاملة واستخدامها في مشاريع مختلفة، أو توسيع إمكانيات الودجات القياسية بإنشاء أصناف فرعية لها، لإنشاء زر يتغير لونه وفقًا لحالته مثلًا، وهو ما فعلناه في وحدة Tix التي ذكرناها أعلاه، وما هي إلا توسيع للصنف Tkinter.
</p>

<p>
	يحتوي Tkinter بدءًا من الإصدار 3.1 على بعض المزايا الجديدة التي تُعرف باسم الودجات ذات السمات themed widgets، وتوجد في وحدة <code>tkinter.ttk</code>، وهي تحسن كثيرًا من مظهر Tkinter إلى حد يصعب التفريق بين نوافذه وبين ودجات النظام المضمّنة، لكننا لن نشرحها هنا، ويُرجَع فيها إلى موقع Tcl/Tk.
</p>

<h2>
	صندوق الأدوات البديل wxPython
</h2>

<p>
	توجد عدة صناديق أدوات أخرى للواجهات الرسومية، لعل أشهرها صندوق WxPython الذي يغلف ودجات صندوق أدوات C++‎، وهذا الصندوق -أي WxPython- أكثر شيوعًا من صندوق أدوات Tkinter عمومًا بين صناديق الواجهات المرئية، حيث يوفر وظائف قياسيةً افتراضيًا أكثر من Tk، مثل التلميحات tooltips، وشرائط الحالة status bars وغيرها، أما في Tk فيجب إنشاؤها يدويًا، وسنستخدم wxPython لإعادة إنشاء مثال Hello World أعلاه.
</p>

<p>
	لكن المشكلة هنا هي أن wxPython ليس متاحًا بعد للإصدار الثالث من بايثون حتى الوقت الذي كتبنا فيه هذه الكلمات، مما يعني أننا سنعامل شيفرة الإصدار الثاني أدناه على أنها مجرد تدريب للقراءة لا غير، أو يمكن تثبيت الإصدار 2.7 من بايثون إذا أردنا التطبيق العملي، وتنزيل الحزمة من موقع <a href="http://www.wxpython.org/" rel="external nofollow">wxPython</a>، إذ لن ندخل كثيرًا في التفاصيل هنا، وعمومًا يعرِّف صندوق الأدوات إطار عمل يسمح لنا بإنشاء نوافذ وملئها بعناصر التحكم، وربط توابع بهذه المتحكمات، وبما أن هذا كائني التوجه فيجب استخدام التوابع وليس الدوال، ويبدو المثال كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7006_84" style=""><span class="kwd">import</span><span class="pln"> wx

</span><span class="com"># --- عرّف إطارًا مخصصًا. سيكون هو النافذة الأساسية ---</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">HelloFrame</span><span class="pun">(</span><span class="pln">wx</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> parent</span><span class="pun">,</span><span class="pln"> id</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">,</span><span class="pln"> pos</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">):</span><span class="pln">
        super</span><span class="pun">().</span><span class="pln">__init__</span><span class="pun">(</span><span class="pln">parent</span><span class="pun">,</span><span class="pln"> id</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">,</span><span class="pln"> pos</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">)</span><span class="pln">
       </span><span class="com"># we need a panel to get the right background</span><span class="pln">
        panel </span><span class="pun">=</span><span class="pln"> wx</span><span class="pun">.</span><span class="typ">Panel</span><span class="pun">(</span><span class="pln">self</span><span class="pun">)</span><span class="pln">

        </span><span class="com"># أنشئ ودجتي النص والزر</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">tHello </span><span class="pun">=</span><span class="pln"> wx</span><span class="pun">.</span><span class="typ">TextCtrl</span><span class="pun">(</span><span class="pln">panel</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hello world"</span><span class="pun">,</span><span class="pln"> pos</span><span class="pun">=(</span><span class="lit">3</span><span class="pun">,</span><span class="lit">3</span><span class="pun">),</span><span class="pln"> size</span><span class="pun">=(</span><span class="lit">185</span><span class="pun">,</span><span class="lit">22</span><span class="pun">))</span><span class="pln">
        bClear </span><span class="pun">=</span><span class="pln"> wx</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">panel</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Clear"</span><span class="pun">,</span><span class="pln"> pos</span><span class="pun">=(</span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">))</span><span class="pln">
        self</span><span class="pun">.</span><span class="typ">Bind</span><span class="pun">(</span><span class="pln">wx</span><span class="pun">.</span><span class="pln">EVT_BUTTON</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">.</span><span class="typ">OnClear</span><span class="pun">,</span><span class="pln"> bClear</span><span class="pun">)</span><span class="pln">
        bQuit </span><span class="pun">=</span><span class="pln"> wx</span><span class="pun">.</span><span class="typ">Button</span><span class="pun">(</span><span class="pln">panel</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Quit"</span><span class="pun">,</span><span class="pln"> pos</span><span class="pun">=(</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">))</span><span class="pln">
        self</span><span class="pun">.</span><span class="typ">Bind</span><span class="pun">(</span><span class="pln">wx</span><span class="pun">.</span><span class="pln">EVT_BUTTON</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">.</span><span class="typ">OnQuit</span><span class="pun">,</span><span class="pln"> bQuit</span><span class="pun">)</span><span class="pln">

   </span><span class="com"># هذه معالجات الأحداث الخاصة بنا</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> </span><span class="typ">OnClear</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> event</span><span class="pun">):</span><span class="pln">
       self</span><span class="pun">.</span><span class="pln">tHello</span><span class="pun">.</span><span class="typ">Clear</span><span class="pun">()</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> </span><span class="typ">OnQuit</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> event</span><span class="pun">):</span><span class="pln">
       self</span><span class="pun">.</span><span class="typ">Destroy</span><span class="pun">()</span><span class="pln">

</span><span class="com"># --- عرّف كائن التطبيق ---</span><span class="pln">
</span><span class="com"># يجب أن تعرّف صنف تطبيق wxPython لاحظ أن كل برامج  </span><span class="pln">
</span><span class="com"># wx.App مشتق من </span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">HelloApp</span><span class="pun">(</span><span class="pln">wx</span><span class="pun">.</span><span class="typ">App</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> </span><span class="typ">OnInit</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
       frame </span><span class="pun">=</span><span class="pln"> </span><span class="typ">HelloFrame</span><span class="pun">(</span><span class="kwd">None</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Hello"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="lit">200</span><span class="pun">,</span><span class="lit">50</span><span class="pun">),</span><span class="pln"> </span><span class="pun">(</span><span class="lit">200</span><span class="pun">,</span><span class="lit">90</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
       frame</span><span class="pun">.</span><span class="typ">Show</span><span class="pun">(</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
       self</span><span class="pun">.</span><span class="typ">SetTopWindow</span><span class="pun">(</span><span class="pln">frame</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">

</span><span class="com"># أنشئ نسخة وابدأ حلقة الحدث</span><span class="pln">
</span><span class="typ">HelloApp</span><span class="pun">().</span><span class="typ">MainLoop</span><span class="pun">()</span></pre>

<p style="text-align: center;">
	<img alt="wx-hello.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83348" data-unique="0kzy3mqgg" src="https://academy.hsoub.com/uploads/monthly_2021_11/wx-hello.png.fe764fb387bbbff43cc17f3616f1a837.png">
</p>

<p>
	نلاحظ استخدام اصطلاح التسمية <code>onXXXX</code> للتوابع التي يستدعيها إطار العمل، واستخدام ثوابت <code>EVT_XXX</code> لربط الأحداث بالودجات، وتوجد مجموعة كبيرة منها.
</p>

<p>
	يحتوي wxPython على ودجات كثيرة، أكثر من Tk، ويمكن بناء واجهات رسومية معقدة بها، لكنها للأسف تميل لاستخدام نظام موضعة مبني على الإحداثيات، وهذا متعب في العمل، لكن يمكننا استخدام نظام شبيه بمحزِّم Tk، مع أنه غير موثَّق جيدًا.
</p>

<p>
	وقد يكون من المهم ملاحظة أن هذا المثال ومثال Tkinter الشبيه به أعلاه يحتويان على نفس عدد الأسطر البرمجية تقريبًا، إذ يحتوي مثال Tk على 23 سطرًا، ومثال wxPython على 21، فإذا رغبنا في واجهة رسومية سريعة لأداة نصية فسيكون Tk كافيًا، أما إذا أردنا بناء تطبيقات كاملة تعمل على عدة منصات تشغيل فينبغي استخدام wxPython.
</p>

<p>
	ومن صناديق الأدوات الأخرى MFC و‎.NET، ولا ننسى Curses التي هي واجهة رسومية مبنية على نصوص، ويمكن تطبيق كثير من الدروس التي تعلمناها مع Tkinter على كل صناديق الأدوات هذه، لكن لكل منها مزاياه وعيوبه، فاختر واحدًا وتعرف عليه واستمتع ببرمجة الواجهات الرسومية.
</p>

<p>
	أخيرًا نشير إلى أن العديد من صناديق الأدوات لها أدوات بناء رسومية، مثل Blackadder لـ Qt ، وGlade لــ GTK ، وكذلك يحتوي wxPython على بانٍ رسومي هو <a href="http://boa-constructor.sourceforge.net/" rel="external nofollow">Boa Constructor</a> رغم أنه لا زال في مرحلة الإصدار Alpha مما يعني أنه غير مستقر، كما يوجد بانٍ رسومي لصندوق Tk يسمى <a href="http://spectcl.sourceforge.net/" rel="external nofollow">GUI Builder</a> كان مخصصًا ابتداءً لبناء واجهات Tcl/Tk، لكنه يستطيع توليد شيفرات في عدة لغات بما فيها بايثون.
</p>

<p>
	توجد عدة كتب أخرى لاستخدام Tcl/Tk وعدة كتب أخرى من بايثون لديها فصول عن Tk، وسنعود إليه في مقال قادم، حين نشرح طريقة تغليف برنامج وضع باتش batch mode في واجهة رسومية لتحسين الاستخدام.
</p>

<h2>
	خاتمة
</h2>

<p>
	نرجو في نهاية هذا المقال أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		تُعرف عناصر تحكم الواجهات الرسومية بالودجات.
	</li>
	<li>
		تُجمَّع الودجات في هرمية احتوائية.
	</li>
	<li>
		توفر صناديق أدوات الواجهات الرسومية مجموعات مختلفةً من الودجات، رغم وجود مجموعة أساسية افتراضية فيها جميعًا.
	</li>
	<li>
		تسمح الإطارات بجمع الودجات المتشابهة، وتشكيل أساس لمكونات واجهة رسومية قابلة للاستخدام.
	</li>
	<li>
		ترتبط دوال معالجة الأحداث أو التوابع بالودجات من خلال ربط أسمائها بخاصية <code>command</code> الخاصة بالودجات.
	</li>
	<li>
		تستطيع البرمجة كائنية التوجه تبسيط برمجة الواجهات الرسومية كثيرًا بإنشاء كائنات تتوافق مع مجموعات الودجات، وتوابع تتوافق مع الأحداث.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutgui.htm" rel="external nofollow">للفصل التاسع عشر: GUI Programming with Tkinter</a> من كتاب Learn To Program لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF%D9%8A%D8%A9-recursion-r1387/" rel="">مفهوم التعاودية Recursion</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AD%D8%AF%D8%AB%D9%8A%D8%A9-event-driven-programming-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D9%82%D8%A9-%D8%A8%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-r1376/" rel="">البرمجة الحدثية Event Driven Programming المساقة بالأحداث</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-programming-%D9%81%D9%8A-php-r316/" rel="">البرمجة كائنية التوجه (Object Oriented Programming) في PHP</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/c-sharp/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-programming-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B3%D9%8A-%D8%B4%D8%A7%D8%B1%D8%A8-c-r328/" rel="">البرمجة كائنية التوجه (Object Oriented Programming) في لغة سي شارب #C</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/c-sharp/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B3%D9%8A-%D8%B4%D8%A7%D8%B1%D8%A8-c-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%84%D8%AB-r338/" rel="">تطبيق البرمجة كائنية التوجه في لغة سي شارب #C - الجزء الثالث</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1374/" rel="">التعابير النمطية في البرمجة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1378</guid><pubDate>Thu, 25 Nov 2021 16:06:00 +0000</pubDate></item><item><title>&#x634;&#x631;&#x62D; &#x645;&#x644;&#x641; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646; manifest &#x644;&#x62A;&#x637;&#x628;&#x64A;&#x642; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x627;&#x644;&#x62A;&#x642;&#x62F;&#x645;&#x64A; PWA</title><link>https://academy.hsoub.com/programming/general/%D8%B4%D8%B1%D8%AD-%D9%85%D9%84%D9%81-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86-manifest-%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1385/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/61a15b499051b_--------------Android-Apps-Progressive-Web-Apps-Web-App-Manifest.png.ef73e95c63b86d9a5c2f264c808e2896.png" /></p>

<p>
	يُحدّد ملف بيان تطبيق الويب web app manifest مظهر وسلوك صفحات الويب التقدميّة PWA كما يجب أن يعرضها المتصفح بعد تثبيت التطبيق على سطح مكتب أو جوّال المستخدم، وهو عبارة عن ملف مكتوب ب<a href="https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-json-%D9%81%D9%8A-javascript-r548/" rel="">صيغة جيسون JSON</a>.
</p>

<p>
	تدّعم معظم المتصفحات ملف بيان تطبيق الويب مثل Chrome و Edge و Firefox و UC Browser و Opera و Samsung أما المتصفح Safari فيوفر دعمًا جزئيًا فقط.
</p>

<h2>
	إنشاء ملف بيان تطبيق الويب
</h2>

<p>
	يُمكن تسمية ملف بيان الويب بأي اسم، إلا أن الشائع تسميته بـ <code>manifest.json</code> ووضعه في الجذر (المجلّد الأعلى لموقع الويب). تنص التوصيات القياسية على وجوب استخدام اللاحقة <code>webmanifest</code> لاسم الملف، إلا أن اللاحقة <code><a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">json</a></code> يُمكن أن تُستخدم أيضًا لاسيما أنها مألوفة لجميع المطورين.
</p>

<p>
	نٌبين فيما يلي مثالًا عن محتوى بيان الويب:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4492_6" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"short_name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Weather"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Weather: Do I need an umbrella?"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"icons"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"src"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/images/icons-192.png"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"image/png"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"sizes"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"192x192"</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"src"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/images/icons-512.png"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"image/png"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"sizes"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"512x512"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="str">"start_url"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/?source=pwa"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"background_color"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#3367D6"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"display"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"standalone"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"scope"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"theme_color"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#3367D6"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"shortcuts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"How's weather today?"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"short_name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Today"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"description"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"View weather information for today"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"url"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/today?source=pwa"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"icons"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[{</span><span class="pln"> </span><span class="str">"src"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/images/today.png"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"sizes"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"192x192"</span><span class="pln"> </span><span class="pun">}]</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"How's weather tomorrow?"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"short_name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Tomorrow"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"description"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"View weather information for tomorrow"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"url"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/tomorrow?source=pwa"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"icons"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[{</span><span class="pln"> </span><span class="str">"src"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/images/tomorrow.png"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"sizes"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"192x192"</span><span class="pln"> </span><span class="pun">}]</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="str">"description"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Weather forecast information"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"screenshots"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"src"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/images/screenshot1.png"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"image/png"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"sizes"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"540x720"</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"src"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/images/screenshot2.jpg"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"image/jpg"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"sizes"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"540x720"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	أهم خصائص ملف بيان الويب
</h2>

<p>
	سنشرح أهم الخصائص التي يحويها ملف بيان الويب والتي عليك ضبطها لتطبيقك.
</p>

<h3>
	الاسم القصير short_name و/أو الاسم name
</h3>

<p>
	يجب تضمين، على الأقل، إحدى الخاصيتين: الاسم القصير <code>short_name</code> أو الاسم <code>name</code>. وفي حال توفر كلتيهما يُستخدم الاسم القصير في شاشة المستخدم الرئيسية home screen وفي مُشغّل التطبيق launcher وفي أي مكان لا تتوفر فيه المساحة الكافية لعرض الاسم كاملًا؛ أما الاسم فيُستخدم عند تثبيت التطبيق.
</p>

<h3>
	الأيقونات icons
</h3>

<p>
	يُمكن تحديد مجموعة من الأيقونات ليعرضها المتصفح على الشاشة الرئيسية home screen وعلى مُشغّل التطبيق launcher وعلى مُبدّل المهام task switcher وعلى شاشة البداية splash screen وغيرها، بعد أن يقوم المستخدم بتثبيت صفحات الويب التقدميّة.
</p>

<p>
	تكون قيمة خاصية الأيقونات icons مصفوفة من العناصر، يحوي كل عنصر منها خاصية المصدر <code>src</code> وخاصية القياسات <code>sizes</code> وخاصية نوع الصورة <code>type</code>. يجب إضافة <code>"purpose": "any maskable"</code> إلى خاصية الأيقونة <code>icon</code> في حال الحاجة لاستخدام الأيقونات المقنّعة maskable icons والتي تُدعى أيضًا بالأيقونات المتكيفة في <a href="https://academy.hsoub.com/programming/android/" rel="">أندرويد</a>.
</p>

<p>
	يتطلب استخدام المتصفح توفير أيقونات بقياس 192x192 بكسل وبقياس 512×512 بكسل على الأقل. إذا توفر هذان القياسان فقط سيقوم المتصفح Chrome بتحجيم الأيقونات لتتناسب مع الجهاز المستخدم. في حال أردت الوصول لكمال الإظهار pixel-perfection فعليك توفير أيقونات بقياسات من مضاعفات 48dp.
</p>

<h3>
	عنوان بدء التطبيق start_url
</h3>

<p>
	توجه الخاصية المطلوبة <code>start_url</code> المتصفح إلى عنوان أو رابط الصفحة التي يجب أن يبدأ منها التطبيق عند تشغيله، وتمنع التطبيق من البدء من الصفحة التي يتصفحها المستخدم عند إضافة التطبيق لشاشته الرئيسية.
</p>

<p>
	توجه الخاصية <code>start_url</code> المستخدم مباشرًة إلى التطبيق عوضًا عن <a href="https://academy.hsoub.com/marketing/inbound-marketing/%d8%aa%d8%b9%d8%b1%d9%91%d9%81-%d8%b9%d9%84%d9%89-%d8%b5%d9%81%d8%ad%d8%a7%d8%aa-%d8%a7%d9%84%d9%87%d8%a8%d9%88%d8%b7-landing-pages-%d9%88%d9%85%d9%83%d9%88%d9%91%d9%86%d8%a7%d8%aa%d9%87%d8%a7-r23/" rel="">صفحة الهبوط landing page</a> لمنتج ما. يجب دومًا التفكير بما يريد المستخدم أن يقوم به حال فتح التطبيق ومن ثم وضعه في المكان المناسب.
</p>

<h3>
	لون الخلفية backgroud_color
</h3>

<p>
	تُستخدم خاصية <a href="https://academy.hsoub.com/programming/css/%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A7%D8%AA-backgrounds-%D9%81%D9%8A-css-r1055/" rel="">لون الخلفية</a> لشاشة البداية splash screen عند تشغيل التطبيق لأول مرة على الجوّال.
</p>

<h3>
	العرض display
</h3>

<p>
	يُمكن تخصيص <a href="https://academy.hsoub.com/learn/front-end-web-development/" rel="">واجهات المستخدم</a> عند تشغيل التطبيق على المتصفح مثل إخفاء شريط العنوان للمتصفح Chrome، كما يُمكن أيضًا التشغيل بوضعية ملء الشاشة لحالة الألعاب مثلًا. يُبين الجدول التالي بعض قيم هذه الخاصية:
</p>

<h4>
	ملء الشاشة fullscreen
</h4>

<p>
	فتح تطبيق الويب دون أي واجهة متصفح متاحة للمستخدم وشغل مساحة العرض المتاحة بالكامل.
</p>

<h4>
	مستقل standalone
</h4>

<p>
	فتح تطبيق الويب ليبدو وكأنه تطبيق مستقل. يعمل التطبيق في نافذته الخاصة المنفصلة عن المتصفح والذي تُخفى عناصره القياسية مثل شريط العناوين.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83461" href="https://academy.hsoub.com/uploads/monthly_2021_11/001standalone.png.7e57e0da035d5d1b6266f8062335dca9.png" rel=""><img alt="001standalone.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83461" data-unique="47v999vm9" src="https://academy.hsoub.com/uploads/monthly_2021_11/001standalone.thumb.png.a91ff4bb85463e19cee826e0adb3d1d6.png" style="width: 700px; height: auto;"></a>
</p>

<h4>
	الحد الأدنى من الواجهة minimal-ui
</h4>

<p>
	يشبه هذا الوضع الوضع المستقل السابق إلا أنه يوفر للمستخدم مجموعة صغيرة من عناصر التنقل (مثل الرجوع back وإعادة التحميل reload).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83462" href="https://academy.hsoub.com/uploads/monthly_2021_11/002minimal.png.f3492eb616a09c3b2b4b637473460169.png" rel=""><img alt="002minimal.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83462" data-unique="3vznveohi" src="https://academy.hsoub.com/uploads/monthly_2021_11/002minimal.thumb.png.c93819f5ae8b6812dde704de054646cf.png" style="width: 700px; height: auto;"></a>
</p>

<h4>
	متصفح browser
</h4>

<p>
	يتيح هذا الوضع <a href="https://academy.hsoub.com/design/user-experience/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-%d8%aa%d8%ac%d8%b1%d8%a8%d8%a9-%d8%a7%d9%84%d9%85%d8%b3%d8%aa%d8%ae%d8%af%d9%85-user-experience-r149/" rel="">تجربة استخدام</a> متصفح تمامًا.
</p>

<h3>
	تجاوز العرض display_override
</h3>

<p>
	تُحدّد خاصية العرض display في ملف بيان تطبيق الويب وضع العرض كما هو موضح أعلاه. ليس مطلوبًا من جميع المتصفحات أن توفر كل أوضاع العرض السابقة إلا أن عليها أن تدعم السلسلة الاحتياطية وفق المواصفات المحدّدة <a href="https://w3c.github.io/manifest/#dfn-fallback-display-mode" rel="external nofollow">spec-defined fallback chain</a> أي التسلسل: ("ملء الشاشة" <code>fullscreen</code>← "مستقل" <code>standalone</code>← "الحد الأدنى من الواجهة" <code>minimal-ui</code>← "المتصفح "<code>browser</code>) والتي تُحتّم على المتصفح في حال عدم إمكانية دعمه لوضع معين أن يوفر الوضع التالي له في السلسلة. يُمكن أن يؤدي هذا السلوك غير المرن لبعض المشاكل في حالات نادرة جدًا كعدم استطاعة المطور أن يطلب وضع الحد الأدنى <code>minimal-ui</code> دون العودة بشكل قسري إلى وضع المتصفح <code>browser</code> وذلك إذا كان وضع الحد الأدنى غير مدعوم أصلًا. يُمكن أن يؤدي هذا السلوك أيضًا إلى مشكلة عدم القدرة على تضمين أوضاع عرض جديدة متوافقة مع الإصدارات السابقة، مثلًا: لا يُمكن التوافق مع وضع التبويب tabbed application mode غير الموجود في السلسلة الاحتياطية.
</p>

<p>
	تحل خاصية "تجاوز العرض" <code>display_override</code> جميع هذه المشاكل حيث يعتمد المتصفح هذه الخاصية قبل خاصية العرض <code>display</code>. توضع قيمة هذه الخاصية على شكل تسلسل مرتب من السلاسل النصية وبحيث يُطبّق أول عرض منها مدعوم من قبل المتصفح، وفي حال عدم وجود أي عرض مدعوم يعود المتصفح إلى خاصية العرض <code>display</code>.
</p>

<p>
	تكون السلسلة الاحتياطية في المثال التالي كما يلي (مع ملاحظة أن تفاصيل الوضع <code>window-control-overlay</code> خارج إطار هذه المقالة):
</p>

<ol>
<li>
		وضع تراكب عناصر النافذة <code>window-control-overlay</code> (أولًا ننظر إلى الخاصية <code>display_override</code>).
	</li>
	<li>
		وضع الحد الأدنى من الواجهة <code>minimal-ui.</code>
	</li>
	<li>
		الوضع المستقل <code>standalone</code> (إذا استُنفذت كل الأوضاع في <code>display_override</code> نعود إلى الخاصية <code>display</code>).
	</li>
	<li>
		وضع الحد الأدنى من الواجهة <code>minimal-ui</code> (نعود في النهاية للسلسلة الاحتياطية للخاصية <code>display</code>).
	</li>
	<li>
		وضع المتصفح <code>browser.</code>
	</li>
</ol>
<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4492_10" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"display_override"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"window-control-overlay"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"minimal-ui"</span><span class="pun">],</span><span class="pln">
  </span><span class="str">"display"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"standalone"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا يقوم المتصفح باستخدام الخاصية <code>display_override</code> ما لم تكن الخاصية <code>display</code> موجودة.
</p>

<h3>
	النطاق scope
</h3>

<p>
	يُحدّد النطاق <code>scope</code> عناوين URLs الصفحات التي يعتبرها المتصفح واقعة ضمن التطبيق وتُستخدم لمعرفة وقت مغادرة المستخدم لهذا التطبيق. يتحكم النطاق ببنية هذه المحدِّدات والتي تتضمن جميع نقاط الدخول والخروج للتطبيق. بالطبع، يجب أن يكون <a href="https://academy.hsoub.com/programming/php/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-url-%D9%81%D9%8A-php-r1128/" rel="">رابط URL</a> للبداية <code>start_url</code> ضمن محدِّدات النطاق هذه.
</p>

<p>
	تحذير: في حال نقر المستخدم لأحد روابط التطبيق الذي يُخرجه من النطاق، فسيُفتح الرابط للعرض ضمن نافذة صفحات الويب التقدميّة الحالية. إذا كان المطلوب فتح الرابط ضمن تبويب جديد للمتصفح فيجب إضافة <code>"target="_blank</code> لوسم الرابط <a href="https://wiki.hsoub.com/HTML/a" rel="external"><code>&lt;a&gt;</code></a>. تُفتح مثل هذه الروابط في أندرويد بتبويب مخصص للمتصفح <a href="https://developer.chrome.com/multidevice/android/customtabs" rel="external nofollow">Chrome Custom Tab</a>.
</p>

<p>
	يجب أخذ الملاحظات التالية حول النطاق <code>scope</code> بعين الاعتبار:
</p>

<ul>
<li>
		في حال عدم تحديد النطاق <code>scope</code> في ملف بيان الويب، فسيكون النطاق الافتراضي هو المجلد الذي يحوي ملف بيان الويب.
	</li>
	<li>
		يُمكن أن تُحدّد قيمة النطاق مسارًا نسبيًا (<code>/..</code>) أو أي مسار لمستوى أعلى (<code>/</code>) مما يسمح بتغطية أكبر للتنقلات في التطبيق.
	</li>
	<li>
		يجب أن يكون رابط URL للبداية <code>start_url</code> ضمن محدِّدات النطاق <code>scope</code>.
	</li>
	<li>
		يكون رابط URL للبداية <code>start_url</code> نسبي للمسار المُعرّف في النطاق <code>scope</code>.
	</li>
	<li>
		إذا ابتدأ <code>start_url</code> بالمحرف <code>/</code> فسيكون دومًا الجذر للبداية.
	</li>
</ul>
<h3>
	لون النمط theme_color
</h3>

<p>
	يُحدّد لون النمط <code>theme_color</code> لون شريط الأدوات، وقد يُستخدم في عرض التطبيق ضمن محوّل المهام task switchers. يجب أن يُطابق لون النمط اللون المحدّد في السمة <code>meta</code> في ترويسة الصفحة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83463" href="https://academy.hsoub.com/uploads/monthly_2021_11/003themecolor.png.714c59a7a4de51f68dbe561bc7f16e4d.png" rel=""><img alt="003themecolor.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83463" data-unique="0iax5q4tx" src="https://academy.hsoub.com/uploads/monthly_2021_11/003themecolor.thumb.png.24a6457285a5e458e6d6b6e53f132fa8.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	بدءًا من نسخ المتصفحات Chromium 93 و Safari 15، يُمكن ضبط لون النمط باستخدام استعلام وسائط media query للخاصية <code>media</code> في السمة <code>meta</code> وباعتماد أول لون مطابق. يُمكن مثلًا تحديد لون ما للوضع الساطع وآخر للوضع الداكن. لايُمكن، حتى وقت كتابة هذه المقالة، تحديد هذا السلوك في ملف بيان الويب (يُمكنك العودة لمناقشة هذه المشكلة في <a href="https://github.com/w3c/manifest/issues/975" rel="external nofollow">w3c/manifest#975 GitHub issue</a>)
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4492_15" style="">
<span class="pun">&lt;</span><span class="pln">meta name</span><span class="pun">=</span><span class="str">"theme-color"</span><span class="pln"> media</span><span class="pun">=</span><span class="str">"(prefers-color-scheme: light)"</span><span class="pln"> content</span><span class="pun">=</span><span class="str">"white"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">meta name</span><span class="pun">=</span><span class="str">"theme-color"</span><span class="pln"> media</span><span class="pun">=</span><span class="str">"(prefers-color-scheme: dark)"</span><span class="pln"> content</span><span class="pun">=</span><span class="str">"black"</span><span class="pun">&gt;</span></pre>

<h3>
	الاختصارات shortcuts
</h3>

<p>
	تسمح هذه الخاصية بتعريف مجموعة من الاختصارات للمهام الأساسية للتطبيق وهي عبارة عن مصفوفة يكون كل عنصر فيها من النوع "كائن اختصار" app shortcut. يُعرّف الكائن باستخدام قاموس من الأزواج مفتاح/قيمة ويجب أن يحوي على الأقل المفتاح <code>name</code> والمفتاح <code>url</code>.
</p>

<h3>
	الوصف description
</h3>

<p>
	تشرح هذه الخاصية الهدف من التطبيق.
</p>

<h3>
	اللقطات screenshots
</h3>

<p>
	تكون قيمة هذه الخاصية مصفوفة من كائنات الصور لبعض لقطات سيناريوهات الاستخدام الشائعة للتطبيق. يجب أن يتضمن كل كائن خاصية المصدر <code>src</code> والقياسات <code>sizes</code> و النوع <code>type</code>.
</p>

<p>
	يجب أن تحترم الصورة المعايير التالية في المتصفح Chrome:
</p>

<ul>
<li>
		لا يقل قياس كل من العرض والارتفاع عن 320 بكسل ولا يزيد عن 3840 بكسل.
	</li>
	<li>
		لا يزيد البعد الأكبر عن 2.3 ضعف البعد الأقل.
	</li>
	<li>
		لجميع اللقطات نفس نسبة الطول إلى العرض aspect ratio.
	</li>
	<li>
		تنسيقات الصور JPEG أو PNG فقط.
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong> تُستخدم الخاصيتان <code>description</code> و <code>screenshots</code> حاليًا في المتصفح Chrome لتطبيقات أندرويد عندما يطلب المستخدم تثبيت التطبيق. سيتم تفعيل الراية <code>about://flags/#mobile-pwa-install-use-bottom-sheet</code> في النسخة 90 من Chrome.
		</p>
	</div>
</blockquote>

<h2>
	إضافة ملف بيان الويب إلى صفحات التطبيق
</h2>

<p>
	يُمكن، بعد الانتهاء من إنشاء ملف بيان الويب، إضافة الوسم <a href="https://wiki.hsoub.com/HTML/link" rel="external"><code>&lt;link&gt;</code></a> لجميع صفحات الويب التقدميّة للتطبيق. مثلًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4492_17" style="">
<span class="pun">&lt;</span><span class="pln">link rel</span><span class="pun">=</span><span class="str">"manifest"</span><span class="pln"> href</span><span class="pun">=</span><span class="str">"/manifest.json"</span><span class="pun">&gt;</span></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong> لا يحتاج طلب بيان الويب إلى اعتماديات credentials، وفي حال الحاجة إليها يُمكن تضمين <code>"crossorigin="use-credentials</code> في سمات ملف البيان.
		</p>
	</div>
</blockquote>

<h2>
	اختبار ملف البيان
</h2>

<p>
	يُمكن استخدام جزء البيان <strong>Manifest</strong> في لوحة التطبيق <strong>Application</strong> من أدوات التطوير DevTools في المتصفح Chrome للتحقق من إعداد ملف البيان بشكل صحيح.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83460" href="https://academy.hsoub.com/uploads/monthly_2021_11/004DevTools.png.a4bff0e323d2c74e19bc544d2095cc16.png" rel=""><img alt="004DevTools.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83460" data-unique="8u5yuvmy7" src="https://academy.hsoub.com/uploads/monthly_2021_11/004DevTools.thumb.png.97a3bdaf368765681e61dc652754c790.png"></a>
</p>

<p>
	يسمح جزء البيان Manifest بمعاينة معظم خصائص ملف البيان بشكل مرئي، ويُسهّل التحقق من تحميل جميع الصور بشكل صحيح.
</p>

<h2>
	شاشة البدء على الجوال
</h2>

<p>
	قد يستغرق تشغيل التطبيق، لا سيما التشغيل الأول، بعض الوقت. يعرض المتصفح شاشة البداية Splash screen حتى ظهور الواجهة الأولى للتطبيق منعًا من إظهار شاشة بيضاء قد توحي للمستخدم بوجود مشكلة ما في التطبيق.
</p>

<p>
	يقوم المتصفح بإنشاء شاشة البداية آليًا معتمدًا على خصائص ملف البيان ولا سيما:
</p>

<ul>
<li>
		الاسم <code>name.</code>
	</li>
	<li>
		لون الخلفية <code>background_color.</code>
	</li>
	<li>
		الأيقونات <code>icons.</code>
	</li>
</ul>
<p>
	يجب أن يكون لون الخلفية <code>background_color</code> نفس لون صفحة التحميل لتوفير انتقال سلس من شاشة البداية إلى واجهة التطبيق الأولى.
</p>

<p>
	يختار المتصفح Chrome الأيقونة الأنسب لدقة الجهاز. يُمكن أن يكون توفير أيقونات بقياس 193 بكسل و512 بكسل كافيًا في معظم الحالات، إلا أن توفير أيقونات إضافية بقياسات مختلفة يوصل لكمال الإظهار بشكل عام.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://web.dev/add-manifest/" rel="external nofollow">Add a web app manifest</a> للمؤلفين: Pete LePage و François Beaufort و Thomas Steiner.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">مدخل إلى تطبيقات الويب التقدمية PWA</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/design/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-%D9%88%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D8%AC%D8%A8-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D9%85%D8%B5%D9%85%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A7%D9%87%D8%AA%D9%85%D8%A7%D9%85-%D8%A8%D9%87%D8%A7%D8%9F-r450/" rel="">ما هي تطبيقات الويب التقدمية ولماذا يجب على المصممين الاهتمام بها؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%B5%D9%8A%D8%BA%D8%A9-json-%D9%88%D8%AA%D9%88%D8%A7%D8%A8%D8%B9%D9%87%D8%A7-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r826/" rel="">صيغة JSON وتوابعها في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/%D8%B5%D9%8A%D8%BA%D8%A9-json-%D9%88xml-%D9%81%D9%8A-php-r1078/" rel="">صيغة JSON وXML في PHP</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1385</guid><pubDate>Wed, 24 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x627;&#x644;&#x62D;&#x62F;&#x62B;&#x64A;&#x629; Event Driven Programming  &#x627;&#x644;&#x645;&#x633;&#x627;&#x642;&#x629; &#x628;&#x627;&#x644;&#x623;&#x62D;&#x62F;&#x627;&#x62B;</title><link>https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AD%D8%AF%D8%AB%D9%8A%D8%A9-event-driven-programming-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D9%82%D8%A9-%D8%A8%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-r1376/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/619d4821ae85d_--Event-Driven-Programming.png.79f85a755a415cdcd886c22d706fe742.png" /></p>
<p>
	درسنا حتى الآن البرامج جزئية التوجه batch oriented programs، والتي تستدعى بإحدى طريقتين: جزئية التوجه batch oriented، حيث تبدأ البرامج بالعمل ثم تنفذ شيئًا ما ثم تتوقف، أو مدفوعة بالأحداث أو حدثية التوجه event driven، أي تبدأ البرامج وتنتظر وقوع أحداث بعينها؛ ولا تتوقف إلا حين يأمرها حدث آخر بالتوقف.
</p>

<p>
	كيف ننشئ برنامجًا مقودًا بالأحداث؟ سنفعل ذلك بطريقتين، حيث سنحاكي أولًا بيئةً حدثيةً، ثم سننشئ برنامجًا رسوميًا بسيطًا يستخدم <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">نظام التشغيل</a> والبيئة لتوليد أحداث.
</p>

<p>
	وسنغطي في هذا المقال النقاط التالية:
</p>

<ul>
	<li>
		أوجه اختلاف البرامج المدفوعة بالأحداث عن البرامج جزئية التوجه.
	</li>
	<li>
		كيفية كتابة <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1306/" rel="">حلقة حدث تكرارية</a>.
	</li>
	<li>
		كيفية استخدام إطار عمل أحداث مثل Tkinter.
	</li>
</ul>

<h2>
	محاكاة حلقة أحداث تكرارية
</h2>

<p>
	يحتوي البرنامج المدفوع بالأحداث أو البرنامج الحدثي event driven program على حلقة تلتقط الأحداث المستَلمة وتعالجها، وقد تولد بيئة التشغيل الأحداث -كما يحدث في جميع البرامج الرسومية تقريبًا-، أو يبحث البرنامج عن الأحداث -كما يحدث في أنظمة التحكم المدمجة التي في الكاميرات وغيرها-، وسنكتب برنامجًا يبحث عن نوع واحد من الأحداث، وهو <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AD%D8%B5%D9%88%D9%84-%D8%B9%D9%84%D9%89-%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D9%85%D9%86-%D9%84%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D9%85%D9%81%D8%A7%D8%AA%D9%8A%D8%AD-%D9%88%D8%A5%D8%AC%D8%B1%D8%A7%D8%A1-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%B3%D8%A7%D8%A8%D9%8A%D8%A9-%D9%81%D9%8A-%D8%B3%D9%83%D8%B1%D8%A8%D8%AA%D8%A7%D8%AA-%D8%A7%D9%84%D8%B5%D8%AF%D9%81%D8%A9-shell-scripts-r266/" rel="">مدخلات لوحة المفاتيح</a>، ويعالج النتائج إلى أن يستلم حدث خروج quit، والذي سيكون حالتنا مفتاح المسافة space على لوحة المفاتيح، وسنعالج الأحداث المدخلة بطريقة سهلة، إذ سنطبع <a href="https://wiki.hsoub.com/Arduino/asciichart" rel="external">ترميز آسكي ASCII</a> الخاص بالمفتاح الذي ضغطه المستخدم، وسنستخدم بايثون لأنها تحوي دالة <code>getch()‎</code> سهلة الاستخدام، وسنقرأ المفاتيح مفتاحًا تلو الآخر، وتأتي هذه الدالة في صورتين وفقًا لنظام التشغيل الذي نستخدمه، فنجدها في <a href="https://academy.hsoub.com/devops/linux/%d8%a3%d9%84%d9%81-%d8%a8%d8%a7%d8%a1-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-%d8%a7%d9%84%d8%aa%d8%b9%d8%a7%d9%85%d9%84-%d9%85%d8%b9-%d9%84%d9%8a%d9%86%d9%83%d8%b3-r61/" rel="">لينكس</a> في وحدة <code>curses</code>، أما في ويندوز فستكون في وحدة <code>msvcrt</code>، وسنستخدم نسخة ويندوز أولًا ثم نناقش خيار لينكس بالتفصيل، ويجب أن نشغل هذه البرامج من سطر أوامر النظام، لأن بيئات التطوير -مثل IDLE- ستلتقط ضربات لوحة المفاتيح التقاطًا مختلفًا.
</p>

<p>
	وسنطبق دوال معالجة الأحداث أولًا، والتي تُستدعى عند التقاط ضغطة أحد المفاتيح، ثم متن البرنامج الرئيسي الذي يبدأ حلقة جمع الأحداث؛ ويستدعي دالة معالجة الحدث المناسبة عند التقاط حدث صالح.
</p>

<h3>
	تطبيق المثال في ويندوز
</h3>

<p>
	إليك التطبيق التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1276_14" style=""><span class="kwd">import</span><span class="pln"> msvcrt
</span><span class="kwd">import</span><span class="pln"> sys

</span><span class="com"># معالجات الأحداث أولًا</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> doKeyEvent</span><span class="pun">(</span><span class="pln">key</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> key </span><span class="pun">==</span><span class="pln"> </span><span class="str">'\x00'</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> key </span><span class="pun">==</span><span class="pln"> </span><span class="str">'\xe0'</span><span class="pun">:</span><span class="pln">
       key </span><span class="pun">=</span><span class="pln"> msvcrt</span><span class="pun">.</span><span class="pln">getch</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">print</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> ord</span><span class="pun">(</span><span class="pln">key</span><span class="pun">),</span><span class="pln"> </span><span class="str">' '</span><span class="pun">,</span><span class="pln"> end</span><span class="pun">=</span><span class="str">''</span><span class="pun">)</span><span class="pln">
    sys</span><span class="pun">.</span><span class="pln">stdout</span><span class="pun">.</span><span class="pln">flush</span><span class="pun">()</span><span class="pln"> </span><span class="com"># make sure it appears on screen</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> doQuit</span><span class="pun">(</span><span class="pln">key</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">()</span><span class="pln"> </span><span class="com"># أدخل سطرًا جديدًا</span><span class="pln">
    </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">SystemExit</span><span class="pln">

</span><span class="com"># أخل مساحة على الشاشة أولًا</span><span class="pln">
lines </span><span class="pun">=</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> 
</span><span class="kwd">for</span><span class="pln"> n </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">lines</span><span class="pun">):</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">()</span><span class="pln">

</span><span class="com"># والآن حلقة الحدث الأساسية</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
    ky </span><span class="pun">=</span><span class="pln"> msvcrt</span><span class="pun">.</span><span class="pln">getch</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">str</span><span class="pun">(</span><span class="pln">ky</span><span class="pun">))</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
        </span><span class="com"># we have a real event</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">ky</span><span class="pun">):</span><span class="pln">
            doQuit</span><span class="pun">(</span><span class="pln">ky</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> 
            doKeyEvent</span><span class="pun">(</span><span class="pln">ky</span><span class="pun">)</span></pre>

<p>
	لاحظ أن ما نفعله مع الأحداث لا علاقة له بالمتن الرئيسي، الذي يجمع الأحداث ويمررها إلى معالجات الأحداث وحسب، وهذه الاستقلالية في التقاط الأحداث معالجتها هي الميزة الأساسية في البرمجة الحدثية.
</p>

<p>
	كما نلاحظ أن <code>getch()‎</code> تعيد بايتات، لذا نحتاج إلى تحويلها إلى سلسلة نصية، وإلى استخدام اختبار <code>in</code> للتحقق متى يمكن الخروج بما أن السلسلة الناتجة لن تكون حرفًا.
</p>

<p>
	وفي الحالة التي لا يكون فيها المفتاح محرف آسكي، كأن يكون مفتاحًا وظيفيًا مثلًا، وهي المفاتيح التي تحمل حرف F في أولها أعلى لوحة المفاتيح، فسنحتاج إلى جلب محرف ثانٍ من لوحة المفاتيح، لأن هذه المفاتيح الخاصة تولد أزواجًا من البايتات، أما <code>getch()‎</code> فلا تجلب إلى بايتًا واحدًا في كل مرة، وتكون القيمة المهمة التي نريدها هي البايت الثاني فعليًا.
</p>

<h3>
	تطبيق المثال في لينكس وماك
</h3>

<p>
	لا يستطيع المبرمجون الذين يستخدمون <a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%A7-%D9%87%D9%88-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%8A%D9%86%D9%83%D8%B3%D8%9F-r451/" rel="">أنظمة تشغيل لينكس</a> وماك استخدام مكتبة <code>msvcrt</code>، لذا يستخدمون وحدةً أخرى تسمى <code>curses</code>، وتكون الشيفرة الناتجة شبيهةً بشيفرة ويندوز، مع بعض التعديلات التي يجب إجراؤها، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1276_18" style=""><span class="kwd">import</span><span class="pln"> curses as c

def doKeyEvent</span><span class="pun">(</span><span class="pln">key</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> key </span><span class="pun">==</span><span class="pln"> </span><span class="str">'\x00'</span><span class="pln"> or key </span><span class="pun">==</span><span class="pln"> </span><span class="str">'\xe0'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> non ASCII key
       key </span><span class="pun">=</span><span class="pln"> screen</span><span class="pun">.</span><span class="pln">getch</span><span class="pun">()</span><span class="pln">     </span><span class="pun">#</span><span class="pln"> fetch second character
    screen</span><span class="pun">.</span><span class="pln">addstr</span><span class="pun">(</span><span class="pln">str</span><span class="pun">(</span><span class="pln">key</span><span class="pun">)+</span><span class="str">' '</span><span class="pun">)</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> uses global screen variable

def doQuitEvent</span><span class="pun">(</span><span class="pln">key</span><span class="pun">):</span><span class="pln">
    c</span><span class="pun">.</span><span class="pln">resetty</span><span class="pun">()</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> terminal settings
    c</span><span class="pun">.</span><span class="pln">endwin</span><span class="pun">()</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> end curses session
    raise </span><span class="typ">SystemExit</span><span class="pln">


</span><span class="pun">#</span><span class="pln"> </span><span class="pun">امسح</span><span class="pln"> </span><span class="pun">الشاشة</span><span class="pln"> </span><span class="pun">واحفظ</span><span class="pln"> </span><span class="pun">الإعدادات</span><span class="pln"> </span><span class="pun">الحالية</span><span class="pln">
</span><span class="pun">#</span><span class="pln"> </span><span class="pun">وأوقف</span><span class="pln"> </span><span class="pun">الطباعة</span><span class="pln"> </span><span class="pun">الآلية</span><span class="pln"> </span><span class="pun">للمحارف</span><span class="pln"> </span><span class="pun">على</span><span class="pln"> </span><span class="pun">الشاشة</span><span class="pln">
</span><span class="pun">#</span><span class="pln"> </span><span class="pun">ثم</span><span class="pln"> </span><span class="pun">أخبر</span><span class="pln"> </span><span class="pun">المستخدم</span><span class="pln"> </span><span class="pun">ما</span><span class="pln"> </span><span class="pun">يفعله</span><span class="pln"> </span><span class="pun">للخروج</span><span class="pln">

screen </span><span class="pun">=</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">initscr</span><span class="pun">()</span><span class="pln">
c</span><span class="pun">.</span><span class="pln">savetty</span><span class="pun">()</span><span class="pln">
c</span><span class="pun">.</span><span class="pln">noecho</span><span class="pun">()</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">addstr</span><span class="pun">(</span><span class="str">"Hit space to end...\n"</span><span class="pun">)</span><span class="pln">

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">والآن</span><span class="pln"> </span><span class="pun">تعمل</span><span class="pln"> </span><span class="pun">الحلقة</span><span class="pln"> </span><span class="pun">الأساسية</span><span class="pln"> </span><span class="pun">بلا</span><span class="pln"> </span><span class="pun">نهاية</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="typ">True</span><span class="pun">:</span><span class="pln">
     ky </span><span class="pun">=</span><span class="pln"> screen</span><span class="pun">.</span><span class="pln">getch</span><span class="pun">()</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> ky </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">:</span><span class="pln">
       </span><span class="pun">#</span><span class="pln"> send events to event handling functions
       </span><span class="kwd">if</span><span class="pln"> ky </span><span class="pun">==</span><span class="pln"> ord</span><span class="pun">(</span><span class="str">" "</span><span class="pun">):</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> check </span><span class="kwd">for</span><span class="pln"> quit event
         doQuitEvent</span><span class="pun">(</span><span class="pln">ky</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> 
         doKeyEvent</span><span class="pun">(</span><span class="pln">ky</span><span class="pun">)</span><span class="pln">

c</span><span class="pun">.</span><span class="pln">endwin</span><span class="pun">()</span></pre>

<p>
	لا تعمل أوامر الطباعة العادية في وحدة <code>curses</code>، بل يجب أن نستخدم دوال معالجة الشاشة الخاصة بوحدة <code>curses</code>، كما تعيد <code>getch</code> هنا <code>‎-1</code> إذا لم يُضغط على أي مفتاح -بدلًا من سلسلة فارغة-، ويطابق منطق البرنامج نسخة ويندوز السابقة فيما عدا ذلك.
</p>

<p>
	ويجب أن تستعيد <code>curses.endwin()‎</code> شاشتنا إلى الحالة العادية، لكنها قد لا تعمل أحيانًا، فإذا اختفى المؤشر أو لم نحصل على محرف إرجاع لبداية السطر أو غير ذلك، فسنصلح المشكلة بالخروج من <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a> باستخدام Ctrl+D واستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1276_20" style=""><span class="pln">$ stty echo </span><span class="pun">-</span><span class="pln">nl</span></pre>

<p>
	تشير <code>nl</code> إلى "سطر جديد"، وينبغي أن يصلح هذا السطر المشكلة أعلاه حال حدوثها.
</p>

<p>
	إذا كنا ننشئ هذا مثل إطار عمل لاستخدامه في مشاريع عدة، فسنضيف استدعاءً إلى دالة تهيئة initialization function في البداية ودالة تنظيف في النهاية، ثم يستطيع المبرمج عندئذ استخدام الجزء الخاص بالحلقة وتوفير دواله الملائمة للتهيئة والمعالجة والتنظيف، وهذا ما تفعله البيئات الرسومية تحديدًا، حيث يكون الجزء الخاص بالحلقة مضمَّنًا في بيئة التشغيل أو إطار العميل، ويكون على البرامج أن توفر دوال معالجة الأحداث الخاصة بها وتربطها بحلقة الأحداث بشكل ما، لنر ذلك عمليًا أثناء دراسة مكتبة Tkinter الرسومية.
</p>

<h2>
	برنامج رسومي
</h2>

<p>
	سنستخدم صندوق أدوات Tkinter من <a href="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">بايثون</a> في هذه التدريب، وهو مغلف بايثون لصندوق أدوات Tk، والذي كُتب في البداية امتدادًا للغة Tcl، كما أنه متاح للغتي Perl وروبي أيضًا، ونسخة بايثون منه هي إطار عمل كائني التوجه، العمل فيه أسهل من نسخة Tk الأصلية، وسننظر بتفصيل أكثر في مبادئ برمجة الواجهات الرسومية فيما بعد في مقال قادم، لذا لن نسهب كثيرًا في الحديث عن <a href="https://academy.hsoub.com/design/user-interface/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-r552/" rel="">مبادئ الواجهات الرسومية</a> في هذا المقال، لأننا نريد التركيز على نمط البرمجة نفسه، وهو استخدام Tkinter لمعالجة حلقة الأحداث، ونترك المبرمج ينشئ الواجهة الرسومية الابتدائية، ثم يعالج الأحداث حال وصولها.
</p>

<p>
	وفي مثالنا هنا ننشئ صنف تطبيق application class اسمه <code>KeysApp</code> ينشئ الواجهة الرسومية في التابع <code>__init__</code>، ويربط مفتاح المسافة بالتابع <code>doQuitEvent</code>، كما يعرّف الصنف تابع <code>doQuitEvent</code> المطلوب، أما الواجهة الرسومية نفسها فتتكون ببساطة من ودجِت widget (تطبيق مُصغَّر) لإدخال النصوص؛ سلوكها الافتراضي هو طباعة المحارف المدخَلة على الشاشة.
</p>

<p>
	إن إنشاء صنف تطبيق في البيئات الحدثية كائنية التوجه أمر شائع، بسبب الارتباط بين مفاهيم الأحداث المرسَلة إلى برنامج ما والرسائل المرسَلة إلى كائن، إذ يرتبطان ببعضهما بسهولة كبيرة، وبذلك تصبح دالة معالجة الحدث تابعًا لصنف التطبيق، وبعد أن عرّفنا الصنف سننشئ نسخةً منه ونرسل إليها رسالة <code>mainloop</code>، وستبدو الشيفرة كما يلي: ً
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1276_22" style=""><span class="com"># للحفظ، بما أن علينا تقديم كل شيءfrom X import * استخدم</span><span class="pln">
</span><span class="com"># tkinter.xxx كـ</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> tkinter </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> sys


</span><span class="com"># أنشئ صنف التطبيق الذي يعرف الواجهة الرسومية وتوابع</span><span class="pln">
</span><span class="com"># معالجة الأحداث</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">KeysApp</span><span class="pun">(</span><span class="typ">Frame</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln"> </span><span class="com"># use constructor to build GUI</span><span class="pln">
        super</span><span class="pun">().</span><span class="pln">__init__</span><span class="pun">()</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">txtBox </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Text</span><span class="pun">(</span><span class="pln">self</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">txtBox</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="str">"&lt;space&gt;"</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">doQuitEvent</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">txtBox</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> doQuitEvent</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln">event</span><span class="pun">):</span><span class="pln">
        sys</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">()</span><span class="pln">


</span><span class="com"># والآن أنشئ نسخة وابدأ تشغيل حلقة الحدث</span><span class="pln">
myApp </span><span class="pun">=</span><span class="pln"> </span><span class="typ">KeysApp</span><span class="pun">()</span><span class="pln">
myApp</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<p>
	نلاحظ أن البرنامج لن يغلق إغلاقًا صحيحًا عند تشغيل هذه الشيفرة من داخل IDLE، بل سيطبع رسالة إغلاق في نافذة الصدفة، وهو أسلوب IDLE حين يريد أن يساعدنا! أما إذا شغلناها في سطر الأوامر فسيعمل كل شيء بسلاسة.
</p>

<p>
	كما نلاحظ أننا لا نطبق معالج أحداث المفاتيح، لأن السلوك الافتراضي لودجِت أو تطبيق النص هو طباعة المفاتيح المضغوطة، لكن هذا يعني أن برامجنا ليست متكافئةً وظيفيًا، فقد طبعنا رموز آسكي في الطرفية بدلًا من طباعة النسخة الأبجدية من المفاتيح القابلة للطباعة كما فعلنا هنا، فليس ثمة شيء يمنعنا من التقاط جميع ضغطات المفاتيح وفعل نفس الشيء، فإذا أردنا تنفيذ هذا فسنضيف السطر التالي إلى تابع <code>__init__</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1276_24" style=""><span class="pln">self</span><span class="pun">.</span><span class="pln">txtBox</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="str">"&lt;Key&gt;"</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">doKeyEvent</span><span class="pun">)</span></pre>

<p>
	كما سنضيف التابع التالي لمعالجة الحدث:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1276_26" style=""><span class="kwd">def</span><span class="pln"> doKeyEvent</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln">event</span><span class="pun">):</span><span class="pln">
    str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"%d\n"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">keycode
    self</span><span class="pun">.</span><span class="pln">txtBox</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="pln">END</span><span class="pun">,</span><span class="pln"> str</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"break"</span></pre>

<p>
	نلاحظ تخزين قيمة المفتاح في حقل <code>keycode</code> للحدث، وقد اضطررت إلى العودة إلى الشيفرة الأساسية للملف Tkinter.py لمعرفة ذلك، تذكر أن الفضول هو الصفة المميزة للمبرمج.
</p>

<p>
	كما نلاحظ أن <code>return "break"‎</code> هي إشارة سحرية تخبر Tkinter بأن لا يستدعي معالجة الأحداث الافتراضية لهذه الودجِت، وبدون هذا السطر سيعرض الصندوق النصي رمز آسكي متبوعًا بالمحرف الحقيقي الذي ضُغط، وليس هذا ما نريده.
</p>

<p>
	إلى هنا يكفي الحديث عن Tkinter، فلم نكن ننو شرحه هنا وإنما في مقال تالٍ.
</p>

<h2>
	البرمجة الحدثية في VBScript وجافاسكربت
</h2>

<p>
	نستطيع تطبيق البرمجة الحدثية في كل من <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت</a> وVBScript عند برمجة متصفح، فعادةً إذا حُمِّلَت صفحة ويب تحتوي على سكربت فإن السكربت ينفَّذ جزءًا جزءًا مع تحميل الصفحة، لكن إذا لم يحوِ السكربت إلا تعريفات الدوال فلن يفعل التنفيذ شيئًا إلا تعريف الدوال على أنها جاهزة للاستخدام، أما الدوال نفسها فلن تُستدعى هنا ابتداءً، بل ستكون مقيدةً إلى عناصر <a href="https://wiki.hsoub.com/HTML#.D8.A7.D9.84.D8.B9.D9.86.D8.A7.D8.B5.D8.B1_.D8.A7.D9.84.D8.AA.D9.82.D8.B3.D9.8A.D9.85.D9.8A.D8.A9" rel="external">HTML</a> في الجزء الخاص بشيفرة HTML في الصفحة -داخل عنصر <code>Form</code> غالبًا-، بحيث تُستدعى هذه الدوال عند وقوع الأحداث، وقد رأينا هذا في مثال جافاسكربت الخاص بالحصول على مدخلات المستخدم عندما نقرأ المدخلات من استمارة HTML، لننظر في هذا المثال مرةً أخرى؛ ونر كيف أنه تطبيق عملي على برمجة حدَثية في صفحة ويب:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1276_31" style=""><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">'entry'</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;p&gt;</span><span class="pln">Type value then click outside the field with your mouse</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">Type</span><span class="pun">=</span><span class="atv">'text'</span><span class="pln"> 
          </span><span class="atn">Name</span><span class="pun">=</span><span class="atv">'data'</span><span class="pln"> 
          </span><span class="atn">onChange</span><span class="pun">=</span><span class="atv">'</span><span class="pln">alert</span><span class="pun">(</span><span class="str">"We got a value of "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">entry</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="atv">'</span><span class="tag">/&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span></pre>

<p>
	نلاحظ عدم وجود تعريف لدالة جافاسكربت، بل مجرد استدعاء لـ <code>alert</code> المرتبطة بسمة <code>onChange</code> لعنصر <code>input</code>، وهذه السمة هي إحدى الأحداث التي تستطيع عناصر HTML توليدها، ونستطيع ربط أي <a href="https://academy.hsoub.com/programming/javascript/%D9%86%D9%85%D8%B7-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r785/" rel="">شيفرة جافاسكربت</a> عشوائية لتنفيذها في كل مرة تقع فيها هذه الأحداث، كما يمكن إنشاء دالة واستدعاؤها بدلًا من استدعاء <code>alert</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1276_35" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> echoValue</span><span class="pun">(){</span><span class="pln">
   alert</span><span class="pun">(</span><span class="str">"We got a value of "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">entry</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">form name</span><span class="pun">=</span><span class="str">'entry'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Type</span><span class="pln"> value then click outside the field </span><span class="kwd">with</span><span class="pln"> your mouse</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">input </span><span class="typ">Type</span><span class="pun">=</span><span class="str">'text'</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">=</span><span class="str">'data'</span><span class="pln"> onChange</span><span class="pun">=</span><span class="str">'echoValue()'</span><span class="pun">/&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span></pre>

<p>
	يعرّف الجزء الخاص بالسكربت دالة جافاسكربت هي <code>echoValue</code> تحاكي استدعاء <code>alert</code> الذي كان معنا من قبل، ويحتوي عنصر <code>input</code> الآن على دالة مسندة على أنها معالج الأحداث للسمة <code>onChange</code>، ثم تنفَّذ الدالة عند تغير قيمة الدخل، وتكون حلقة الحدث التي تلتقط الأحداث مضمنةً داخل المتصفح.
</p>

<p>
	ورغم أن دالتنا هذه استدعت <code>alert</code> إلا أنها تستطيع أكثر من ذلك، بل من الممكن جعلها برنامجًا معقدًا بذاتها، وذلك وفقًا لما نضعه في متنها.
</p>

<p>
	يمكن استخدام VBScript بنفس الطريقة، عدا أن تعريفات الدوال ستكون بـ VBscript بدلًا من جافاسكربت، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1276_39" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Sub</span><span class="pln"> </span><span class="typ">EchoInput</span><span class="pun">()</span><span class="pln">
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"We got a value of "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">Document</span><span class="pun">.</span><span class="pln">entry2</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">value
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">form name</span><span class="pun">=</span><span class="str">'entry2'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Type</span><span class="pln"> value then click outside the field </span><span class="kwd">with</span><span class="pln"> your mouse</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">input </span><span class="typ">Type</span><span class="pun">=</span><span class="str">'text'</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">=</span><span class="str">'data'</span><span class="pln"> onChange</span><span class="pun">=</span><span class="str">'EchoInput()'</span><span class="pun">/&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span></pre>

<p>
	وبهذا نرى أن الشيفرة الموجهة للمتصفحات يمكن كتابتها في صورة أجزاء batches أو في صورة حدَثية event driven، أو بهما معًا، وفق متطلبات كل حالة.
</p>

<h2>
	خاتمة
</h2>

<p>
	نأمل في هذا المقال أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		لا تبالي حلقات الأحداث بالأحداث التي تلتقطها.
	</li>
	<li>
		تعالج معالجات الأحداث حدثًا واحدًا في كل مرة.
	</li>
	<li>
		توفر أطر العمل -مثل Tkinter- حلقة أحداث، وبعض معالجات الأحداث الافتراضية أحيانًا.
	</li>
	<li>
		يمكن كتابة الشيفرة لمتصفحات الويب بأسلوب مدفوع بالأحداث، أو بالأجزاء، أو بهما معًا.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutevent.htm" rel="external nofollow">للفصل الثامن عشر: Event Driven Programming</a>، من كتاب Learn To Program لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-tkinter-r1378/" rel="">برمجة الواجهات الرسومية باستخدام Tkinter</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">البرمجة كائنية التوجه</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">ما هي البرمجة ومتطلبات تعلمها؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1376</guid><pubDate>Thu, 18 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x643;&#x627;&#x626;&#x646;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x648;&#x62C;&#x647;</title><link>https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/619d450cd6165_--.png.69ac948bcc6abd4eb7cb149f05aa97d6.png" /></p>
<p>
	رغم أن الأفكار التي كانت وراء البرمجة الكائنية التوجه طُورت في ستينيات القرن الماضي إلا أنها لم تشتهر في الوسط البرمجي إلا بعد ذلك بعقدين، أي في الثمانينيات، بعد إطلاق Smalltalk-80 ومجموعة متنوعة من تطبيقات لغة Lisp، ولم تكن وقتها اتجاهًا سائدًا في البرمجة وإنما كانت تثير الفضول فقط، ثم تغير ذلك عندما انتشرت الواجهات الرسومية في الحواسيب الشخصية على حواسيب أبل أولًا، ثم على الحواسيب العاملة بنظام ويندوز ونظام نوافذ X في يونكس، إلى أن اقتربنا من نهاية الألفية السابقة، حيث صارت البرمجة الكائنية التوجه Object Oriented Programming -والتي تعرف اختصارًا <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr>- التقنية الأبرز ل<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7%D8%AA/" rel="">تطوير البرمجيات</a>.
</p>

<p>
	وتتجسد مفاهيم البرمجة الكائنية التوجه في لغات مثل <a href="https://academy.hsoub.com/programming/java/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-objects-%D9%88%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-oop-r966/" rel="">جافا</a> وC++‎ و<a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-programming-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r309/" rel="">بايثون</a> بحيث لا تكاد تفعل شيئًا فيها إلا وتقابل كائنًا في مكان ما، ونريد في هذا المقال أن نتعرف على هذه التقنية وننظر في المفاهيم الأساسية لها، مثل تعريف الكائن والصنف وتعددية الأشكال polymorphism والوراثة inheritance، وكيفية إنشاء الكائنات وتخزينها واستخدامها، والبرمجة الكائنية التوجه موضوع كبير قد كُتبت فيه كتب، فإذا أردت التعمق فيه أكثر مما هو مذكور في هذا المقال فانظر هذه الكتب باللغة الإنجليزية:
</p>

<ul>
	<li>
		كتاب Object Oriented Analysis لبيتر كود Peter Coad وإد يوردون Ed Yourdon.
	</li>
	<li>
		كتاب Object Oriented Analysis and Design with Applications لجريدي بوش Grady Booch (الطبعة الأولى أو الثالثة).
	</li>
	<li>
		كتاب Object Oriented Software Construction لبرتراند ماير Berterand Meyer (الطبعة الثانية).
	</li>
</ul>

<p>
	تختلف هذه الكتب عن بعضها في العمق والحجم والدقة الأكاديمية بالترتيب، فالكتاب الأول مناسب للأغراض العامة التي هي خارج نطاق العمل البرمجي، والحق أنها كلها ليست كتبًا في البرمجة، بل كتب تحليل وتصميم برمجي، لأن أفضل تطبيق للبرمجة الكائنية التوجه يكون بتطبيق المبادئ خلال دورة حياة المشروع، وهذه طريقة مختلفة لحل المشاكل عن الطريقة العادية للبرمجة.
</p>

<p>
	أما في هذا المقال فسنتحدث باختصار عن مفاهيم البرمجة الكائنية التوجه التي ذكرناها، ولا مشكلة إذا لم تستوعبها في البداية، فلا تزال تستطيع استخدام الكائنات بدون أن تستوعب المفهوم الذي بُنيت عليه، ثم ستتضح الأمور بالتدريج مع التدرب والوقت،كما يمكن استخدام تصميم كائني التوجه في لغة غير كائنية من خلال الاصطلاحات البرمجية، لكن لا يُنصح بهذا الأسلوب، وإنما يستخدَم ملاذًا أخيرًا عندما لا نجد حلًا آخر، حيث تُستخدم التقنيات الكائنية التوجه إذا كانت المشكلة توافقها وتُحل بها، ويُفضل أن تُستخدم لغة كائنية التوجه أيضًا عندها، وتدعم أغلب اللغات الحديثة البرمجة الكائنية التوجه جيدًا، بما فيها اللغات الثلاثة التي نتدرب عليها، لكننا سنستخدم بايثون في الأمثلة الواردة هنا، ثم سنعرض المفاهيم الأساسية فقط في <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت</a> وVBScript.
</p>

<h2>
	جمع البيانات والدوال
</h2>

<p>
	الكائنات هي تجميعات من البيانات والدوال التي تنفذ مهامًا على تلك البيانات، وتوضعان معًا بحيث يمكن تمرير كائن من جزء ما في البرنامج كي نحصل تلقائيًا على وصول إلى العمليات المتاحة وسمات البيانات، وهذا الجمع بين البيانات والدوال هو أصل البرمجة الكائنية التوجه، ويُعرف باسم التغليف encapsulation، لأن بعض <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a> تخفي البيانات عن مستخدمي الكائن، وبناءً عليه تتطلب توابع الكائن للوصول إليها، وتسمى هذه التقنية باسم إخفاء البيانات، ويطلق عليها التغليف أحيانًا، وكمثال على التغليف، قد يخزن كائن سلسلة نصية سلسلة محارف، لكنه يوفر كذلك توابع للعمل على هذه السلسلة؛ لتنفيذ أمور مثل البحث وتغيير حالة الأحرف وحساب الطول وغير ذلك، وتستخدم الكائنات مجازًا تمرير الرسالة message passing، حيث يمرر كائنٌ رسالةً إلى كائن آخر، ويرد الكائن المستقبل بتنفيذ تابع -وهو إحدى عملياته-، وهكذا يُستدعى التابع عند استقبال الرسالة الموافقة له بواسطة الكائن المالك، ويمكن تمثيل ذلك بصيغ مختلفة، وأكثرها شيوعًا الصيغة النقطية <code>.</code> التي تحاكي الوصول إلى العناصر التي في الوحدات، فبالنسبة إلى صنف widget وهمي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_14" style=""><span class="pln">w </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Widget</span><span class="pun">()</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> widget </span><span class="pun">جديدة</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> w </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">نسخة</span><span class="pln"> 
w</span><span class="pun">.</span><span class="pln">paint</span><span class="pun">()</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> paint </span><span class="pun">أرسل</span><span class="pln"> </span><span class="pun">إليها</span><span class="pln"> </span><span class="pun">الرسالة</span><span class="pln"> </span></pre>

<p>
	ستستدعي هذه التعليمات التابع paint الخاص بكائن widget.
</p>

<h2>
	تعريف الأصناف
</h2>

<p>
	يمكن للكائنات أن تحتوي على أنواع مختلفة، كما أن للبيانات أنواعًا مختلفةً، وتُعرَّف تجميعات الكائنات التي لها صفات متطابقة باسم الأصناف classes، ونستطيع تعريف هذه الأصناف وإنشاء نسخ منها، حيث تكون تلك النسخ هي الكائنات الفعلية، كما يمكن تخزين مراجع إلى تلك الكائنات في المتغيرات داخل برامجنا، لننظر الآن في مثال حقيقي لنرى إن كنا نستطيع تفسيره وشرحه، حيث سننشئ صنف رسالة يحتوي على سلسلة نصية -تمثل نص الرسالة- وتابع لطباعة الرسالة.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9113_18" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Message</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">,</span><span class="pln"> aString</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">text </span><span class="pun">=</span><span class="pln"> aString
    </span><span class="kwd">def</span><span class="pln"> printIt</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
        print</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">text </span><span class="pun">)</span></pre>

<ul>
	<li>
		الملاحظة الأولى: يسمى أحد توابع هذا الصنف باسم <code>__init__</code>، وهو تابع خاص يسمى الباني constructor، وسبب هذا الاسم أنه يُستدعى عند إنشاء أو بناء نسخة جديدة من كائن ما، وستكون المتغيرات المسندة داخل هذا التابع -والتي أنشئت داخل <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-programming-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r313/" rel="">بايثون</a>- متغيرات فريدة للنسخة الجديدة، وتوجد عدة توابع خاصة مثل هذا التابع في بايثون، وجميعها مميزة بصيغة التسمية التي فيها شرطتان سفليتان عن يمينها وشمالها <code>__xxx__</code>، ويطلق عليها مستخدمو <a href="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">بايثون</a> أحيانًا اسم التوابع السحرية magic methods أو التوابع المحاطة بشرطين سفليتين dunder methods (إذ dunder اختصار إلى double under)؛ أما وقت استدعاء الباني الدقيق فيختلف بين اللغات، حيث يُستدعى التابع <code>init</code> في بايثون بعد إنشاء النسخة في الذاكرة، لكنه في لغات أخرى يعيد النسخة نفسها، والفرق في هذا بين اللغات طفيف ولا يستحق الانتباه له.
	</li>
	<li>
		الملاحظة الثانية: يحتوي كلا التابعين المعرفين على معامل أول هو <code>self</code>، والاسم مجرد اصطلاح يشير إلى نسخة الكائن، وسنرى قريبًا أن هذا المعامِل لا يملؤه المبرمج، بل يُملأ بواسطة المفسر في وقت التشغيل، وعلى هذا يُستدعى <code>printIt</code> على نسخة للصنف -انظر أدناه-، بدون وسطاء بالشكل <code>m.printIt()‎</code>.
	</li>
	<li>
		الملاحظة الثالثة: لقد استدعينا الصنف <code>Message</code> بحرف M كبير كما نرى، وهذا للسهولة فقط، لكن هذا الاصطلاح يُستخدم بكثرة في لغات البرمجة الكائنية التوجه، وليس في بايثون وحدها، ويوجد اصطلاح قريب من هذا يقتضي أن تبدأ أسماء التوابع بحرف صغير ثم تبدأ الكلمات التالية في الاسم بحرف كبير، فإذا كان لدينا تابع اسمه calculate current balance، فسيُكتب بالشكل <code>calculateCurrentBalance</code>.
	</li>
</ul>

<p>
	ننصحك عند هذه النقطة بالعودة إلى مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r1287/" rel="">البيانات وأنواعها</a>، لقراءة قسم الأنواع المعرَّفة من قِبل المستخدم، حيث ستفهم مثال دليل جهات الاتصال في بايثون فهمًا أفضل بعد هذا الشرح هنا، فالنوع الوحيد الذي يعرّفه المستخدم في بايثون هو الصنف، والصنف الذي له سمات attributes وليس له توابع -ما عدا <code>__init__</code>- يكافئ الباني المسمى <code>record</code> أو <code>struct</code> في بعض لغات البرمجة.
</p>

<h2>
	الصيغة الرسومية
</h2>

<p>
	تبنّى مجتمع <a href="https://academy.hsoub.com/programming/general/%D9%87%D9%86%D8%AF%D8%B3%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7%D8%AA/" rel="">هندسة البرمجيات</a> صيغةً مرئيةً لوصف الأصناف والكائنات وعلاقاتها بعضها ببعض، وتسمى هذه الصيغة باسم <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%AE%D8%B7%D8%B7%D8%A7%D8%AA-%D8%A7%D9%84%D9%81%D8%A6%D8%A7%D8%AA-class-diagram-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D9%88%D8%AD%D8%AF%D8%A9-uml-r307/" rel="">لغة النمذجة الموحدة</a> Unified Modelling Language أو UML اختصارًا، وهي أداة تصميم قوية وتحتوي على العديد من المخططات والأيقونات، وسننظر في بعضها هنا بما يعيننا على فهم المبادئ التي نريد شرحها فقط، وأول أيقونة سنقابلها في UML هي وصف الصنف، وهي أهم الأيقونات، وتتكون من صندوق من ثلاثة أجزاء، يحتوي الجزء العلوي على اسم الصنف، والأوسط على سماته أو البيانات فيه، أما الجزء السفلي فيحتوي على توابع الصنف أو دواله، وبناءً عليه سيبدو صنف Message المعرَّف أعلاه كما يلي:
</p>

<p style="text-align: center;">
	<img alt="uml-class.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83271" data-unique="me65pdxzh" src="https://academy.hsoub.com/uploads/monthly_2021_11/uml-class.png.2386e876bf062477aef79688db48ec99.png">
</p>

<p>
	سنرى في هذا المقال أيقونات UML أخرى، ونتعرض لمفاهيم جديدة تدعمها هذه الصيغة.
</p>

<h2>
	استخدام الأصناف
</h2>

<p>
	بما أننا عرّفنا الصنف Message فنستطيع إنشاء نسخ منه الآن والعمل عليها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9113_25" style=""><span class="pln">m1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Message</span><span class="pun">(</span><span class="str">"Hello world"</span><span class="pun">)</span><span class="pln">
m2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Message</span><span class="pun">(</span><span class="str">"So long, it was short but sweet"</span><span class="pun">)</span><span class="pln">

notes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">m1</span><span class="pun">,</span><span class="pln"> m2</span><span class="pun">]</span><span class="pln"> </span><span class="com"># ضع الكائنات في قائمة</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> msg in notes</span><span class="pun">:</span><span class="pln">
    msg</span><span class="pun">.</span><span class="pln">printIt</span><span class="pun">()</span><span class="pln"> </span><span class="com"># اطبع الرسائل متتابعة</span></pre>

<p>
	وبهذا نعامل الصنف كما لو كان نوع بيانات قياسيًا في بايثون، وهو الغرض من التدريب ابتداءً.
</p>

<p>
	كما توجد أيقونة للكائن أو النسخة في UML، وهي مثل أيقونة الصنف إلا أننا نترك الجزئين السفليين في الصندوق فارغين، ويتكون الاسم من اسم الكائن أو النسخة متبوعًا بنقطتين رأسيتين ثم اسم الصنف، وعليه فإن <code>m1:Message</code> تخبرنا أن <code>m1</code> ما هي إلا نسخة من الصنف <code>Message</code>، ويمكن رسم مثال الرسالة الخاص بنا الآن كما يلي:
</p>

<p style="text-align: center;">
	<img alt="uml-object.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83272" data-unique="o5epxwq9h" src="https://academy.hsoub.com/uploads/monthly_2021_11/uml-object.png.c340e95bfeff2ebeb1577785d7374490.png">
</p>

<p>
	نلاحظ أن الصنف <code>List</code> يمثل نوع القائمة القياسي في بايثون، كما هو موضح من وضع كلمة <code>builtin</code> بين أقواس حادة، وهي بنية معروفة في UML باسم القالب النمطي stereotype، وتشير الخطوط ذوات الرؤوس الماسية في الصورة إلى القائمة التي تحتوي على كائنات <code>Message</code>، وبالمثل فإن كائن <code>MyProg</code> يُنمَّط stereotyped على أنه صنف مساعد utility class، مما يعني في هذه الحالة أنه غير موجود مثل صنف داخل البرنامج، لكنه منتج من منتجات البيئة نفسها، وتُظهَر أدوات نظام التشغيل عادةً بهذه الطريقة، مثل مكتبات لدوال.
</p>

<p>
	أما الخطوط المستقيمة التي تخرج من <code>myProg</code> إلى <code>Message</code> فتوضح أن الكائن <code>myProg</code> يرتبط بـكائنات <code>Message</code> أو يشير إليها، وتشير الأسهم المرافقة لتلك الخطوط أن كائن <code>myProg</code> يرسل رسالة <code>printIt</code> إلى كل كائن من كائنات <code>Message</code>، وتُنقل رسائل الكائنات من خلال ارتباطات associations.
</p>

<h3>
	المعامل self
</h3>

<p>
	يطرح من يبدأ حديثًا في البرمجة الكائنية التوجه ببايثون سؤالًا هو: ما هو المعامل self؟ لأن تعريف أي تابع في صنف ما في بايثون يبدأ به، ويجب أن نبين أن الاسم نفسه مجرد اصطلاح، ولم يتغير إلى الآن لأن الثبات أمر محمود في الاصطلاحات البرمجية، <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-javascript-r664/" rel="">فلغة جافاسكربت</a> مثلًا لديها مفهوم مشابه لكنها تستخدم اسم <code>this</code> بدلًا من self.
</p>

<p>
	أما self نفسه فهو مرجع إلى النسخة الحالية، فحين ننشئ نسخةً من الصنف فإنها تحتوي على بياناتها الخاصة كما أنشأها الباني، لكنها لا تحوي التوابع، لذا عندما نرسل رسالةً إلى نسخة وتستدعي التابع الموافق؛ فإنها تستدعيه إلى الصنف من خلال مرجع داخلي، فتمرر مرجعًا إلى نفسها self إلى التابع لتعرف شيفرة الصنف أي نسخة يجب أن تستخدمها.
</p>

<p>
	لننظر الآن في مثال مألوف، فإذا كان لدينا تطبيق رسومي فيه كائنات أزرار كثيرة، فسيُفعَّل التابع المرتبط بكل زر عندما يضغطه المستخدم، ويعرف تابع الزر أي زر ضغِط بالإشارة إلى قيمة self التي ستكون مرجعًا إلى نسخة الزر الحقيقي الذي ضُغط، وسنرى ذلك عمليًا في مقال لاحق.
</p>

<p>
	وعند إرسال رسالة إلى كائن يحدث ما يلي:
</p>

<ul>
	<li>
		تستدعي شيفرة العميل النسخة، أي ترسل الرسالة إذا أردنا الحديث باصطلاح البرمجة الكائنية التوجه.
	</li>
	<li>
		تستدعي النسخة تابع الصنف، وتمرر مرجعًا إلى نفسها self.
	</li>
	<li>
		يستخدم تابع الصنف بعدها المرجع الممرَّر ليأخذ بيانات النسخة للكائن المستقبِل.
	</li>
</ul>

<p>
	يمكن رؤية تلك النقاط عمليًا في تسلسل الشيفرة التالي، ونلاحظ أننا نستطيع استدعاء تابع الصنف صراحةً كما فعلنا في السطر الأخير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_29" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> C</span><span class="pun">:</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   def __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> val</span><span class="pun">):</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">val </span><span class="pun">=</span><span class="pln"> val
</span><span class="pun">...</span><span class="pln">   def f</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln"> print </span><span class="pun">(</span><span class="str">"hello, my value is:"</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">val</span><span class="pun">)</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> create two instances
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> a </span><span class="pun">=</span><span class="pln"> C</span><span class="pun">(</span><span class="lit">27</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> b </span><span class="pun">=</span><span class="pln"> C</span><span class="pun">(</span><span class="lit">42</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> first </span><span class="kwd">try</span><span class="pln"> sending messages to the instances
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">f</span><span class="pun">()</span><span class="pln">
hello</span><span class="pun">,</span><span class="pln"> my value is </span><span class="lit">27</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> b</span><span class="pun">.</span><span class="pln">f</span><span class="pun">()</span><span class="pln">
hello</span><span class="pun">,</span><span class="pln"> my value is </span><span class="lit">42</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> now call the method explicitly via the </span><span class="kwd">class</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> C</span><span class="pun">.</span><span class="pln">f</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">
hello</span><span class="pun">,</span><span class="pln"> my value is </span><span class="lit">27</span></pre>

<p>
	نستطيع استدعاء التوابع كما نرى في المثال أعلاه من خلال النسخة، وتملأ بايثون معامِل self في تلك الحالة لنا، أو من خلال الصنف صراحةً، وفي تلك الحالة نحتاج إلى تمرير قيمة self صراحةً.
</p>

<p>
	لدينا سؤال يطرح نفسه الآن، فإذا كانت بايثون تستطيع توفير مرجع بين النسخة وصنفها، ألا تستطيع أن تملًا self بنفسها أيضًا؟ ربما يكون هذا سؤالًا منطقيًا لكن الإجابة عليه هي أن Guido Van Rossum -منشئ اللغة- صممها هكذا. لكن مع هذا فإن العديد من لغات البرمجة الكائنية التوجه تخفي معامِل self، لكن بايثون تعتمد الصراحة explicity وتفضلها على الضمنية implicity، ويتعود المبرمج على هذا المبدأ مع كثرة العمل.
</p>

<h2>
	تعددية الأشكال polymorphism
</h2>

<p>
	لدينا الآن القدرة على تعريف أصنافنا الخاصة وإنشاء نسخ منها وإسنادها إلى متغيرات، ثم تمرير رسائل إلى تلك الكائنات تؤدي إلى تشغيل التوابع التي عرفناها، لكن هناك عنصر أخير يتعلق بالبرمجة الكائنية التوجه هنا، وهو الأهم فيها من نواحٍ عدة، فإذا كان لدينا كائنان من صنفين مختلفين لكنهما يدعمان نفس مجموعة الرسائل، لكن مع التوابع الموافقة لها، فنستطيع عندئذ أن نجمع تلك الكائنات معًا ونعاملها معاملةً واحدةً في برنامجنا، لكنها ستتصرف تصرفًا مختلفًا، وتُعرف تلك القدرة على التصرف المختلف لنفس رسائل الدخل باسم تعددية الأشكال، تُستخدم هذه الخاصية عادةً لجعل عدد من الكائنات الرسومية المختلفة ترسم نفسها عند استلام رسالة paint، فترسم الدائرة شكلًا مختلفًا تمامًا عن المثلث، لكن بما أن لهما نفس تابع paint فنستطيع -نحن المبرمجين- أن نتجاهل الاختلافات ونراهما على أنهما مجرد أشكال، لننظر الآن في مثال نحسب فيه مساحة الأشكال بدلًا من رسمها:
</p>

<p>
	ننشئ أولًا الصنفين <code>Square</code> و<code>Circle</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_31" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Square</span><span class="pun">:</span><span class="pln">
    def __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> side</span><span class="pun">):</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">side </span><span class="pun">=</span><span class="pln"> side
    def calculateArea</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">side</span><span class="pun">**</span><span class="lit">2</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Circle</span><span class="pun">:</span><span class="pln">
    def __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> radius</span><span class="pun">):</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">radius </span><span class="pun">=</span><span class="pln"> radius
    def calculateArea</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">import</span><span class="pln"> math
        </span><span class="kwd">return</span><span class="pln"> math</span><span class="pun">.</span><span class="pln">pi</span><span class="pun">*(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">radius</span><span class="pun">**</span><span class="lit">2</span><span class="pun">)</span></pre>

<p>
	نستطيع الآن أن ننشئ قائمةً من الأشكال -دوائر أو مربعات- ثم نطبع مساحاتها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_33" style=""><span class="pln">shapes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="typ">Circle</span><span class="pun">(</span><span class="lit">5</span><span class="pun">),</span><span class="typ">Circle</span><span class="pun">(</span><span class="lit">7</span><span class="pun">),</span><span class="typ">Square</span><span class="pun">(</span><span class="lit">9</span><span class="pun">),</span><span class="typ">Circle</span><span class="pun">(</span><span class="lit">3</span><span class="pun">),</span><span class="typ">Square</span><span class="pun">(</span><span class="lit">12</span><span class="pun">)]</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> item in shapes</span><span class="pun">:</span><span class="pln">
    print </span><span class="str">"The area is: "</span><span class="pun">,</span><span class="pln"> item</span><span class="pun">.</span><span class="pln">calculateArea</span><span class="pun">()</span></pre>

<p>
	إذا جمعنا هذه الأفكار مع وحدات modules فسنحصل على آلية بالغة القوة لإعادة استخدام الشيفرة، حيث نضع تعريفات الصنف في وحدة ولتكن <code>shapes.py</code> مثلًا، ثم نستورد تلك الوحدة حين نرغب في التعديل على الأشكال، وهذا بالضبط ما حصل مع العديد من وحدات بايثون القياسية، وهو السبب الذي يجعل الوصول إلى توابع كائن ما يشبه استخدام الدوال في وحدة.
</p>

<p style="text-align: center;">
	<img alt="uml-shape-obj.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83273" data-unique="7x5eff0ud" src="https://academy.hsoub.com/uploads/monthly_2021_11/uml-shape-obj.png.098d13b5699854feff053b222eed31e9.png">
</p>

<p>
	نرى في الصورة أعلاه مخطط كائن أكثر تعقيدًا، ونلاحظ أن الكائنات التي داخل القائمة في هذه الحالة ليس لها أسماء لأننا لم ننشئ متغيرات لها صراحةً، ففي تلك الحالة نعرض مسافةً فارغةً قبل النقطين الرأسيتين واسم الصنف، لكن هذا يجعل المخطط مزدحمًا، لذا لا نرسم مخططات الكائنات إلا عند الضرورة لتوضيح بعض المزايا غير المألوفة للتصميم، أما في الأحوال العادية فنستخدم خصائص معقدةً أكثر من مخططات الأصناف لعرض العلاقات التي لدينا، كما سنرى في الأمثلة التالية.
</p>

<h2>
	الوراثة inheritence
</h2>

<p>
	تُستخدم الوراثة (أو الاكتساب) عادةً لتنفيذ تعددية الأشكال واستخدامها، وقد تكون هي الآلية الوحيدة لذلك في العديد من لغات البرمجة الكائنية، ويمكن للصنف أن يرث السمات والعمليات من صنف أب parent class أو صنف رئيسي super class، وهذا يعني أن الصنف الجديد المطابق لصنف آخر في أغلب جوانبه لا يجب أن يعيد تنفيذ جميع التوابع التي في الصنف الأول، بل يمكن أن يرث تلك الإمكانيات ثم يغيرها لتنفيذ أمور مختلفة، كما في تابع <code>calculateArea</code> أعلاه، وسنستخدم للتوضيح مثالًا فيه هرمية أصناف حسابات بنكية، حيث نستطيع إيداع المال والحصول على الرصيد والقيام بعمليات سحب، ولبعض الحسابات نسبة ربوية (فائدة) سنفترض أنها تُحسب عند كل إيداع، إضافةً إلى بعض الرسوم الأخرى لعمليات السحب.
</p>

<h3>
	الصنف BankAccount
</h3>

<p>
	لنرى الآن كيف سيبدو هذا المثال، سننظر في السمات والعمليات الخاصة بالحساب البنكي في أكثر مستوىً عام له، ومن الأفضل هنا أن ننظر في العمليات أولًا، ثم نوفر السمات حسب الحاجة لدعم تلك العمليات، فمع الحساب المصرفي نستطيع القيام بما يلي:
</p>

<ul>
	<li>
		إيداع المال.
	</li>
	<li>
		سحب المال.
	</li>
	<li>
		التحقق من الرصيد الحالي.
	</li>
	<li>
		تحويل الأموال إلى حساب آخر.
	</li>
</ul>

<p>
	وسنحتاج إلى معرِّف الحساب المصرفي ID للحساب الآخر والرصيد الحالي، بالنسبة للمعرِّف فسنستخدم المتغير الذي نسند الكائن إليه، لكن إذا كنا في مشروع حقيقي فيجب إنشاء سمة خاصة بالمعرِّف تخزن مرجعًا فريدًا، كما سنحتاج إلى تخزين الرصيد، وعند تمثيل ذلك بلغة النمذجة الموحدة UML فسيبدو كما يلي:
</p>

<p style="text-align: center;">
	<img alt="bankaccount-uml.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83267" data-unique="p2pq7fvpq" src="https://academy.hsoub.com/uploads/monthly_2021_11/bankaccount-uml.png.bb7c1ef171576df555f8a9a211399eeb.png">
</p>

<p>
	نستطيع الآن أن ننشئ صنفًا يدعم ذلك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9113_35" style=""><span class="com"># ‫ننشئ صنف اعتراض Exception مخصص</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">BalanceError</span><span class="pun">(</span><span class="typ">Exception</span><span class="pun">):</span><span class="pln"> 
      value </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Sorry you only have $%6.2f in your account"</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">BankAccount</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> initialAmount</span><span class="pun">):</span><span class="pln">
       self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">=</span><span class="pln"> initialAmount
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Account created with balance %5.2f"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> deposit</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> amount</span><span class="pun">):</span><span class="pln">
       self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">=</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">+</span><span class="pln"> amount

    </span><span class="kwd">def</span><span class="pln"> withdraw</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> amount</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">&gt;=</span><span class="pln"> amount</span><span class="pun">:</span><span class="pln">
          self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">=</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">-</span><span class="pln"> amount
       </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
          </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">BalanceError</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> checkBalance</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">balance

    </span><span class="kwd">def</span><span class="pln"> transfer</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> amount</span><span class="pun">,</span><span class="pln"> account</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">try</span><span class="pun">:</span><span class="pln"> 
          self</span><span class="pun">.</span><span class="pln">withdraw</span><span class="pun">(</span><span class="pln">amount</span><span class="pun">)</span><span class="pln">
          account</span><span class="pun">.</span><span class="pln">deposit</span><span class="pun">(</span><span class="pln">amount</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">BalanceError</span><span class="pun">:</span><span class="pln">
          </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="typ">BalanceError</span><span class="pun">.</span><span class="pln">value </span><span class="pun">%</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">)</span></pre>

<ul>
	<li>
		الملاحظة الأولى: نتحقق من الرصيد قبل السحب، ونستخدم اعتراضًا لمعالجة الأخطاء، وبما أنه لا يوجد خطأ من النوع <code>BalanceError</code> في بايثون فسنحتاج إلى إنشاء واحد، وهو صنف فرعي من الصنف <code>Exception</code> مع قيمة نصية، وتُعرَّف قيمة السلسلة <code>value</code> سمةً لصنف الاعتراض لمجرد الاصطلاح فقط، وهي تضمن أننا نولد رسائل خطأ في كل مرة نرفع فيها اعتراضًا، ونلاحظ هنا أننا لم نستخدم <code>self</code> عند تعريف القيمة في <code>BalanceError</code> لأن <code>value</code> سمة مشتركة بين كل النسخ، وهي معرَّفة على مستوى الصنف وتُعرف بمتغير الصنف، ونصل إليها باستخدام اسم الصنف متبوعًا بنقطة <code>BalanceError.value</code> كما رأينا أعلاه، فعندما يولّد خطأ التعقب العكسي traceback -أي مسار مكان وقوع الخطأ ورجوعًا ضمن سلسلة الاستدعاءات- فسينتهي بطباعة سلسلة الخطأ المصاغة مع عرض الرصيد الحالي.
	</li>
	<li>
		الملاحظة الثانية: يستخدم التابع <code>transfer</code> الدالة التابعة <code>withdraw/deposit</code> الخاصة بالصنف <code>BankAccount</code> أو توابعه لتنفيذ عملية التحويل، وهذا أمر شائع في البرمجة الكائنية التوجه ويُعرف بالمراسلة الذاتية self messaging، ويعني أن الأصناف المشتقة تستطيع تنفيذ نسخها الخاصة من <code>deposit/withdraw</code> لكن يظل التابع <code>transfer</code> كما هو لجميع أنواع الحسابات.
	</li>
</ul>

<p>
	بما أننا عرّفنا <code>BankAccount</code> صنفًا قاعديًا فنستطيع أن نعود إلى الوراثة التي كنا نشرحها، ولننظر في أول صنف فرعي لنا فيما يلي.
</p>

<h3>
	الصنف InterestAccount
</h3>

<p>
	نستخدم الوراثة الآن لتوفير حساب يضيف نسبة ربوية -سنفترض أنها ‎3%- عند كل عملية إيداع، وستكون مطابقةً لصنف BankAccount القياسي عدا تابع الإيداع وبدء معدل النسبة، لذا نعيد كتابة تنفيذ هذه التوابع كما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9113_37" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">InterestAccount</span><span class="pun">(</span><span class="typ">BankAccount</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">,</span><span class="pln"> initialAmount</span><span class="pun">,</span><span class="pln"> interest</span><span class="pun">=</span><span class="lit">0.03</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">super</span><span class="pun">().</span><span class="pln">__init__</span><span class="pun">(</span><span class="pln">initialAmount</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">interest </span><span class="pun">=</span><span class="pln"> interest
   </span><span class="kwd">def</span><span class="pln"> deposit</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">,</span><span class="pln"> amount</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">super</span><span class="pun">().</span><span class="pln">deposit</span><span class="pun">(</span><span class="pln">amount</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">balance </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">interest</span><span class="pun">)</span></pre>

<ul>
	<li>
		الملاحظة الأولى: نمرر الصنف الرئيسي (أو الأب) معامِلًا في تعريف الصنف، ويكون هذا الصنف الأب في حالتنا هو <code>BankAccount</code>.
	</li>
	<li>
		الملاحظة الثانية: نستدعي <code>super().__init__()‎</code> في بداية التابع <code>‎__init__()‎</code>، والدالة <code>super()‎</code> هي دالة خاصة وظيفتها معرفة الصنف الرئيسي، ويفيدنا ذلك عند وراثة أكثر من صنف رئيسي واحد فيما يسمى بالوراثة المتعددة، حيث نتجنب بعض المشاكل الغريبة التي قد تظهر إذا حاولنا استدعاء الصنف الرئيسي باسمه، لذلك يُفضل استخدام <code>super()‎</code>.
	</li>
</ul>

<p>
	ونبدأ الصنف الموروث باستدعاء التابع <code>__init__</code> الخاص بالصنف الرئيسي، ولا نحتاج هنا إلا إلى بدء السمة <code>interest</code> التي قدمناها هنا، وبالمثل في استخدام <code>super()‎</code> في تابع الإيداع، إذ يستدعي التابع <code>deposit</code> الخاص بالصنف الأب فلا نحتاج إلا إلى إضافة المزايا الجديدة للصنف <code>InterestAccount</code>.
</p>

<p>
	وهكذا نرى قوة البرمجة الكائنية التوجه وإمكانياتها، فبما أننا وضعنا <code>BankAccount</code> داخل الأقواس بعد اسم الصنف فقد صارت جميع التوابع موروثةً من <code>BankAccount</code>، ونلاحظ أن <code>deposit</code> تستدعي التابع <code>deposit</code> الخاص بالصنف الرئيسي بدلًا من نسخ الشيفرة، وسيحصل الصنف الفرعي على تلك التعديلات تلقائيًا إذا عدّلنا <code>deposit</code> الخاص بالصنف <code>BankAccount</code> بحيث يحوي تحققًا من بعض الأخطاء.
</p>

<h3>
	الصنف ChargingAccount
</h3>

<p>
	هذا الصنف مطابق للصنف <code>BankAccount</code> عدا أنه يطلب رسومًا افتراضية مقدارها ‎3$ لكل عملية سحب، وبالنسبة لـ <code>InterestAccount</code> فيمكن إنشاء صنف يرث من <code>BankAccount</code> ويعدّل التابعين <code>init</code> و <code>withdraw</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9113_39" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">ChargingAccount</span><span class="pun">(</span><span class="typ">BankAccount</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> initialAmount</span><span class="pun">,</span><span class="pln"> fee</span><span class="pun">=</span><span class="lit">3</span><span class="pun">):</span><span class="pln">
        super</span><span class="pun">().</span><span class="pln">__init__</span><span class="pun">(</span><span class="pln">initialAmount</span><span class="pun">)</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">fee </span><span class="pun">=</span><span class="pln"> fee

    </span><span class="kwd">def</span><span class="pln"> withdraw</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> amount</span><span class="pun">):</span><span class="pln">
        super</span><span class="pun">().</span><span class="pln">withdraw</span><span class="pun">(</span><span class="pln">amount</span><span class="pun">+</span><span class="pln">self</span><span class="pun">.</span><span class="pln">fee</span><span class="pun">)</span></pre>

<ul>
	<li>
		الملاحظة الأولى: نخزن الرسوم مثل متغير نسخة intance variable لنستطيع تغييره لاحقًا عند الحاجة، ونلاحظ أننا نستدعي <code>__init__</code> مرةً أخرى مثل أي تابع آخر.
	</li>
	<li>
		الملاحظة الثانية: نضيف الرسوم إلى عملية السحب المطلوبة في استدعاء التابع الموروث <code>withdraw</code> الذي ينجز العمل الفعلي.
	</li>
	<li>
		الملاحظة الثالثة: نضيف أثرًا جانبيًا هنا حيث تُفرض رسوم تلقائيًا على عمليات التحويل، لكن هذا مطلوب على الأرجح لذا لا بأس به، وتجدر الإشارة هنا إلى أن إعادة الاستخدام هذه تحمل في طياتها احتمالية الآثار الجانبية غير المتوقعة التي يجب الحذر منها.
	</li>
</ul>

<p>
	ونمثل هذه الوراثة في UML بسهم مصمت من الصنف الفرعي إلى الصنف الرئيسي، فتُمثَّل هرمية الحساب البنكي الآن كما يلي:
</p>

<p style="text-align: center;">
	<img alt="inheritance-uml.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83270" data-unique="fphk8vdla" src="https://academy.hsoub.com/uploads/monthly_2021_11/inheritance-uml.png.370d5a365e7b3be49d89bfb45aaa95f5.png">
</p>

<p>
	نلاحظ أننا سردنا التوابع والسمات التي تغيرت فقط أو أضيفت إلى الأصناف الفرعية.
</p>

<h3>
	اختبار النظام
</h3>

<p>
	للتحقق من عمل الهرمية السابقة بكفاءة، جرب تنفيذ الشيفرة التالية في محث بايثون أو بإنشاء ملف اختبار منفصل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9113_41" style=""><span class="kwd">from</span><span class="pln"> bankaccount </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln">
</span><span class="com"># الحساب البنكي العادي</span><span class="pln">
a </span><span class="pun">=</span><span class="pln"> </span><span class="typ">BankAccount</span><span class="pun">(</span><span class="lit">500</span><span class="pun">)</span><span class="pln">
b </span><span class="pun">=</span><span class="pln"> </span><span class="typ">BankAccount</span><span class="pun">(</span><span class="lit">200</span><span class="pun">)</span><span class="pln">
a</span><span class="pun">.</span><span class="pln">withdraw</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln">
</span><span class="com"># a.withdraw(1000)</span><span class="pln">
a</span><span class="pun">.</span><span class="pln">transfer</span><span class="pun">(</span><span class="lit">100</span><span class="pun">,</span><span class="pln">b</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"A = "</span><span class="pun">,</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"B = "</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

</span><span class="com"># حساب للنسبة الربوية</span><span class="pln">
c </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InterestAccount</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">)</span><span class="pln">
c</span><span class="pun">.</span><span class="pln">deposit</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"C = "</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

</span><span class="com"># حساب للرسوم المفروضة</span><span class="pln">
d </span><span class="pun">=</span><span class="pln"> </span><span class="typ">ChargingAccount</span><span class="pun">(</span><span class="lit">300</span><span class="pun">)</span><span class="pln">
d</span><span class="pun">.</span><span class="pln">deposit</span><span class="pun">(</span><span class="lit">200</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"D = "</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
d</span><span class="pun">.</span><span class="pln">withdraw</span><span class="pun">(</span><span class="lit">50</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"D = "</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
d</span><span class="pun">.</span><span class="pln">transfer</span><span class="pun">(</span><span class="lit">100</span><span class="pun">,</span><span class="pln">a</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"A = "</span><span class="pun">,</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"D = "</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

</span><span class="com"># حوّل من حساب الرسوم إلى حساب النسبة الربوية</span><span class="pln">
</span><span class="com"># حساب الرسوم سيطلب رسومًا، وحساب النسبة الربوية</span><span class="pln">
</span><span class="com"># يضيف نسبة ربوية</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"C = "</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"D = "</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
d</span><span class="pun">.</span><span class="pln">transfer</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"C = "</span><span class="pun">,</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"D = "</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	أزل علامة التعليق الآن من السطر <code>(a.withdraw(1000</code> لترى الاعتراض عمليًا.
</p>

<p>
	وبهذا نكون أتممنا مثالًا بسيطًا يظهر كيفية استخدام الوراثة لتوسيع إطار بسيط وإضافة مزايا قوية إليه، وقد رأينا كيف يبنى المثال على مراحل ويوضع برنامج اختبار للتحقق من نجاحه، مع أن اختباراتنا لم تكن كاملةً لأننا لم نغطِّ كل الحالات الممكنة، وكان من الممكن إدراج المزيد من الاختبارات، كما في حالة إنشاء حساب برصيد سالب.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<h4 data-gramm="false">
		التطوير الموجه بالاختبارات
	</h4>

	<p>
		يستخدم العديد من المبرمجين العاملين تقنيةً تسمى التطوير الموجَّه بالاختبار test driven development، حيث يكتبون اختباراتهم قبل كتابة الشيفرة البرمجية نفسها، مما يسمح لهم باختبار شيفرتهم مرةً بعد مرة أثناء تطويرها، وينتقلون تدريجيًا من فشل الاختبارات المتكرر إلى نجاحها، وإذا نجحت جميع الاختبارات فإن هذا يعني أن البرنامج يعمل بكفاءة. وهذا النهج شائع جدًا في البرمجة لدرجة تطوير أدوات خاصة لتساعد فيه، ولدى بايثون أدوات مثل هذه موجودة في وحدة <code>unittest</code> في المكتبة القياسية، وهذا النهج -وإن كان مفيدًا في كتابة شيفرة حقيقية- لن يفيدنا في شرحنا كثيرًا لأنه يخفي الشيفرة الأساسية وحالات اختبار كثيرة نحاول دراستها، لذا لن نستخدمه هنا، لكن قد ننظر فيه في مقال لاحق.
	</p>
</blockquote>

<h2>
	تجميعات الكائنات
</h2>

<p>
	إحدى المشاكل التي قد تواجهها هي كيفية التعامل مع كائنات كثيرة، أو كيفية التعامل مع كائنات تنشئها في وقت التشغيل، فمن السهل إنشاء حسابات بنكية ثابتة كما فعلنا أعلاه:
</p>

<pre class="ipsCode">acc1 = BankAccount(...)
acc2 = BankAccount(...)
acc3 = BankAccount(...)
etc...
</pre>

<p>
	لكن في العالم الحقيقي لا تكون لدينا بيانات عن عدد الحسابات التي يجب إنشاؤها، فكيف نحل هذه المشكلة؟ لننظر فيها بتفصيل أكبر:
</p>

<p>
	نريد شكلًا ما من <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قواعد البيانات</a> التي تسمح لنا بإيجاد أي حساب بنكي باسم مالكه أو رقم حسابه -بما أنه قد يكون للشخص الواحد عدة حسابات-، والعكس صحيح، ولكن ألا يشبه البحث عن شيء له معرّف خاص به القاموس؟ لنجرب استخدام <a href="https://academy.hsoub.com/programming/python/%D9%81%D9%87%D9%85-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%85%D9%8A%D8%B3-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r743/" rel="">قاموس في بايثون</a> للاحتفاظ بكائنات منشأة ديناميكيًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_45" style=""><span class="pln">from bankaccount </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">BankAccount</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> time

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">دالة</span><span class="pln"> </span><span class="pun">جديدة</span><span class="pln"> </span><span class="pun">لتوليد</span><span class="pln"> </span><span class="pun">أرقام</span><span class="pln"> </span><span class="pun">معرّفات</span><span class="pln"> </span><span class="pun">فريدة</span><span class="pln">
def getNextID</span><span class="pun">():</span><span class="pln">
    ok </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Create account[y/n]? "</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> ok</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> in </span><span class="str">'yY'</span><span class="pun">:</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> check valid input
       id </span><span class="pun">=</span><span class="pln"> time</span><span class="pun">.</span><span class="pln">time</span><span class="pun">()</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> use current time as basis of ID
       id </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="lit">10000</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">حول</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">صحيح</span><span class="pln"> </span><span class="pun">وقلله</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">أرقام</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">وذلك</span><span class="pln"> </span><span class="pun">سيوقف</span><span class="pln"> </span><span class="pun">الحلقة</span><span class="pln"> </span><span class="pun">التكرارية</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> id

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">بعض</span><span class="pln"> </span><span class="pun">الحسابات</span><span class="pln"> </span><span class="pun">وخزنها</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">القاموس</span><span class="pln">
accountData </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">قاموس</span><span class="pln"> </span><span class="pun">جديد</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="typ">True</span><span class="pun">:</span><span class="pln">          </span><span class="pun">#</span><span class="pln"> </span><span class="pun">كرر</span><span class="pln"> </span><span class="pun">حلقيًا</span><span class="pln"> </span><span class="pun">بلا</span><span class="pln"> </span><span class="pun">نهاية</span><span class="pln">
   id </span><span class="pun">=</span><span class="pln"> getNextID</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> id </span><span class="pun">==</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">:</span><span class="pln"> 
      </span><span class="kwd">break</span><span class="pln">       </span><span class="pun">#</span><span class="pln"> </span><span class="pun">تخرج</span><span class="pln"> </span><span class="pun">إجباريًا</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">الحلقة</span><span class="pln"> </span><span class="pun">التكرارية</span><span class="pln">
   bal </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Opening Balance? "</span><span class="pun">))</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">حول</span><span class="pln"> </span><span class="pun">السلسلة</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">ذي</span><span class="pln"> </span><span class="pun">فاصلة</span><span class="pln"> </span><span class="pun">عائمة</span><span class="pln">  
   accountData</span><span class="pun">[</span><span class="pln">id</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">BankAccount</span><span class="pun">(</span><span class="pln">bal</span><span class="pun">)</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">استخدم</span><span class="pln"> </span><span class="pun">المعرِّف</span><span class="pln"> </span><span class="pun">لإنشاء</span><span class="pln"> </span><span class="pun">إدخال</span><span class="pln"> </span><span class="pun">جديد</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">القاموس</span><span class="pln">
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"New account created, Number: %04d, Balance %0.2f"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> bal</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">دعنا</span><span class="pln"> </span><span class="pun">نصل</span><span class="pln"> </span><span class="pun">الآن</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">بعض</span><span class="pln"> </span><span class="pun">الحسابات</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> id in accountData</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">():</span><span class="pln">
    print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%04d\t%0.2f"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> accountData</span><span class="pun">[</span><span class="pln">id</span><span class="pun">].</span><span class="pln">checkBalance</span><span class="pun">())</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">ونبحث</span><span class="pln"> </span><span class="pun">عن</span><span class="pln"> </span><span class="pun">واحد</span><span class="pln"> </span><span class="pun">فيها</span><span class="pln">
</span><span class="pun">#</span><span class="pln"> </span><span class="pun">أدخل</span><span class="pln"> </span><span class="pun">محرفًا</span><span class="pln"> </span><span class="pun">غير</span><span class="pln"> </span><span class="pun">رقمي</span><span class="pln"> </span><span class="pun">لرفع</span><span class="pln"> </span><span class="pun">اعتراض</span><span class="pln"> </span><span class="pun">وإنهاء</span><span class="pln"> </span><span class="pun">البرنامج</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="typ">True</span><span class="pun">:</span><span class="pln">
   id </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Which account number? "</span><span class="pun">))</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> id in accountData</span><span class="pun">:</span><span class="pln">
      print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Balance = %0.2d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> accountData</span><span class="pun">[</span><span class="pln">id</span><span class="pun">].</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Invalid ID"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لا شك أن المفتاح الذي نستخدمه للقاموس قد يكون أي شيء يعرّف الكائن تعريفًا فريدًا، فقد يكون أحد سماته -مثل الرصيد <code>balance</code>- لكن الرصيد قد يتشابه بين الحسابات، ويتغير بالزيادة والنقص، وهكذا نفكر في الخيارات المتاحة إلى أن نصل إلى معرّف لا يتكرر، وهنا يمكن الرجوع إلى مقال البيانات وأنواعها، لقراءة القسم الخاص بالقاموس مرةً أخرى.
</p>

<p>
	يمثَّل هذا مرئيًا في UML باستخدام مخطط الصنف، ويُعرض القاموس مثل صنف له علاقة مع العديد من الحسابات البنكية، ونرى ذلك موضحًا بمحرف النجمة على الخط الموصل بين الأصناف، ونستخدم محرف النجمة هنا لأنه الرمز المستخدم في التعابير النمطية للإشارة إلى عدد من العناصر مقداره صفر أو أكثر، وهذا يُعرف بعدد عناصر العلاقة cardinality of the relationship، ويمكن رؤيته بعد طرق، لكن المجالات العددية للتعابير النمطية هي المستخدمة بكثرة لثرائها ومرونتها.
</p>

<p style="text-align: center;">
	<img alt="collection-uml.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83268" data-unique="zr2cwhk5p" src="https://academy.hsoub.com/uploads/monthly_2021_11/collection-uml.png.242368888955d77edb11c3bc5ea3a31c.png">
</p>

<p>
	نلاحظ استخدام القالب النمطي stereotype على القاموس <code>Dictionary</code> لإظهار أنه صنف مضمَّن، كما نلاحظ وجود الصندوق الملحق بالارتباط، والذي يوضح أن المفتاح هو قيمة المعرّف <code>ID</code>، فإذا كنا نستخدم قائمةً بسيطةً فلن يكون لدينا الصندوق ولكان الخط وصل بين الصنفين مباشرةً، وبهذا يتضح أننا نتجنب الحاجة إلى مخططات الكائنات الكبيرة والمعقدة باستخدام علاقات الأصناف وعدد العناصر في المجموعة cardinality، حيث نركز على العلاقات المجردة بين الأصناف بدلًا من التعامل مع عدد كبير من العلاقات الحقيقية بين النسخ المفردة.
</p>

<h2>
	حفظ الكائنات
</h2>

<p>
	إن فقد البيانات عند انتهاء المخطط هو أحد مشاكل السلوك السابق، لذا نريد طريقةً لحفظ الكائنات، ويمكن فعل ذلك باستخدام قواعد البيانات لكنه أسلوب متقدم، أما الآن فسنستخدم ملفًا نصيًا بسيطًا لحفظ الكائنات واسترجاعها، ورغم أن بايثون تحتوي على وحدتين لتنفيذ ذلك بكفاءة، وهما <code>pickle</code> و<code>shelve</code>، إلا أننا سنشرح الطريقة العامة التي تصلح لأي لغة، والطريقة العامة التي نقصدها هي إنشاء التابعين <code>save</code> و<code>restore</code> في الكائن ذي المستوى الأعلى، ثم إعادة كتابتهما في كل صنف ليستدعيا النسخة الموروثة ثم يضيفا السمات المعرفة محليًا، وبالمناسبة يُستخدم مصطلح الثبات Persistence للإشارة إلى القدرة على حفظ الأشياء واستعادتها.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9113_47" style=""><span class="kwd">class</span><span class="pln"> A</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln">x</span><span class="pun">,</span><span class="pln">y</span><span class="pun">):</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> x
     self</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> y
     self</span><span class="pun">.</span><span class="pln">f </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> save</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln">fn</span><span class="pun">):</span><span class="pln">
     f </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">fn</span><span class="pun">,</span><span class="str">"w"</span><span class="pun">)</span><span class="pln">
     f</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">str</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)+</span><span class="pln"> </span><span class="str">'\n'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># convert to a string and add newline</span><span class="pln">
     f</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">str</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)+</span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">
     </span><span class="kwd">return</span><span class="pln"> f             </span><span class="com"># for child objects to use</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> restore</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> fn</span><span class="pun">):</span><span class="pln">
     f </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">fn</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">f</span><span class="pun">.</span><span class="pln">readline</span><span class="pun">())</span><span class="pln"> </span><span class="com"># convert back to original type</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">f</span><span class="pun">.</span><span class="pln">readline</span><span class="pun">())</span><span class="pln">
     </span><span class="kwd">return</span><span class="pln"> f

</span><span class="kwd">class</span><span class="pln"> B</span><span class="pun">(</span><span class="pln">A</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln">x</span><span class="pun">,</span><span class="pln">y</span><span class="pun">,</span><span class="pln">z</span><span class="pun">):</span><span class="pln">
     super</span><span class="pun">().</span><span class="pln">__init__</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln">y</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">z </span><span class="pun">=</span><span class="pln"> z

   </span><span class="kwd">def</span><span class="pln"> save</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln">fn</span><span class="pun">):</span><span class="pln">
     f </span><span class="pun">=</span><span class="pln"> super</span><span class="pun">().</span><span class="pln">save</span><span class="pun">(</span><span class="pln">fn</span><span class="pun">)</span><span class="pln">  </span><span class="com"># call parent save</span><span class="pln">
     f</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">str</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">z</span><span class="pun">)+</span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">
     </span><span class="kwd">return</span><span class="pln"> f         </span><span class="com"># in case further children exist</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> restore</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> fn</span><span class="pun">):</span><span class="pln">
     f </span><span class="pun">=</span><span class="pln"> super</span><span class="pun">().</span><span class="pln">restore</span><span class="pun">(</span><span class="pln">fn</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">z </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">f</span><span class="pun">.</span><span class="pln">readline</span><span class="pun">())</span><span class="pln">
     </span><span class="kwd">return</span><span class="pln"> f

</span><span class="com"># أنشئ النُسخ</span><span class="pln">
a </span><span class="pun">=</span><span class="pln"> A</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
b </span><span class="pun">=</span><span class="pln"> B</span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="lit">4</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">

</span><span class="com"># احفظ النُسخ</span><span class="pln">
a</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'a.txt'</span><span class="pun">).</span><span class="pln">close</span><span class="pun">()</span><span class="pln"> </span><span class="com"># تذكر أن تغلق الملف</span><span class="pln">
b</span><span class="pun">.</span><span class="pln">save</span><span class="pun">(</span><span class="str">'b.txt'</span><span class="pun">).</span><span class="pln">close</span><span class="pun">()</span><span class="pln">

</span><span class="com"># اجلب النسخ</span><span class="pln">
newA </span><span class="pun">=</span><span class="pln"> A</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">
newA</span><span class="pun">.</span><span class="pln">restore</span><span class="pun">(</span><span class="str">'a.txt'</span><span class="pun">).</span><span class="pln">close</span><span class="pun">()</span><span class="pln"> </span><span class="com"># تذكر أن تغلق الملف</span><span class="pln">
newB </span><span class="pun">=</span><span class="pln"> B</span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">8</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln">
newB</span><span class="pun">.</span><span class="pln">restore</span><span class="pun">(</span><span class="str">'b.txt'</span><span class="pun">).</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"A: "</span><span class="pun">,</span><span class="pln">newA</span><span class="pun">.</span><span class="pln">x</span><span class="pun">,</span><span class="pln">newA</span><span class="pun">.</span><span class="pln">y </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"B: "</span><span class="pun">,</span><span class="pln">newB</span><span class="pun">.</span><span class="pln">x</span><span class="pun">,</span><span class="pln">newB</span><span class="pun">.</span><span class="pln">y</span><span class="pun">,</span><span class="pln">newB</span><span class="pun">.</span><span class="pln">z </span><span class="pun">)</span></pre>

<p>
	نلاحظ أن القيم المطبوعة هي القيم المسترجعة، وليست القيم التي استخدمناها لإنشاء النسخ.
</p>

<p>
	والمهم هنا هو إعادة كتابة التابع save والتابع restore في كل صنف واستدعاء التابع الرئيسي في خطوة أولى، ثم لا نتعامل في الصنف الفرعي إلا مع سمات ذلك الفرعي فقط، ومن البديهي أن تحويل السمة إلى سلسلة نصية وحفظها أمر متروك لك كونك مبرمجًا، لكن يجب إخراجها على سطر واحد، أما عند الاستعادة فببساطة يمكن عكس عملية التخزين، لكن تظهر هنا عقبة كبيرة في هذا الأسلوب، وهي أننا نحتاج إلى إنشاء ملف منفصل لكل كائن، وهذا قد يعني آلاف الملفات الصغيرة إذا كنا في بيئة برمجية لسوق حقيقي، حيث سيتعقد العمل بوتيرة متسارعة، وسنحتاج إلى استخدام <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D9%81%D9%8A-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87%D8%A7-r519/" rel="">قاعدة بيانات</a> لحفظ الكائنات، وسنبحث في ذلك في مقال لاحق، أما الآن فيكفي أن تعلم أن المفاهيم الأساسية ستظل كما هي.
</p>

<h2>
	دمج الأصناف والوحدات
</h2>

<p>
	توفر الأصناف والوحدات آليات للتحكم في تعقيد البرنامج، ومن المنطقي مع ازدياد حجم البرنامج ازدياد الحاجة إلى دمج المزايا بوضع أصناف داخل وحدات، وتنصح بعض الهيئات بوضع كل صنف في وحدة منفصلة، لكن هذا يؤدي إلى وحدات كثيرة جدًا ويزيد التعقيد بدلًا من تقليله، والبديل الذي لدينا هو تجميع الأصناف معًا، ووضع المجموعة في وحدة، وإذا عدنا إلى مثالنا أعلاه فسنضع كل تعريفات أصناف الحساب المصرفي في وحدة واحدة هي <code>bankaccount</code> مثلًا، ثم ننشئ وحدةً منفصلةً لشيفرة التطبيق التي تستخدم الوحدة.
</p>

<p>
	يمكن تمثيل ذلك مرئيًا بواسطة UML بطريقتين، حيث يمكن تمثيل الجمع المنطقي للأصناف باستخدام حزمة، أو نستطيع تمثيل الملف الحقيقي مثل مكوّن:
</p>

<p style="text-align: center;">
	<img alt="component-package-uml.png" class="ipsImage ipsImage_thumbnailed" data-fileid="83269" data-unique="lwu302vp6" src="https://academy.hsoub.com/uploads/monthly_2021_11/component-package-uml.png.a64157652133fa5223b9eb72e1609a4d.png">
</p>

<p>
	والهدف هنا أن تبدو أيقونة الحزمة مثل مجلد في أي برنامج مدير ملفات، أما الأيقونة الصغيرة التي في أعلى اليمين في أيقونة المكون فهي رمز المكون القديم في UML، وبما أن رسمها صعب في المخططات عند رسم الخطوط التي تظهر العلاقات بين المكونات فقد صغِّر شكلها في UML 2.0.
</p>

<p>
	هذا ما سنغطيه حول UML في هذه السللسلة، ويمكن الرجوع لمحركات البحث والويب للاستزادة من المراجع والتدريبات وأدوات رسم UML، رغم أن الأشكال سهلة الرسم في أي برنامج رسم متجهي.
</p>

<p>
	إذا أردنا تمثيلًا بسيطًا لذلك التصميم فسيكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_53" style=""><span class="pun">#</span><span class="pln"> </span><span class="typ">File</span><span class="pun">:</span><span class="pln"> bankaccount</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">#</span><span class="pln">
</span><span class="pun">#</span><span class="pln"> </span><span class="typ">Implements</span><span class="pln"> a </span><span class="kwd">set</span><span class="pln"> of bank account classes
</span><span class="pun">###################</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">BankAccount</span><span class="pun">:</span><span class="pln"> </span><span class="pun">....</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">InterestAccount</span><span class="pun">:</span><span class="pln"> </span><span class="pun">...</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ChargingAccount</span><span class="pun">:</span><span class="pln"> </span><span class="pun">...</span></pre>

<p>
	ثم إذا أردنا استخدامه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_55" style=""><span class="kwd">import</span><span class="pln"> bankaccount

newAccount </span><span class="pun">=</span><span class="pln"> bankaccount</span><span class="pun">.</span><span class="typ">BankAccount</span><span class="pun">(</span><span class="lit">50</span><span class="pun">)</span><span class="pln">
newChrgAcct </span><span class="pun">=</span><span class="pln"> bankaccount</span><span class="pun">.</span><span class="typ">ChargingAccount</span><span class="pun">(</span><span class="lit">200</span><span class="pun">)</span><span class="pln">


</span><span class="pun">#</span><span class="pln"> </span><span class="pun">هنا</span><span class="pln"> </span><span class="pun">يمكن</span><span class="pln"> </span><span class="pun">تنفيذ</span><span class="pln"> </span><span class="pun">المهام</span><span class="pln"> </span><span class="pun">التي</span><span class="pln"> </span><span class="pun">تريدها</span></pre>

<p>
	لكن ماذا لو أراد صنفان في وحدتين الوصول إلى بيانات بعضهما بعضًا؟ إن أبسط حل لهذا هو استيراد كلتا الوحدتين وإنشاء نُسخ للأصناف التي نريدها، وتمرير نُسخ أحد الصنفين إلى توابع النسخة الأخرى، وتمرير الكائنات كاملةً من مكان لآخر ما هو إلا برمجة كائنية التوجه، وهنا ندرك أحد أسباب التسمية لهذا النوع من البرمجة، فلا نحتاج إلى استخراج سمات كائن وتمريرها إلى كائن آخر، بل نمرر الكائن كله، وإذا كان الكائن يستخدم رسالةً متعددة الأشكال للوصول إلى المعلومات التي يحتاج إليها فسيصلح التابع مع أي نوع من الكائنات التي تدعم الرسالة.
</p>

<p>
	لننظر في مثال واقعي لتوضيح ذلك، حيث ننشئ وحدةً قصيرةً نسميها <code>logger</code> تحتوي صنفين، هما <code>Logger</code> الذي يسجل النشاط داخل ملف، ويحتوي هذا الصنف على تابع واحد هو <code>log()‎</code> الذي يأخذ معاملًا كائنًا قابلًا للتسجيل، أما الصنف الآخر فهو <code>Loggable</code> الذي تستطيع الأصناف الأخرى أن ترثه لتعمل مع logger:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9113_57" style=""><span class="com"># File: logger.py</span><span class="pln">
</span><span class="com">#</span><span class="pln">
</span><span class="com"># Create Loggable and Logger classes for logging activities </span><span class="pln">
</span><span class="com"># of objects</span><span class="pln">
</span><span class="com">############</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Loggable</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> activity</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"This needs to be overridden locally"</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Logger</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> logfilename </span><span class="pun">=</span><span class="pln"> </span><span class="str">"logger.dat"</span><span class="pun">):</span><span class="pln">
       self</span><span class="pun">.</span><span class="pln">_log </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">logfilename</span><span class="pun">,</span><span class="str">"a"</span><span class="pun">)</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> log</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> loggedObj</span><span class="pun">):</span><span class="pln">
       self</span><span class="pun">.</span><span class="pln">_log</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">loggedObj</span><span class="pun">.</span><span class="pln">activity</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> __del__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
       self</span><span class="pun">.</span><span class="pln">_log</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	نلاحظ أننا وفرنا تابع تدمير destructor هو <code>__del__</code> لإغلاق الملف عند حذف كائن التسجيل أو كنسه garbage collected، وهو أحد التوابع السحرية الموجودة في بايثون كما نرى من الشرطتين السفليتين حوله، واللتين تشبهان <code>‎__init__()‎</code>، مع فرق أن <code>init</code> يُستدعى عند إنشاء نسخة ما، أما <code>del</code> فيستدعى عندما يحذف كانس المخلفات النسخة، وقد لا يُستدعى إذا خرجت بايثون خروجًا غير متوقع، حيث سيكون لدينا في هذه الحالة مشاكل أكبر من استدعاء <code>del</code> أو عدم استدعائه.
</p>

<p>
	كما استدعينا سمة السجل <code>‎_log</code> مع شرطة سفلية قبلها، وهو اصطلاح للتسمية في بايثون، كما في استخدام الكلمات ذات الأحرف الكبيرة لأسماء الأصناف، فالشرطة السفلية المفردة تعني أن السمة ليست مصممةً لنصل إليها مباشرةً، بل من خلال توابع الصنف.
</p>

<p>
	سننشئ الآن وحدةً جديدةً تعرِّف النسخ القابلة للتسجيل لأصناف حساباتنا المصرفية السابقة، لنستطيع استخدام وحدتنا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9113_59" style=""><span class="com"># File: loggablebankaccount.py</span><span class="pln">
</span><span class="com">#</span><span class="pln">
</span><span class="com"># Extend Bank account classes to work with logger module.</span><span class="pln">
</span><span class="com">###############################</span><span class="pln">

import bankaccount</span><span class="pun">,</span><span class="pln"> logger

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">LoggableBankAccount</span><span class="pun">(</span><span class="pln">bankaccount</span><span class="pun">.</span><span class="typ">BankAccount</span><span class="pun">,</span><span class="pln"> logger</span><span class="pun">.</span><span class="typ">Loggable</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> activity</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Account balance = %d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">LoggableInterestAccount</span><span class="pun">(</span><span class="pln">bankaccount</span><span class="pun">.</span><span class="typ">InterestAccount</span><span class="pun">,</span><span class="pln">
                              logger</span><span class="pun">.</span><span class="typ">Loggable</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> activity</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Account balance = %d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">LoggableChargingAccount</span><span class="pun">(</span><span class="pln">bankaccount</span><span class="pun">.</span><span class="typ">ChargingAccount</span><span class="pun">,</span><span class="pln">
                              logger</span><span class="pun">.</span><span class="typ">Loggable</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> activity</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Account balance = %d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span></pre>

<p>
	استخدمنا الوراثة المتعددة في المثال أعلاه، حيث ورثنا صنفين رئيسيين وليس صنفًا واحدًا، وهذا غير ضروري في بايثون بما أننا نستطيع إضافة التابع <code>activity()‎</code> إلى أصنافنا الأصلية ونحقق نفس الأثر، أما في لغات برمجة كائنية التوجه ثابتة مثل <a href="https://academy.hsoub.com/programming/android/%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d8%a9-%d9%83%d8%a7%d8%a6%d9%86%d9%8a%d8%a9-%d8%a7%d9%84%d8%aa%d9%88%d8%ac%d9%87%d8%8c-%d8%a7%d9%84%d9%85%d8%aa%d8%ba%d9%8a%d8%b1%d8%a7%d8%aa%d8%8c-%d8%a7%d9%84%d8%ac%d9%85%d9%84-%d8%a7%d9%84%d8%b4%d8%b1%d8%b7%d9%8a%d8%a9-%d9%88%d8%a7%d9%84%d8%ad%d9%84%d9%82%d8%a7%d8%aa-%d9%81%d9%8a-%d8%ac%d8%a7%d9%81%d8%a7-r310/" rel="">جافا</a> أو C++‎ فسيكون هذا ضروريًا، لذا سنشرح التقنية هنا، قد تلاحظ أن التابع <code>activity()‎</code> متطابق في الأصناف الثلاثة، وهذا يعني أننا نستطيع توفير بعض الكتابة على أنفسنا بإنشاء نوع وسيط من صنف حساب قابل للتسجيل يرث <code>Loggable</code> وله تابع <code>activity</code> فقط، ثم ننشئ ثلاثة أنواع حسابات قابلة للتسجيل بوراثتها من ذلك الصنف الجديد ومن صنف <code>Loggable</code>، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9113_61" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">LoggableAccount</span><span class="pun">(</span><span class="pln">logger</span><span class="pun">.</span><span class="typ">Loggable</span><span class="pun">):</span><span class="pln">
     </span><span class="kwd">def</span><span class="pln"> activity</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
         </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Account balance = %d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">checkBalance</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">LoggableBankAccount</span><span class="pun">(</span><span class="pln">bankaccount</span><span class="pun">.</span><span class="typ">BankAccount</span><span class="pun">,</span><span class="pln"> </span><span class="typ">LoggableAccount</span><span class="pun">):</span><span class="pln">
     pass

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">LoggableInterestAccount</span><span class="pun">(</span><span class="pln">bankaccount</span><span class="pun">.</span><span class="typ">InterestAccount</span><span class="pun">,</span><span class="pln"> </span><span class="typ">LoggableAccount</span><span class="pun">):</span><span class="pln">
     pass

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">LoggableChargingAccount</span><span class="pun">(</span><span class="pln">bankaccount</span><span class="pun">.</span><span class="typ">ChargingAccount</span><span class="pun">,</span><span class="pln"> </span><span class="typ">LoggableAccount</span><span class="pun">):</span><span class="pln">
     pass</span></pre>

<p>
	لا يوفر هذا علينا الكثير من الكتابة، لكنه يعني أن علينا اختبار تعريف تابع واحد فقط والاحتفاظ به بدلًا من ثلاثة توابع متطابقة، وهذا النوع من البرمجة الذي يكون فيه لصنف رئيسي وظيفةً مشتركةً يسمى بالبرمجة الخليطة mixin programming، ويسمى الصنف الأدنى بالصنف الخليط mixin class، والناتج المتوقع من ذلك الأسلوب أن يكون لتعريفات الصنف النهائي متن صغير أو ليس لها متن أصلًا، لكنها تحوي قائمةً طويلةً من الأصناف الموروثة كما رأينا هنا.
</p>

<p>
	ومن الشائع أيضًا أن الأصناف المختلطة لا ترث من أي شيء بنفسها، رغم أننا فعلنا هذا هنا، فما هي إلا طريقة لإضافة تابع مشترك أو مجموعة من التوابع إلى صنف أو مجموعة أصناف باستخدام الوراثة، ويأتي مصطلح المختلطة mixin، من مجال صناعة المثلجات، حيث تضاف نكهات مختلفة إلى الفانيليا لإنتاج نكهة جديدة، وكانت أول لغة تدعم هذا الأسلوب هي لغة Flavors، والتي كانت إحدى لغات Lisp المشهورة وقتها.
</p>

<p>
	نأتي الآن إلى النقطة التي نُظهر فيها شيفرة التطبيق الخاص بنا بإنشاء كائن مسجل logger وبعض الحسابات المصرفية، ثم تمرير الحسابات إلى المسجل، رغم أنها معرّفة في وحدات مختلفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_66" style=""><span class="pun">#</span><span class="pln"> </span><span class="typ">Test</span><span class="pln"> logging and loggable bank accounts</span><span class="pun">.</span><span class="pln">
</span><span class="pun">#############</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> logger
</span><span class="kwd">import</span><span class="pln"> loggablebankaccount as lba

log </span><span class="pun">=</span><span class="pln"> logger</span><span class="pun">.</span><span class="typ">Logger</span><span class="pun">()</span><span class="pln">

ba </span><span class="pun">=</span><span class="pln"> lba</span><span class="pun">.</span><span class="typ">LoggableBankAccount</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln">
ba</span><span class="pun">.</span><span class="pln">deposit</span><span class="pun">(</span><span class="lit">700</span><span class="pun">)</span><span class="pln">
log</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">ba</span><span class="pun">)</span><span class="pln">

intacc </span><span class="pun">=</span><span class="pln"> lba</span><span class="pun">.</span><span class="typ">LoggableInterestAccount</span><span class="pun">(</span><span class="lit">200</span><span class="pun">)</span><span class="pln">
intacc</span><span class="pun">.</span><span class="pln">deposit</span><span class="pun">(</span><span class="lit">500</span><span class="pun">)</span><span class="pln">
log</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">intacc</span><span class="pun">)</span></pre>

<p>
	نلاحظ هنا كلمة <code>as</code> المفتاحية التي تُستخدم لإنشاء اسم مختصر عند استدعاء <code>loggablebankaccount</code>.
</p>

<p>
	لا نحتاج إلى استخدام سابقة الوحدة module prefix بعد إنشاء النسخ المحلية، وبما أنه لا يوجد وصول مباشر من كائن إلى آخر بل من خلال الرسائل، فلا حاجة أن تشير وحدتا تعريف الصنف إلى بعضهما البعض مباشرةً، كما يعمل المسجل مع نسخ كل من <code>LoggableBankAccount</code> و<code>LoggableInterestAccount</code> لأنهما يدعمان واجهة <code>Loggable</code>، فالتوافق بين واجهات الكائنات من خلال تعددية الأشكال هو الأساس الذي تبنى عليه جميع البرامج الكائنية التوجه.
</p>

<p>
	يوجد نظام تسجيل أكثر تعقيدًا في وحدة المكتبة القياسية <code>logging</code>، لإظهار بعض التقنيات فقط، ونذكره هنا لتكون هذه المكتبة أول خيار نبحث فيه عند الحاجة إلى أدوات تسجيل في البرامج التي نكتبها.
</p>

<p>
	نأمل أن يكون هذا الشرح كافيًا لفهم البرمجة كائنية التوجه، مع الاستزادة من المصادر الموجودة في الويب أو قراءة أحد الكتب المذكورة في بداية المقال، أما الآن فسننظر في كيفية تنفيذ البرمجة كائنية التوجه في جافاسكربت وVBScript.
</p>

<h2>
	البرمجة الكائنية في VBScript
</h2>

<p>
	تدعم VBScript مفهوم الكائنات وتسمح بتعريف الأصناف وإنشاء نسخ منها، لكنها لا تدعم مفهوم الوراثة ولا تعددية الأشكال، وعلى هذا تكون لغة VBScript لغةً كائنية الأساس object based وليست كائنية التوجه، لكن مفهوم دمج البيانات والدوال في كائن واحد لا يزال صالحًا هنا، ويمكن تنفيذ صورة محدودة من الوراثة باستخدام تقنية تسمى التفويض delegation.
</p>

<h3>
	تعريف الأصناف
</h3>

<p>
	يُعرَّف الصنف في VBScript باستخدام تعليمة <code>Class</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_68" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">VBScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Class</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pln">
   </span><span class="typ">Private</span><span class="pln"> anAttribute
   </span><span class="typ">Public</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln"> aMethodWithNoReturnValue</span><span class="pun">()</span><span class="pln">
       </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"MyClass.aMethodWithNoReturnValue"</span><span class="pln">
   </span><span class="typ">End</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln">
   </span><span class="typ">Public</span><span class="pln"> </span><span class="typ">Function</span><span class="pln"> aMethodWithReturnValue</span><span class="pun">()</span><span class="pln">
       </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"MyClass.aMethodWithReturnValue"</span><span class="pln">
       aMethodWithReturnValue </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
   </span><span class="typ">End</span><span class="pln"> </span><span class="typ">Function</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">Class</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	وهذا يعرِّف صنفًا جديدًا اسمه <code>MyClass</code> مع سمة تسمى <code>anAttribute</code> تكون مرئيةً فقط للتوابع التي في الصنف، كما نرى من كلمة <code>Private</code> المفتاحية، ومن المتعارف عليه أن نصرح عن سمات البيانات بأنها <code>Private</code>، وعن أغلب التوابع بأنها <code>Public</code>، ويُعرف هذا باسم إخفاء البيانات، وميزته أنه يسمح لنا بالتحكم في الوصول إلى البيانات بإجبار استخدام التوابع التي تتحقق من جودة البيانات على القيم التي تمرَّر إلى داخل وخارج الكائن، وتوفر بايثون آليةً خاصةً بها لتنفيذ هذا لكنها خارج نطاق شرحنا.
</p>

<h3>
	إنشاء النسخ
</h3>

<p>
	ننشئ النسخ في VBScript بدمج الكلمتين المفتاحيتين <code>Set</code> و<code>New</code>، ويجب أن يكون المتغير الذي أُسندت إليه النسخة الجديدة قد صرِّح عنه باستخدام كلمة <code>Dim</code> كما هو متبع في VBScript:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_71" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">VBScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> anInstance
</span><span class="typ">Set</span><span class="pln"> anInstance </span><span class="pun">=</span><span class="pln"> </span><span class="typ">New</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	يؤدي هذا إلى إنشاء نسخة من الصنف مصرح عنها في القسم السابق وإسنادها إلى متغير <code>anInstance</code>، لاحظ أننا يجب أن نسبق اسم المتغير بـ <code>Set</code>، وأننا نستخدم كلمة <code>New</code> لإنشاء الكائن.
</p>

<h3>
	إرسال الرسائل
</h3>

<p>
	تُرسَل الرسائل إلى النسخ باستخدام نفس الصيغة النقطية <code>.</code> التي تستخدمها بايثون:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_74" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">VBScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> aValue
anInstance</span><span class="pun">.</span><span class="pln">aMethodWithNoReturnValue</span><span class="pun">()</span><span class="pln">
aValue </span><span class="pun">=</span><span class="pln"> anInstance</span><span class="pun">.</span><span class="pln">aMethodWithReturnValue</span><span class="pun">()</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"aValue = "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> aValue
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	يُستدعى التابعان المصرح عنهما في تعريف الصنف، ولا توجد في الحالة الأولى قيمة معادة، أما في الحالة الثانية فسنسند القيمة المعادة إلى المتغير <code>aValue</code>، ولا يوجد شيء غير اعتيادي هنا باستثناء أن البرنامج الفرعي subroutine والدالة مسبوقان باسم النسخة.
</p>

<h3>
	الوراثة وتعددية الأشكال
</h3>

<p>
	لا تدعم VBScript أي آلية للوراثة أو تعددية الأشكال، لكن نستطيع محاكاة ذلك إلى حد ما باستخدام تقنية تسمى التفويض، وهذا يعني أننا نعرف سمةً للصنف الفرعي ليكون نسخةً من الصنف الرئيسي المفترض، ثم نعرف تابعًا لجميع التوابع الموروثة التي تستدعي تابع النسخة الرئيسية أو تفوض إليه، لننشئ صنفًا فرعيًا من <code>MyClass</code> كما هو معرَّف أعلاه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_76" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">VBScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Class</span><span class="pln"> </span><span class="typ">SubClass</span><span class="pln">
   </span><span class="typ">Private</span><span class="pln"> parent
   </span><span class="typ">Private</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln"> </span><span class="typ">Class_Initialize</span><span class="pun">()</span><span class="pln">
      </span><span class="typ">Set</span><span class="pln"> parent </span><span class="pun">=</span><span class="pln"> </span><span class="typ">New</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pln">
   </span><span class="typ">End</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln">
   </span><span class="typ">Public</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln"> aMethodWithNoReturnValue</span><span class="pun">()</span><span class="pln">
      parent</span><span class="pun">.</span><span class="pln">aMethodWithNoREturnVAlue
   </span><span class="typ">End</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln">
   </span><span class="typ">Public</span><span class="pln"> </span><span class="typ">Function</span><span class="pln"> aMethodWithReturnValue</span><span class="pun">()</span><span class="pln">
      aMethodWithReturnValue </span><span class="pun">=</span><span class="pln"> parent</span><span class="pun">.</span><span class="pln">aMethodWithReturnValue
   </span><span class="typ">End</span><span class="pln"> </span><span class="typ">Function</span><span class="pln">
   </span><span class="typ">Public</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln"> aNewMethod
      </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"This is unique to the sub class"</span><span class="pln">
   </span><span class="typ">End</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">Class</span><span class="pln">

</span><span class="typ">Dim</span><span class="pln"> inst</span><span class="pun">,</span><span class="pln">aValue
</span><span class="typ">Set</span><span class="pln"> inst </span><span class="pun">=</span><span class="pln"> </span><span class="typ">New</span><span class="pln"> </span><span class="typ">SubClass</span><span class="pln">
inst</span><span class="pun">.</span><span class="pln">aMethodWithNoReturnVAlue
aValue </span><span class="pun">=</span><span class="pln"> inst</span><span class="pun">.</span><span class="pln">aMethodWithReturnValue
inst</span><span class="pun">.</span><span class="pln">aNewMethod
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"aValue = "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">CStr</span><span class="pun">(</span><span class="pln">aValue</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	نلاحظ هنا استخدام السمة الخاصة <code>parent</code> والتابع الخاص المميز <code>Class_Initialise</code>، فالأولى هي سمة تفويض الصنف الأب، والثاني هو المكافئ للتابع <code>__init__</code> في بايثون لبدء النسخ عند إنشائها، أي أنه الباني في لغة VBScript.
</p>

<h2>
	البرمجة الكائنية في جافاسكربت
</h2>

<p>
	تدعم جافاسكربت الكائنات باستخدام تقنية تسمى النمذجة الأولية prototyping، وهذا يعني عدم وجود بنية صنف صريحة في جافاسكربت، بل نستطيع تعريف الصنف بمجموعة من الدوال أو مثل مفهوم شبيه بالقاموس يُعرف بالمهيئ initializer.
</p>

<h3>
	تعريف الأصناف
</h3>

<p>
	من أكثر الطرق شيوعًا لتعريف الأصناف في جافاسكربت هي إنشاء دالة بنفس اسم الصنف، ويكون هو الباني، لكنه لا يُحتوى داخل أي بنية أخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_78" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">JavaScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pun">(</span><span class="pln">theAttribute</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">anAttribute </span><span class="pun">=</span><span class="pln"> theAttribute</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ربما تلاحظ كلمة <code>this</code> التي تُستخدم بنفس طريقة استخدام <code>self</code> في بايثون مثل مرجع نائب placeholder reference إلى النسخة الحالية، رغم أننا لا نحتاج في الغالب إلى إدراج <code>this</code> صراحةً في قائمة المعامِلات لتوابع الصنف، ونستطيع إضافة سمات جديدة إلى الصنف لاحقًا باستخدام السمة <code>prototype</code> المضمَّنة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_80" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">JavaScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">MyClass</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">newAttribute </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ويعرِّف هذا سمةً جديدةً لـ <code>MyClass</code> اسمها <code>newAttribute</code>، وتضاف التوابع من خلال تعريف دالة عادية؛ ثم إسناد اسم الدالة إلى سمة جديدة مع اسم التابع، ويكون للتابع والدالة نفس الاسم عادةً، لكن لا مانع من تغيير اسم التابع إلى شيء مختلف، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_82" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">JavaScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> oneMethod</span><span class="pun">(){</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">anAttribute</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="typ">MyClass</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">getAttribute </span><span class="pun">=</span><span class="pln"> oneMethod</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> printIt</span><span class="pun">(){</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">anAttribute </span><span class="pun">+</span><span class="pln"> </span><span class="str">"&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="typ">MyClass</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">printIt </span><span class="pun">=</span><span class="pln"> printIt</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ولا شك أن الأسهل تعريف الدوال ثم الباني، ثم إسناد التوابع داخل الباني، وهذا هو الأسلوب الافتراضي، لذا سيبدو تعريف الصنف كاملًا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_84" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">JavaScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> oneMethod</span><span class="pun">(){</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">anAttribute</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> printIt</span><span class="pun">(){</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">anAttribute </span><span class="pun">+</span><span class="pln"> </span><span class="str">"&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pun">(</span><span class="pln">theAttribute</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">anAttribute </span><span class="pun">=</span><span class="pln"> theAttribute</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">getAttribute </span><span class="pun">=</span><span class="pln"> oneMethod</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">printIt </span><span class="pun">=</span><span class="pln"> printIt</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لكن ثمة طريقة أخرى في جافاسكربت، باستخدام صيغة مختلفة قليلًا لإنشاء دوال التابع، حيث تسمح جافاسكربت بتعريف الدالة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_86" style=""><span class="pln">square </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">x</span><span class="pun">){</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x</span><span class="pun">;}</span></pre>

<p>
	ثم نستدعي ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_88" style=""><span class="pln">document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"The square of 5 is: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> square</span><span class="pun">(</span><span class="lit">5</span><span class="pun">))</span></pre>

<p>
	فإذا طبقناه على تعريف الصنف الخاص بنا نحصل على:
</p>

<pre class="ipsCode">&lt;script type=text/JavaScript&gt;
function MyClass(theAttribute)
{
   this.anAttribute = theAttribute;
   this.getAttribute = function(){
                       return this.anAttribute;
                       };
   this.printIt = function printIt(){
                  document.write(this.anAttribute + "&lt;BR&gt;");
                  };
};
&lt;/script&gt;
</pre>

<p>
	يفضل بعض المبرمجين هذا الأسلوب لأنه يبقي تعريفات التابع داخل الصنف دون تلويث فضاء الاسم الخارجي، بينما يرى آخرون أن هذا أسلوب فوضوي وأصعب في القراءة، وأنت حر في اختيار أي الأسلوبين تفضل.
</p>

<h3>
	إنشاء النسخ
</h3>

<p>
	تُنشأ نسخ الأصناف باستخدام كلمة <code>new</code> المفتاحية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_90" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">JavaScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> anInstance </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pun">(</span><span class="lit">42</span><span class="pun">);</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	مما ينشئ نسخةً جديدةً اسمها <code>anInstance</code>.
</p>

<h3>
	إرسال الرسائل
</h3>

<p>
	لا يختلف إرسال الرسائل في جافاسكربت عن اللغات الأخرى، إذ نستخدم الصيغة النقطية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_92" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">JavaScript</span><span class="pun">&gt;</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"The attribute of anInstance is: &lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
anInstance</span><span class="pun">.</span><span class="pln">printIt</span><span class="pun">();</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<h3>
	الوراثة وتعددية الأشكال
</h3>

<p>
	يمكن استخدام آلية النمذجة الأولية في جافاسكربت للوراثة من صنف آخر -على عكس VBScript-، مع أنها أعقد من تقنية بايثون لكن يمكن التعامل معها وضبطها، لكنها ليست منتشرةً بين مبرمجي جافاسكربت، إن أساس الوراثة في جافاسكربت هو الكلمة المفتاحية <code>prototype</code> التي استخدمناها في التمرير في الشيفرة أعلاه، حيث يمكن إضافة مزايا إلى كائن ما بعد تعريفه، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_94" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Message</span><span class="pun">(</span><span class="pln">text</span><span class="pun">){</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">text </span><span class="pun">=</span><span class="pln"> text</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">say </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
        document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">text </span><span class="pun">+</span><span class="pln"> </span><span class="str">'&lt;br&gt;'</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

msg1 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Message</span><span class="pun">(</span><span class="str">'This is the first'</span><span class="pun">);</span><span class="pln">
msg1</span><span class="pun">.</span><span class="pln">say</span><span class="pun">();</span><span class="pln">

</span><span class="typ">Message</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">shout </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
    alert</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">text</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

msg2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Message</span><span class="pun">(</span><span class="str">'This gets the new feature'</span><span class="pun">);</span><span class="pln">
msg2</span><span class="pun">.</span><span class="pln">shout</span><span class="pun">();</span><span class="pln">

</span><span class="com">/* msg1 وبالمثل بالنسبة لـ ...*/</span><span class="pln">
msg1</span><span class="pun">.</span><span class="pln">shout</span><span class="pun">();</span><span class="pln">

</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	الملاحظة الأولى: أضفنا تابع <code>alert</code> جديد باستخدام <code>prototype</code> بعد إنشاء نسخة <code>msg1</code> للصنف، غير أن الخاصية كانت متاحةً للنسخة الحالية ونسخة <code>msg2</code> التي أنشئت بعد الإضافة، أي أن الخاصية الجديدة تضاف إلى جميع نسخ <code>Message</code> الحالية والجديدة، وتؤدي خاصية النمذجة الأولية هذه إلى إمكانية تغيير سلوك كائنات جافاسكربت المضمَّنة، بإضافة مزايا جديدة أو تغيير الطريقة التي تتصرف بها المزايا الحالية، لذا استخدمها بحرص إذا لم ترد أن تضيع وقتك مع زلات برمجية يصعب تعقبها. ومع ذلك لاستخدام <code>prototype</code> آليةً لإضافة وظائف إلى الأصناف الحالية عيوبه، التي منها تغيير سلوك النسخة الحالية، وتغيير تعريف الصنف الأصلي. ويوجد أسلوب تقليدي أكثر من الوراثة يمكن استخدامه، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_96" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Parent</span><span class="pun">(){</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Parent'</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">basemethod </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
       alert</span><span class="pun">(</span><span class="str">'This is the parent'</span><span class="pun">);</span><span class="pln">
       </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Child</span><span class="pun">(){</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Parent</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">parent</span><span class="pun">();</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">submethod </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
       alert</span><span class="pun">(</span><span class="str">'This from the child'</span><span class="pun">);</span><span class="pln">
       </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> aParent </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Parent</span><span class="pun">();</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> aChild </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Child</span><span class="pun">();</span><span class="pln">

aParent</span><span class="pun">.</span><span class="pln">basemethod</span><span class="pun">();</span><span class="pln">
aChild</span><span class="pun">.</span><span class="pln">submethod</span><span class="pun">();</span><span class="pln">
aChild</span><span class="pun">.</span><span class="pln">basemethod</span><span class="pun">();</span><span class="pln">

</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	يجب أن نلاحظ أن كائن <code>child</code> هنا له وصول إلى <code>basemethod</code>، دون أن يُعطى ذلك الوصول صراحةً، وإنما يرثه من الصنف الرئيسي بحكم أسطر الإسناد/الاستدعاء داخل تعريف الصنف <code>Child</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_98" style=""><span class="pln">   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Parent</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">parent</span><span class="pun">();</span></pre>

<p>
	وبهذا نكون ورثنا <code>basemethod</code> من الصنف الرئيسي <code>Parent</code>.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<h3 data-gramm="false">
		الخلاف حول جافاسكربت
	</h3>

	<p>
		لجافاسكربت سمعة سيئة وسط المبرمجين لأسباب كثيرة، أحدها إمكانية إنشاء كائنات دون استخدام الكلمة المفتاحية <code>new</code>، ودون إرسال أي خطأ، لذا ستكون النتيجة غير التي نريدها، وسنواجه زلات برمجيةً يصعب إيجادها، أحد أسبابها أن جافاسكربت ليس لديها مفهوم الصنف نفسه، وإنما تحاكيه محاكاةً فقط من خلال آلية النموذج الأولي، وليتغلب مبرمجو جافاسكربت على هذه المشكلة طوروا بعض المصطلحات التي تنتج شيفرات أكثر موثوقيةً، لكن تفسيرها يتطلب بعض المفاهيم المتقدمة من علوم الحاسوب التي يقصر عنها شرحنا، فإذا أردت استخدام جافاسكربت للبرمجة الكائنية التوجه ننصحك بقراءة الكتاب القصير Javascript the Good Parts الذي كتبه Douglas Crockford، والذي يشرح السبب الذي يجعل التقنيات المشروحة أعلاه غير مثالية، وكيفية تنفيذها بشكل أفضل.
	</p>
</blockquote>

<p>
	يمكن استخدام نفس حيلة التفويض التي استخدمناها في VBScript، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9113_100" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">JavaScript</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> noReturn</span><span class="pun">(){</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">parent</span><span class="pun">.</span><span class="pln">printIt</span><span class="pun">();</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> returnValue</span><span class="pun">(){</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">parent</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">();</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> newMethod</span><span class="pun">(){</span><span class="pln">
      document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"This is unique to the sub class&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">SubClass</span><span class="pun">(){</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">MyClass</span><span class="pun">(</span><span class="lit">27</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">aMethodWithNoReturnValue </span><span class="pun">=</span><span class="pln"> noReturn</span><span class="pun">;</span><span class="pln"> 
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">aMethodWithReturnValue </span><span class="pun">=</span><span class="pln"> returnValue</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">aNewMethod </span><span class="pun">=</span><span class="pln"> newMethod</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> inst</span><span class="pun">,</span><span class="pln"> aValue</span><span class="pun">;</span><span class="pln">
inst </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">SubClass</span><span class="pun">();</span><span class="pln"> </span><span class="com">// عرِّف الصنف الرئيسي </span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"The sub class value is:&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
inst</span><span class="pun">.</span><span class="pln">aMethodWithNoReturnValue</span><span class="pun">();</span><span class="pln">
aValue </span><span class="pun">=</span><span class="pln"> inst</span><span class="pun">.</span><span class="pln">aMethodWithReturnValue</span><span class="pun">();</span><span class="pln">
inst</span><span class="pun">.</span><span class="pln">aNewMethod</span><span class="pun">();</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"aValue = "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> aValue</span><span class="pun">);</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	سنرى استخدام الكائنات والأصناف في دراسات الحالات والفصول التالية، ورغم أنه من الصعب أن يرى المبرمج المبتدئ كيف أن هذه البنية المعقدة تسهل كتابة وفهم البرامج، إلا أننا نأمل أن يتضح هذا المفهوم إذا رأيت استخدام الأصناف في البرامج الحقيقية، على أن ذلك ليس له فائدة كبيرة في البرامج الصغيرة، وإنما سيجعلها أعقد وأطول، لكن كلما زاد حجم البرنامج -أكثر من 100 سطر مثلًا-، فستعين الأصناف والكائنات على تنظيمه وتقليل كمية الشيفرات المكتوبة، ومن المهم أن تعلم أنه من الممكن تعلم البرمجة وكتابة برامج دون الحاجة إلى مفهوم البرمجة الكائنية التوجه أصلًا، فكم من مبرمج كتب برامج دون إنشاء صنف واحد طيلة حياته، لكن إذا استطعت استيعابها فإن فيها مزايا وتقنيات قويةً ومفيدةً.
</p>

<h2>
	خاتمة
</h2>

<p>
	نأمل في نهاية هذا المقال أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		تغلِّف الأصناف البيانات والدوال في كيان واحد.
	</li>
	<li>
		تشبه الأصناف قاطعات البسكويت، حيث تُستخدم لإنشاء النسخ أو الكائنات.
	</li>
	<li>
		تتواصل الكائنات من خلال إرسال رسائل إلى بعضها البعض.
	</li>
	<li>
		عندما يستقبل كائن ما رسالةً فإنه ينفذ تابعًا موافقًا لها.
	</li>
	<li>
		التوابع هي دوال تُخزَّن مثل سمات للصنف.
	</li>
	<li>
		تستطيع الأصناف أن ترث التوابع والبيانات من أصناف أخرى، مما يسهل توسيع إمكانيات الصنف دون تغيير الصنف الأصلي.
	</li>
	<li>
		تعددية الأشكال هي القدرة على إرسال نفس الرسالة إلى عدة أنواع مختلفة من الكائنات، وسيستجيب كل منها بطريقته الخاصة.
	</li>
	<li>
		التغليف وتعددية الأشكال والوراثة كلها خصائص للغات البرمجة كائنية التوجه.
	</li>
	<li>
		تسمى لغة VBScript لغةً كائنية الأساس، لأنها لا تدعم الوراثة وتعددية الأشكال دعمًا كاملًا، رغم دعمها للتغليف.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutclass.htm" rel="external nofollow">للفصل السابع عشر: Object Oriented Programming من كتاب Learning To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AD%D8%AF%D8%AB%D9%8A%D8%A9-event-driven-programming-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D9%82%D8%A9-%D8%A8%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-r1376/" rel="">البرمجة الحدثية Event Driven Programming المساقة بالأحداث</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1374/" rel="">التعابير النمطية في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D8%A7%D9%84%D8%B3%D8%AD%D8%B1%D9%8A%D8%A9-magic-methods-%D9%81%D9%8A-php-r1124/" rel="">التوابع السحرية (Magic Methods) في PHP</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-programming-%D9%81%D9%8A-php-r316/" rel="">البرمجة كائنية التوجه (Object Oriented Programming) في PHP</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/c-sharp/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-programming-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B3%D9%8A-%D8%B4%D8%A7%D8%B1%D8%A8-c-r328/" rel="">البرمجة كائنية التوجه (Object Oriented Programming) في لغة سي شارب #C</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/c-sharp/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B3%D9%8A-%D8%B4%D8%A7%D8%B1%D8%A8-c-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%84%D8%AB-r338/" rel="">تطبيق البرمجة كائنية التوجه في لغة سي شارب #C - الجزء الثالث</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1375</guid><pubDate>Fri, 12 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x628;&#x64A;&#x631; &#x627;&#x644;&#x646;&#x645;&#x637;&#x64A;&#x629; &#x641;&#x64A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1374/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/619d23288b1f6_---.png.c409e468f920355a10da03b1c6ae7c3c.png" /></p>
<p>
	تعرَّف <a href="https://academy.hsoub.com/devops/linux/%d9%85%d9%82%d8%af%d9%85%d8%a9-%d9%81%d9%8a-%d8%a7%d9%84%d8%aa%d8%b9%d8%a7%d8%a8%d9%8a%d8%b1-%d8%a7%d9%84%d9%86%d9%85%d8%b7%d9%8a%d8%a9-regular-expressions-r63/" rel="">التعابير النمطية</a> بأنها مجموعات من المحارف التي تصف مجموعةً أخرى من المحارف أكبر منها، وهي تصف نمط المحارف الذي نستطيع البحث عنه في متن نص ما، وهي تشبه مفهوم المحارف البديلة wildcards المستخدمة في تسمية الملفات على أغلب <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">نظم التشغيل</a>، حيث يمكن استخدام محرف النجمة <code>*</code> لتمثيل أي تسلسل من المحارف في اسم ملف، ولهذا فإن <code>‎*.py</code> تعني أي ملف ينتهي بالامتداد <code>‎.py</code>، بل إن المحارف البديلة ما هي إلا مجموعة فرعية صغيرة من التعابير النمطية.
</p>

<p>
	وتدعم أغلب لغات البرمجة الحديثة التعابير النمطية ضمنيًا، أو لديها مكتبات أو وحدات متاحة للاستخدام في البحث عن النصوص واستبدالها وفقًا لتعابير نمطية، وذلك بسبب الإمكانيات الكبيرة لهذه التعابير، لكن شرحها المفصل هو خارج نطاق حديثنا، وستجد مصادر أخرى تتحدث عنها بتوسع شديد، وننصحك هنا بمراجعة كتب مثل <a href="http://www.oreilly.com/catalog/regex/" rel="external nofollow">كتاب أورايلي في التعابير النمطية</a> وهو باللغة الإنجليزية، إضافةً إلى <a href="https://academy.hsoub.com/search/" rel="">المقالات الموجودة في أكاديمية حسوب</a>.
</p>

<p>
	ولعل إحدى الخصائص المميزة للتعابير النمطية هي أنها تُظهر أوجه التشابه مع البرامج في البنية، فهي أنماط مبنية من وحدات أصغر منها، وتلك الوحدات هي:
</p>

<ul>
	<li>
		محارف منفردة.
	</li>
	<li>
		محارف بديلة.
	</li>
	<li>
		نطاقات أو مجموعات من المحارف، أو مجموعات محاطة بأقواس.
	</li>
</ul>

<p>
	وبما أن المجموعة نفسها ما هي إلا وحدة، فيمكن أن تكون لدينا مجموعات من المجموعات إلى أن نصل إلى مستوى تعقيد كبير، ونستطيع جمع تلك الوحدات بطرق تشبه استخدام التسلسلات أو التكرارات أو العوامل الشرطية في لغات البرمجة، وسننظر في كل منها في حينه، فإضافةً إلى شرح مفهوم التعابير النمطية، سنعرف كيف نستخدمها في <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">برامج بايثون</a>، وننظر كيف تدعمها لغتا VBScript <a href="https://wiki.hsoub.com/JavaScript" rel="external">وجافاسكربت</a>، ولنستطيع تجربة الأمثلة هنا يجب أن نستورد وحدة <code>re</code> ونستخدم التوابع الخاصة بها، وسنفترض أنك استوردتها تلقائيًا دون ذكر ذلك في كل مرة.
</p>

<h2>
	التسلسلات
</h2>

<h3>
	تسلسلات المحارف
</h3>

<p>
	لا شك أن أبسط <a href="https://academy.hsoub.com/programming/javascript/%D8%A8%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r669/" rel="">بنية برمجية</a> يمكن تصورها هي تسلسل من المحارف، كما أن أبسط تعبير نمطي ما هو إلا تسلسل من المحارف كذلك:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_1493_12" style=""><span class="pln">red</span></pre>

<p>
	وهذا سيطابق أو يبحث في سلسلة نصية عن أي حدوث لهذه الأحرف الثلاثة التي تتكون منها كلمة red على الترتيب، وبناءً على ذلك سيجد كلمات مثل red وlettered وcredible، لأنها تحتوي على كلمة red ضمنها. ولنتحكم أكثر في خرج المطابقات، فإننا نوفر بعض المحارف الخاصة التي تُعرف باسم المحارف الوصفية metacharacters للحد من نطاق البحث:
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th style="text-align:center">
				التعبير
			</th>
			<th style="text-align:center">
				المعنى
			</th>
			<th style="text-align:center">
				مثال
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				<code>‎^red</code>
			</td>
			<td style="text-align:center">
				في بداية السطر فقط
			</td>
			<td style="text-align:center">
				<strong>red</strong> ribbons are good
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				<code>red$‎</code>
			</td>
			<td style="text-align:center">
				في نهاية السطر فقط
			</td>
			<td style="text-align:center">
				I love <strong>red</strong>
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				<code>‎\Wred</code>
			</td>
			<td style="text-align:center">
				في بداية الكلمة فقط
			</td>
			<td style="text-align:center">
				it's <strong>red</strong>irected by post
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				<code>‎red\W‎</code>
			</td>
			<td style="text-align:center">
				في نهاية الكلمة فقط
			</td>
			<td style="text-align:center">
				you cove<strong>red</strong> it already
			</td>
		</tr>
	</tbody>
</table>

<p>
	يُطلق على هذه المحارف اسم المرابط anchors لأنها تثبت موضع التعبير النمطي في جملة أو كلمة ما، وهناك عدة مرابط أخرى معرَّفة في توثيق وحدة <code>re</code> يمكنك الاطلاع عليها.
</p>

<h3>
	المحارف البديلة
</h3>

<p>
	قد تحتوي التسلسلات على محارف بديلة Wildcard Characters تحل محل أي محرف، والمحرف البديل هو نقطة <code>.</code>
</p>

<p>
	 جرِّب الشيفرة التالية مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_14" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> re
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'be.t'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'best'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">_sre</span><span class="pun">.</span><span class="pln">SRE_Match object at </span><span class="lit">0x01365AA0</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'be.t'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bess'</span><span class="pun">)</span></pre>

<p>
	تخبرنا الرسالة التي في الأقواس السهمية أن التعبير النمطي <code>'be.t'</code> -الممرَّر وسيطًا أول- يطابق السلسلة <code>'best'</code> الممرَّرة وسيطًا ثانيًا، كما يطابق 'beat' و'bent' و'belt' وغيرها، لكن المثال الثاني لا يطابق لأن <code>'bess'</code> لا تنتهي بحرف <code>t</code>، لذا لا يُنشئ <code>MatchObject</code>. يمكنك تجريب عدة مطابقات أخرى لتفهم كيفية عملها، ولاحظ أن <code>match()‎</code> لا تطابق إلا في بداية السلسلة النصية، أما لمنتصفها فنستخدم <code>search()‎</code> كما سنرى لاحقًا.
</p>

<h3>
	المجالات أو الفئات
</h3>

<p>
	يتكون المجال range (أو الفئة set) من تجميعة من المحارف المغلَّفة في أقواس مربعة، ويبحث التعبير النمطي عن أي محرف يكون داخل هذه الأقواس:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_18" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'s[pwl]am'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'spam'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">_sre</span><span class="pun">.</span><span class="pln">SRE_Match object at </span><span class="lit">0x01365AD8</span><span class="pun">&gt;</span></pre>

<p>
	فهذا سيطابق <code>swam</code> أو <code>slam</code>، لكن لن يطابق <code>sham</code> لأن <code>h</code> غير موجودة في فئة التعبير النمطي.
</p>

<p>
	أما إذا وضعنا محرف الإقحام <code>^</code> أول عنصر في المجموعة، فكأننا نقول أننا نريد البحث عن أي محرف عدا المحارف الموجودة في المجموعة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_20" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'[^f]ool'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cool'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">_sre</span><span class="pun">.</span><span class="pln">SRE_Match object at </span><span class="lit">0x01365AA0</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'[^f]ool'</span><span class="pun">,</span><span class="str">'fool'</span><span class="pun">)</span></pre>

<p>
	وبناءً على ذلك نستطيع مطابقة <code>cool</code> و<code>pool</code>، لكننا لن نطابق <code>fool</code> لأننا نبحث عن أي محرف عدا <code>f</code> في بداية النمط.
</p>

<h3>
	المجموعات
</h3>

<p>
	نستطيع جمع تسلسلات من المحارف أو الوحدات الأخرى معًا من خلال تغليفها بأقواس، وهي لا تقوم بدور العزل هنا، بل تفيدنا عند دمجها مع خصائص التكرار والشرطيات التي سنشرحها لاحقًا.
</p>

<h2>
	التكرار
</h2>

<p>
	يمكن إنشاء تعابير نمطية تطابق تسلسلات مكررةً من المحارف باستخدام بعض المحارف الوصفية الخاصة، ونستطيع البحث بها عن تكرار محرف واحد أو مجموعة محارف:
</p>

<table>
	<thead>
		<tr>
			<th style="text-align:center">
				التعبير
			</th>
			<th style="text-align:center">
				المعنى
			</th>
			<th style="text-align:center">
				مثال
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				'?'
			</td>
			<td style="text-align:center">
				محرف واحد على الأكثر من المحارف السابقة -أي عدد صفر أو واحد من المحارف-، انتبه إلى الجزء الصفري هنا لأنه قد يربكك.
			</td>
			<td style="text-align:center">
				pythonl?y يطابق: <strong>pythony</strong> و<strong>pythonly</strong>
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				'*'
			</td>
			<td style="text-align:center">
				يبحث عن صفر محرف سابق أو أكثر.
			</td>
			<td style="text-align:center">
				<p>
					pythonl*y يطابق ما ذكر في السطر السابق بالإضافة إلى: <strong>pythonlly </strong>و<strong>pythonllly</strong> ...  إلخ
				</p>
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				'+'
			</td>
			<td style="text-align:center">
				يبحث عن محرف واحد أو أكثر من المحارف السابقة.
			</td>
			<td style="text-align:center">
				pythonl+y يطابق: <strong>pythonly</strong> و<strong>pythonlly </strong>و<strong>pythonllly</strong> ...إلخ
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				{n,m}
			</td>
			<td style="text-align:center">
				يبحث عن نطاق من التكرارات من n إلى m من المحارف السابقة.
			</td>
			<td style="text-align:center">
				{ fo{1,2 يطابق : <strong>fo</strong> أو <strong>foo</strong>
			</td>
		</tr>
	</tbody>
</table>

<p>
	يمكن تطبيق جميع محارف التكرار هذه على مجموعات أخرى من المحارف، وبناءً عليه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_22" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'(.an){1,2}s'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cans'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">_sre</span><span class="pun">.</span><span class="pln">SRE_Match object at </span><span class="lit">0x013667E0</span><span class="pun">&gt;</span></pre>

<p>
	يكون النمط هنا <code>‎(.an){1,2}s</code> الذي يقول إن لدينا مجموعةً تتكون من أي محرف متبوع بالحرفين <code>an</code>، ونريد أن نجد مجموعةً أو اثنتين متبوعتين بالحرف <code>s</code>، وسيطابق هذا النمط: cancans وpans وcanpans، لكن لن يطابق bananas لانعدام وجود حرف قبل مجموعة an الثانية فيها. جرب تعديل البحث ليطابق bananas.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>إرشاد</strong>: انظر في محددات التكرار الأخرى، ولا تنس a الإضافية التي في آخر bananas.
	</p>
</blockquote>

<p>
	هناك مشكلة واحدة مع نمط التكرار <code>{m,n}</code>، وهو أنه لا يحد المطابقة لعدد <code>n</code> من الوحدات، وعلى ذلك سيطابق مثال <code>{fo{1,2</code> الذي في الجدول السابق <code>fooo</code> لأنه يطابق <code>foo</code> في بداية <code>fooo</code>، وعليه فإذا أردنا الحد من عدد المحارف المطابَقة، فسنحتاج إلى أن نُتبع تعبير الضرب بمرساة أو نطاق نفي negated range.
</p>

<p>
	وفي حالتنا، فإن <code>[fo{1,2}[^o</code> سيمنع <code>fooo</code> من المطابقة بما أنه يقول طابق حرف <code>o</code> واحد أو حرفين متبوعين بأي شيء غير <code>o</code>، لكن يجب أن يكون متبوعًا بشيء ما، لذا فإن <code>foo</code> لم تَعُد مطابقةً الآن. يوضح هذا الطبيعة المتقلبة للتعابير النمطية، فقد يصعب ضبطها للحصول على الخرج الذي نريده، ويجب أن نضعها تحت اختبارات فاحصة لتجنب الأخطاء.
</p>

<p>
	أما النمط الفعلي المطلوب للسماح بمطابقة <code>foo</code> و<code>foobar</code> مع استثناء <code>fooo</code>، فهو <code>‎'fo{1,2}[^o]*$'‎</code>، وهذا يعني <code>fo</code> أو <code>foo</code> المتبوعين بعدد صفر أو أكثر من حروف <code>o</code> ونهاية السطر، وفي الواقع حتى هذا النمط ليس تامًا وخاليًا من الأخطاء -جرب <code>fooboo</code> مثلًا-، لكن نحتاج أن نشرح بعض العناصر الأخرى قبل أن نحسّنه ونعدل فيه.
</p>

<h3>
	التعابير الجشعة
</h3>

<p>
	يقال إن التعابير النمطية جشعة، أي أن دوال البحث والمطابقة ستطابق كل ما تستطيعه من السلسلة النصية، بدلًا من التوقف عند أول مطابقة تامة، وهذا لا يهم غالبًا، لكننا سنحصل على مطابقات أكثر من المطلوب عند جمع المحارف البديلة مع عوامل التكرار. لننظر في المثال التالي: إذا كان لدينا تعبير نمطي مثل <code>a.*b</code> الذي يقول إننا نريد إيجاد <code>a</code> متبوعًا بأي عدد من المحارف إلى أن نصل إلى حرف <code>b</code>، فستبحث دالة المطابقة من أول <code>a</code> إلى آخر <code>b</code>، مما يعني أنه إذا احتوت سلسلة البحث على أكثر من <code>b</code> فستُضمَّن جميعًا في الجزء‏ ‎<code>*.</code> من التعبير عدا آخر واحدة، وعليه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_24" style=""><span class="pln">re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'a.*b'</span><span class="pun">,</span><span class="str">'abracadabra'</span><span class="pun">)</span></pre>

<p>
	فقد طابق MatchObject في هذا المثال كل <code>abracadab</code> وليس أول <code>ab</code> فقط، وسلوك المطابقة الجشع هذا هو أكثر الأخطاء التي يرتكبها المبرمج في بداية استخدامه للتعابير النمطية، ولمنع هذا السلوك الجشع نضيف <code>'?'</code> بعد محرف التكرار، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_26" style=""><span class="pln">re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'a.*?b'</span><span class="pun">,</span><span class="str">'abracadabra'</span><span class="pun">)</span></pre>

<p>
	مما سيطابق <code>ab</code> فقط.
</p>

<h2>
	الشرطيات
</h2>

<p>
	يتبقى لدينا الآن أن نجعل التعبير النمطي يبحث في عناصر اختيارية أو يختار نمطًا من بين عدة أنماط، وسننظر في كل منها على حدة.
</p>

<h3>
	العناصر الاختيارية
</h3>

<p>
	يمكن تحديد محرف ما ليكون اختياريًا باستخدام عدد صفر أو أكثر من محارف التكرار الوصفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_28" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'computer?d?'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'computer'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">re</span><span class="pun">.</span><span class="typ">MatchObject</span><span class="pln"> instance at </span><span class="lit">864890</span><span class="pun">&gt;</span></pre>

<p>
	هذا سيطابق <code>compute</code> و<code>computer</code> و<code>computed</code>، كما سيطابق <code>computerd</code>، لكننا لا نريد هذه الأخيرة، لذا سنضيق النطاق الذي نريده كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_30" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">'compute[rd]$'</span><span class="pun">,</span><span class="str">'computer'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">re</span><span class="pun">.</span><span class="typ">MatchObject</span><span class="pln"> instance at </span><span class="lit">874390</span><span class="pun">&gt;</span></pre>

<p>
	وهذا سيختار <code>computer</code> و<code>computed</code> فقط، ويرفض <code>computerd</code>، وإذا أضفنا <code>?</code> بعد هذا النطاق فسنسمح باختيار <code>compute</code> مع تجنب <code>computerd</code> أيضًا.
</p>

<h3>
	التعابير الاختيارية
</h3>

<p>
	بالإضافة إلى خيارات المطابقة من قائمة محارف السابقة الذكر، يمكن المطابقة بناءً على اختيار من تعابير فرعية، فقد ذكرنا سابقًا أننا نستطيع جمع تسلسلات من المحارف في أقواس، لكن الواقع أننا نستطيع جمع أي تعبير نمطي عشوائي بين أقواس ومعاملته مثل وحدة، وسنستخدم الصيغة <code>(RE)</code> أثناء شرح التركيب اللغوي هنا للإشارة إلى أي تجميع لتعابير نمطية، والحالة التي نريد دراستها هنا هي مطابقة تعبير نمطي يحتوي على <code>‎(RE)xxxx</code> أو <code>‎(RE)yyyy</code> حيث تكون <code>xxxx</code> و<code>yyyy</code> أنماطًا مختلفةً، وبناءً عليه فإذا أردنا مطابقة <code>premature</code> و<code>preventative</code> فسنفعل هذا بواسطة محرف الاختيار الوصفي <code>|</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_32" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> regexp </span><span class="pun">=</span><span class="pln"> </span><span class="str">'pre(mature|ventative)'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="pln">regexp</span><span class="pun">,</span><span class="str">'premature'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">re</span><span class="pun">.</span><span class="typ">MatchObject</span><span class="pln"> instance at </span><span class="lit">864890</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="pln">regexp</span><span class="pun">,</span><span class="str">'preventative'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">re</span><span class="pun">.</span><span class="typ">MatchObject</span><span class="pln"> instance at </span><span class="lit">864890</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="pln">regexp</span><span class="pun">,</span><span class="str">'prelude'</span><span class="pun">)</span></pre>

<p>
	نلاحظ أنه عند تعريف التعبير النمطي تعين علينا أن ندرج النص الكامل لكلا الخيارين داخل أقواس بدلًا من <code>(e|v)</code>، ولو لم نفعل لاقتصر الخيار على <code>prematureentative</code> و<code>prematurventative</code> فقط، أي كان الحرفان فقط هما اللذان سيمثلان الخيارات المتاحة، وليس المجموعات كلها.
</p>

<p>
	نستطيع الآن باستخدام هذه التقنية أن نعود إلى المثال أعلاه الذي أردنا فيه التقاط <code>fo</code> أو <code>foo</code> وتجنب التقاط <code>fooo</code> إضافةً إلى أي شيء يأتي بعدها، وقد تركناها مع تعبير نمطي يتكون من <code>fo{1,2}[^o]*$‎</code>، والمشكلة هنا أن التطابق سيفشل إذا احتوت السلسلة النصية التالية لـ <code>fo</code> أو <code>foo</code> على <code>o</code>، لكن يمكن الالتفاف على ذلك باستخدام عدة خيارات من التعبيرات، ونريد أن ينجح التطابق سواء كان النمط في نهاية السطر أو متبوعًا بأي حرف سوى <code>o</code>، وسيبدو ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_34" style=""><span class="pln">fo</span><span class="pun">{</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">}(</span><span class="pln">$</span><span class="pun">|[^</span><span class="pln">o</span><span class="pun">])</span></pre>

<p>
	والذي سيعطينا أخيرًا ما نريده، تجدر الإشارة إلى أنه يجب تنفيذ اختبارات كافية عند استخدام التعابير النمطية، لضمان عدم التقاط أي شيء غير مرغوب فيه، وأننا نلتقط كل ما نريد التقاطه.
</p>

<h2>
	المزيد من الملاحظات حول التعابير النمطية
</h2>

<p>
	تحتوي وحدة <code>re</code> على مزايا كثيرة لم نذكرها هنا، يجدر النظر فيها ودراستها من توثيق الوحدة نفسها، لكننا نريد تسليط الضوء على مجموعة من الرايات flags التي يمكن استخدامها عند تصريف التعبيرات مع دالة <code>re.compile()‎</code>، والتي تتحكم في أمور مثل مطابقة النمط في الأسطر المختلفة، أو تجاهله لحالة الأحرف، أو غير ذلك.
</p>

<p>
	ومن المهم استخدام أداة تختبر التعابير النمطية للتحقق من نتائجها، وتوجد أدوات عديدة منها على الويب، لكن نخص بالذكر منها أداة <a href="https://regex101.com/" rel="external nofollow">regex101</a>، حيث نكتب فيها تعبيرًا نمطيًا وسلسلة اختبار، ثم نرى الأجزاء التي طابقها التعبير من السلسلة النصية، وهذه الأداة تحديدًا تعطينا وصفًا مفيدًا عما يفعله التعبير النمطي، وتسمح لنا باختيار أصناف فرعية للمطابَقات الناتجة، وغيرها من المزايا المفيدة.
</p>

<h2>
	استخدام التعابير النمطية في بايثون
</h2>

<p>
	رأينا في السطور السابقة شيئًا يسيرًا من التعابير النمطية، ونريد أن نطبق ذلك في <a href="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">بايثون</a>، حيث نستطيع استخدامها أداة بحث قويةً جدًا في النصوص، إذ يمكن البحث عن صور كثيرة مختلفة لسلاسل نصية في عملية واحدة، بل يمكن البحث عن المحارف التي لا تُطبع مثل الأسطر الفارغة باستخدام بعض المحارف الوصفية المتاحة، كما يمكن استبدال هذه الأنماط باستخدام التوابع والدوال الخاصة بوحدة <code>re</code>، كما رأينا في دالة <code>match()‎</code> أعلاه، وفيما يلي بعض الدوال الأخرى المتاحة:
</p>

<table>
	<thead>
		<tr>
			<th style="text-align:center">
				الدالة - التابع
			</th>
			<th style="text-align:center">
				التأثير
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				(match(RE,string
			</td>
			<td style="text-align:center">
				يعيد كائن مطابقة إذا طابق التعبير النمطي بداية السلسلة.
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				(search(RE,string
			</td>
			<td style="text-align:center">
				يعيد كائن مطابقة إذا وُجد تعبير نمطي في أي مكان في السلسلة النصية.
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				(split(RE, string
			</td>
			<td style="text-align:center">
				مثل <code>string.split()‎</code> لكن يستخدم تعبيرًا نمطيًا مثل فاصل.
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				(sub(RE, replace, string
			</td>
			<td style="text-align:center">
				تعيد سلسلةً نصيةً أُنتجت عن طريق استبدال لـ re في أول مطابقة للتعبير النمطي، وهذه الدالة لها مزايا أخرى إضافية، انظر توثيقها للمزيد.
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				(findall(RE, string
			</td>
			<td style="text-align:center">
				تبحث عن جميع مرات حدوث التعبير النمطي في سلسلة نصية، وتعيد سلسلةً من كائنات المطابقة.
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				(compile(RE
			</td>
			<td style="text-align:center">
				تنتج كائن تعبير نمطي يمكن إعادة استخدامه لعدة عمليات مع نفس التعبير النمطي، ويكون للكائن جميع التوابع أعلاه لكن مع re مضمَّنة، ويكون أكثر كفاءةً من النسخ الخاصة بالدالة.
			</td>
		</tr>
	</tbody>
</table>

<p>
	لا شك أن هذه القائمة لا تحتوي جميع توابع re ودوالها، كما أن التوابع التي ذكرناها في الجدول لها معامِلات اختيارية لتوسيع استخدامها، واخترناها لأنها أكثر العمليات استخدامًا، ومناسبةً لاحتياجاتنا.
</p>

<h3>
	مثال عملي على التعابير النمطية
</h3>

<p>
	لننشئ برنامجًا يبحث في ملف <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> عن وسم IMG ليس له قسم ALT، فإذا وجدنا واحدًا فسنضيف رسالةً إلى المالك ليكتب ملفات HTML أفضل في المستقبل.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1493_38" style=""><span class="pln">import re

# لنسمح بصفر مسافة أو أكثر بين img أو IMG التقط 
# &lt; و I
img = '&lt; *[iI][mM][gG] '     

# alt أو ALT السماح بأي عدد من المحارف حتى 
before &gt;
alt = img + '.*[aA][lL][tT].*&gt;'

# افتح الملف واقرأه في قائمة
filename = input('Enter a filename to search ')
inf = open(filename,'r')
lines = inf.readlines()

# ALT بدون IMG إذا احتوى السطر على وسم
# HTML فأضف رسالتنا كتعليق
for index,line in enumerate(lines):
  if ( re.search(img,line) and not
       re.search(alt,line) ):
        lines[index] += '</span><span class="com">&lt;!-- PROVIDE ALT TAGS ON IMAGES! --&gt;</span><span class="pln">\n'

# والآن اكتب الملف المعدَّل.
inf.close()
outf = open(filename,'w')
outf.writelines(lines)
outf.close()</span></pre>

<p>
	لدينا ملاحظتان على الشيفرة أعلاه نريد الإشارة إليهما، الأولى أننا استخدمنا <code>re.search</code> بدلًا من <code>re.match</code>، لأن الأولى تبحث عن الأنماط في أي مكان داخل السلسلة النصية، بينما تبحث الثانية في بداية السلسلة فقط، أما الملاحظة الثانية فهي أننا وضعنا زوجًا خارجيًا من الأقواس حول الاختبارين، وهو أمر غير ضروري لكنه يسمح لنا بتقسيم الاختبار إلى سطرين، مما يجعله أسهل في القراءة خاصةً إذا كنا سندمج تعبيرات كثيرةً.
</p>

<p>
	وهذه الشيفرة ليست مثاليةً لأنها لا تأخذ في الحسبان الحالة التي يكون وسم <code>img</code> فيها مقسمًا على عدة أسطر، لكنها تكفي لشرح التقنية عمومًا، على أنه يُفضل تجنب هذا "التخريب" الذي قمنا به في ملف HTML، لكن الذي ينسى وسوم <code>alt</code> يستحق جزاءه.
</p>

<p>
	نأتي لأمر أخير، وهو حدود كفاءة التعابير النمطية، فلهياكل البيانات المعرَّفة بوضوح -مثل HTML- أدوات أخرى غير التعابير النمطية، تُعرف باسم المحلِّلات تكون أكثر كفاءةً وأسهل في الاستخدام دون أخطاء، وسنستخدم محلل HTML في <a href="http://www.alan-g.me.uk/l2p2/tutwebc.htm" rel="external nofollow">ج</a>زئية لاحقة من هذه السلسلة، وتتجلى فائدة التعابير النمطية في عمليات البحث المعقدة في النصوص الحرة إذ تحل لنا مشاكل كثيرة، مع التأكيد مرةً أخرى على الاختبار المفصل لها، كما لا يجب استخدامها إلا عند الحاجة الضرورية إليها، أما إذا كنا نريد البحث عن سلسلة بسيطة فنستخدم التابع <code>find</code>، لتجنب مشاكل التعابير النمطية.
</p>

<p>
	وسنعود مرةً أخرى إلى التعابير النمطية في دراسة الحالة لعدّاد القواعد النحوية، لذا جرب استخدامها حتى ذلك الحين، وتفقد التوابع الأخرى الموجودة في وحدة re، فلم نشرح حتى الآن إلا قشور هذه الأدوات بالغة القوة في معالجة النصوص.
</p>

<h2>
	التعابير النمطية في جافاسكربت
</h2>

<p>
	تدعم جافاسكربت <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-regular-expressions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1278/" rel="">التعابير النمطية</a> ضمنيًا وبقوة، بل إن عمليات البحث في السلاسل النصية التي استخدمناها من قبل ما هي إلا بحوث تعابير نمطية، فقد استخدمنا أبسط صورة لها "تسلسل بسيط من المحارف"، وتنطبق جميع القواعد التي ذكرناها في بايثون على جافاسكربت، عدا أن التعابير النمطية هنا تكون محاطةً بشرطة مائلة <code>/</code> بدلًا من علامات الاقتباس:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_40" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"A lovely bunch of bananas"</span><span class="pun">;</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">str </span><span class="pun">+</span><span class="pln"> </span><span class="str">"&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">str</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">/^A/</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"Found string beginning with A&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">str</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">/b[au]/</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"Found substring with either ba or bu&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">str</span><span class="pun">.</span><span class="pln">match</span><span class="pun">(</span><span class="str">/zzz/</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"Didn't find substring zzz!&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ينجح التعبيران الأولان ويفشل الثالث، لذا حصلنا على الاختبار السلبي، لاحظ علامة التعجب في البداية.
</p>

<h2>
	التعابير النمطية في VBScript
</h2>

<p>
	لا تحتوي VBScript على دعم مضمّن للتعابير النمطية كما في جافاسكربت، لكن فيها كائن تعبير نمطي يمكن بدؤه واستخدامه للبحث وعمليات الاستبدال وغيرها، كما يمكن التحكم فيه لتجاهل حالة الأحرف وللبحث في جميع النسخ أو نسخة واحدة فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1493_43" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> regex</span><span class="pun">,</span><span class="pln"> matches
</span><span class="typ">Set</span><span class="pln"> regex </span><span class="pun">=</span><span class="pln"> </span><span class="typ">New</span><span class="pln"> </span><span class="typ">RegExp</span><span class="pln">

regex</span><span class="pun">.</span><span class="typ">Global</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">True</span><span class="pln">
regex</span><span class="pun">.</span><span class="typ">Pattern</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"b[au]"</span><span class="pln">

</span><span class="typ">Set</span><span class="pln"> matches </span><span class="pun">=</span><span class="pln"> regex</span><span class="pun">.</span><span class="typ">Execute</span><span class="pun">(</span><span class="str">"A lovely bunch of bananas"</span><span class="pun">)</span><span class="pln">
</span><span class="typ">If</span><span class="pln"> matches</span><span class="pun">.</span><span class="typ">Count</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="typ">Then</span><span class="pln">
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"Found "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> matches</span><span class="pun">.</span><span class="typ">Count</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">" substrings"</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">If</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	نكون بهذا قد وصلنا إلى نهاية هذا المقال مكتفين بما ذكرناه فيه، لكن نعيد التأكيد على أن التعابير النمطية غنية بالتعقيدات الدقيقة التي لا يمكن تغطيتها في هذا المقال القصير، ويمكن الرجوع إلى المصادر الموجودة في الويب لمزيد من المعلومات عن استخدامها، إضافةً إلى كتاب أورايلي الذي أوردناه في بداية المقال.
</p>

<h2>
	خاتمة
</h2>

<p>
	بنهاية هذا المقال نود أن تكون قد تعلمت:
</p>

<ul>
	<li>
		التعابير النمطية هي أنماط نصية تستطيع تطوير قوة وكفاءة عمليات البحث النصية.
	</li>
	<li>
		يصعب التحكم بالتعابير النمطية، وقد تتسبب في زلات برمجية غريبة، لذا يجب التعامل معها بحرص.
	</li>
	<li>
		التعابير النمطية ليست الحل السهل لكل مشكلة، بل قد يكون الحل في منظور أكثر تعقيدًا، فإذا لم ينجح استخدام التعابير النمطية في حل مشكلة لثلاث محاولات متتالية، فيجب البحث عن حل آخر.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutregex.htm" rel="external nofollow">للفصل السادس عشر: Regular Expressions من كتاب Learn To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">البرمجة كائنية التوجه</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D9%81%D8%B6%D8%A7%D8%A1%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D9%85%D8%A7%D8%A1-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1362/" rel="">فضاءات الأسماء في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">ما هي البرمجة ومتطلبات تعلمها؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-regexppcre-%D9%81%D9%8A-php-r1085/" rel="">التعابير النمطية (regexp/PCRE) في PHP</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1374</guid><pubDate>Thu, 04 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x641;&#x636;&#x627;&#x621;&#x627;&#x62A; &#x627;&#x644;&#x623;&#x633;&#x645;&#x627;&#x621; Namespaces &#x641;&#x64A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D9%81%D8%B6%D8%A7%D8%A1%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D9%85%D8%A7%D8%A1-namespaces-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1362/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/61825ee87198c_--.png.413fd5c21632f1fbac0ecc626f91c184.png" /></p>
<p>
	فضاء الاسم Namespace هو المساحة أو المنطقة داخل البرنامج التي يكون الاسم صالحًا فيها، سواءً كان ذلك الاسم متغيرًا، أو دالةً، أو صنفًا، أو غير ذلك. يُستخدم هذا المبدأ في الحياة العملية كل يوم، فلو كنت تعمل في شركة كبيرة مثلًا ولك زميل اسمه عماد، ويوجد عماد آخر في قسم المحاسبة، فإنك تشير إلى عماد زميلك في القسم باسمه المجرد "عماد"؛ أما عماد الآخر فستقول "عماد الذي في قسم المحاسبة"، أي أنك تستخدم أسماء أقسام الشركة معرِّفات للعاملين فيها، وهذا هو مبدأ فضاء الاسم في البرمجة، فهو يخبر المبرمج والمترجم بالاسم المقصود فيما لو وجد أكثر من اسم.
</p>

<p>
	لقد ظهرت فضاءات الأسماء لأن لغات البرمجة القديمة -مثل BASIC- لم تكن فيها إلا متغيرات عامة Global Variables، أي متغيرات يمكن رؤيتها في البرنامج كله وداخل الدوال أيضًا، لكن هذا جعل متابعة أداء البرامج الكبيرة وصيانتها صعبًا، لأن التعديل على متغير في جزء ما من البرنامج سيتسبب في تغير وظيفة جزء آخر دون أن يدرك المبرمج ذلك، وهو ما يسمى بالآثار الجانبية، وقد قدمت اللغات التالية -بما فيها النسخ الأحدث من BASIC- مبدأ فضاء الأسماء إلى البرمجة، بل إن لغةً مثل <a href="https://academy.hsoub.com/programming/cpp/%D9%81%D8%B6%D8%A7%D8%A1%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D9%85%D8%A7%D8%A1-namespaces-%D9%81%D9%8A-cpp-r938/" rel="">C++</a>‎ تسمح للمبرمج بإنشاء فضاء اسم خاص به في أي مكان داخل البرنامج، وهذا مفيد لمنشئي المكتبات الذين يرغبون في الاحتفاظ بأسماء دوالهم فريدةً عند اختلاطها مع مكتبات أخرى.
</p>

<p>
	يشار أحيانًا إلى فضاء الاسم بالنطاق Scope، ونطاق الاسم هو امتداد البرنامج الذي يمكن استخدام الاسم فيه، كأن يكون داخل دالة أو وحدة module، وفضاء الاسم والنطاق هما وجهان لعملة واحدة باستثناء فروق طفيفة بين المصطلحين، ولن يناقش فيها إلا عالم حاسوب يحب الجدل؛ أما بالنسبة لمستوى الشرح الذي نريده فهما متطابقان.
</p>

<p>
	سيشرح هذا المقال:
</p>

<ul>
	<li>
		مفهوم فضاء الاسم أو النطاق وأهميته.
	</li>
	<li>
		كيفية عمل فضاء الاسم في <a href="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">بايثون</a>.
	</li>
	<li>
		مفهوم فضاء الاسم في لغتي <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت</a> وVBScript.
	</li>
</ul>

<h2>
	فضاء الاسم في بايثون
</h2>

<p>
	تنشئ كل وحدة في بايثون فضاء الاسم الخاص بها، وللوصول إلى تلك الأسماء لا بد أن نسبقها باسم الوحدة، أو أن نستورد الأسماء التي نريد استخدامها إلى فضاء الاسم الخاص بالوحدة، وقد كنا نفعل هذا مع وحدتي <code>sys</code> و<code>time</code> في المقالات السابقة، كما أن تعريف <a href="https://wiki.hsoub.com/Python#.D8.A7.D9.84.D8.A3.D8.B5.D9.86.D8.A7.D9.81" rel="external">الصنف Class</a> ينشئ فضاء اسم خاص به. وبناءً عليه، فإذا أردنا الوصول إلى تابع أو خاصية في صنف ما، فسنحتاج إلى استخدام اسم متغير النسخة أو اسم الصنف أولًا، وسنتحدث عن هذا بالتفصيل في مقال لاحق.
</p>

<p>
	تتيح بايثون خمسة فضاءات أسماء -أو نطاقات- هي:
</p>

<ol>
	<li>
		النطاق المضمَّن: الأسماء المعرفة داخل بايثون نفسها، وهي متاحة دائمًا من أي مكان في البرنامج.
	</li>
	<li>
		نطاق الوحدة: وهي أسماء معرَّفة ومرئية داخل ملف أو وحدة، لكن هذا النطاق يشار إليه في بايثون باسم النطاق العام global scope، في حين أن المعنى الذي يتبادر للذهن عند سماع الاسم هو أن النطاق العام يمكن رؤيته في أي جزء من البرنامج.
	</li>
	<li>
		النطاق المحلي: وهي الأسماء المعرَّفة داخل دالة أو تابع صنف، بما في ذلك المعامِلات.
	</li>
	<li>
		نطاق الصنف: الأسماء المعرفة داخل الأصناف، وسننظر فيها في مقال لاحق.
	</li>
	<li>
		النطاق المتشعب nested Scope: هذا موضوع معقد قليلًا تستطيع تجاهله حاليًا.
	</li>
</ol>

<p>
	لننظر الآن في الشيفرة التالية التي تحتوي على أمثلة لأول ثلاثة نطاقات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4048_7" style=""><span class="kwd">def</span><span class="pln"> square</span><span class="pun">(</span><span class="pln">x</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">*</span><span class="pln">x

data </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">'Type a number to be squared: '</span><span class="pun">))</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> data</span><span class="pun">,</span><span class="pln"> </span><span class="str">'squared is: '</span><span class="pun">,</span><span class="pln"> square</span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	يسرد الجدول التالي كلًا من الاسم والنطاق الذي ينتمي إليه:
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th style="text-align:center">
				الاسم
			</th>
			<th style="text-align:center">
				فضاء الاسم
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td style="text-align:center">
				square
			</td>
			<td style="text-align:center">
				الوحدة-عام
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				x
			</td>
			<td style="text-align:center">
				محلي للنطاق square
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				data
			</td>
			<td style="text-align:center">
				الوحدة-عام
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				int
			</td>
			<td style="text-align:center">
				مضمَّن
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				input
			</td>
			<td style="text-align:center">
				مضمَّن
			</td>
		</tr>
		<tr>
			<td style="text-align:center">
				print
			</td>
			<td style="text-align:center">
				مضمَّن
			</td>
		</tr>
	</tbody>
</table>

<p>
	لاحظ أننا لا نَعُد <code>def</code> و<code>return</code> من الأسماء، وذلك لأنهما كلمتان مفتاحيتان أو جزء من تعريف اللغة نفسها، وسنحصل على خطأ إذا استخدمنا كلمةً مفتاحيةً اسمًا لمتغير.
</p>

<p>
	لنطرح سؤالًا جديدًا الآن، ماذا يحدث عندما يكون للمتغيرات التي في فضاءات أسماء مختلفة نفس الاسم؟ وماذا يحدث عند الإشارة إلى اسم ليس موجودًا في فضاء الاسم الحالي؟
</p>

<h3>
	الوصول إلى الأسماء التي خارج النطاق الحالي
</h3>

<p>
	تحدد بايثون الأسماء حتى لو لم تكن في فضاء الاسم الحالي بالنظر إلى:
</p>

<ol>
	<li>
		فضاء الاسم المحلي -الدالة الحالية- أو الدالة المغلِّفة أو الصنف المغلِّف إذا كانت دالةً متشعبةً أو تابعًا متشعبًا.
	</li>
	<li>
		نطاق الوحدة، أي الملف الحالي.
	</li>
	<li>
		النطاق المضمَّن.
	</li>
</ol>

<p>
	فإذا كان الاسم في وحدة أخرى، فسنستورد الوحدة باستخدام <code>import</code> كما رأينا في المقالات السابقة، وعند استيرادها سيكون اسم الوحدة مرئيًا في نطاق تلك الوحدة، وسنستطيع حينئذ أن نستخدم اسم الوحدة للوصول إلى أسماء المتغيرات فيها باستخدام نمط <code>module.name</code> المعتاد، ويتبين من هذا أن استيراد جميع الأسماء من وحدة إلى الملف الحالي ليس صحيحًا، إذ قد يتطابق اسم وحدة ما مع اسم أحد متغيراتنا، مما سيتسبب في سلوك غريب للبرنامج لأن أحد الاسمين سيغطي على الآخر.
</p>

<p>
	لنعرِّف وحدتين تستورد الثانية فيهما الأولى على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4048_9" style=""><span class="com">##### module first.py #########</span><span class="pln">
spam </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> print42</span><span class="pun">():</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> spam </span><span class="pun">)</span><span class="pln">
</span><span class="com">###############################</span><span class="pln">
</span><span class="com">##### module second.py ########</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> first </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln">  </span><span class="com"># استورد جميع الأسماء من الأولى</span><span class="pln">

spam </span><span class="pun">=</span><span class="pln"> </span><span class="lit">101</span><span class="pln">   </span><span class="com"># لتخفي النسخة الأولى spam أنشئ متغير </span><span class="pln">
print42</span><span class="pun">()</span><span class="pln">    </span><span class="com"># ما الذي سيُطبع، هل 42 أم 101</span><span class="pln">

</span><span class="com">################################</span></pre>

<p>
	إذا ظننت أن هذا المثال سيطبع 101 فستكون مخطئًا، لأنه سيطبع 42 بسبب تعريف المتغير في بايثون، فكما شرحنا -في مقال: <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r1287/" rel="">البيانات وأنواعها</a>-؛ الاسم هو عنوان يُستخدم للإشارة إلى كائن، وقد كان الاسم <code>print42</code> في الوحدة الأولى يشير إلى كائن الدالة المعرَّف في الوحدة، (وسننظر في ذلك بالتفصيل حين نشرح تعبير لامدا في مقال لاحق)، ومع أننا استوردنا الاسم إلى وحدتنا، إلا أننا لم نستورد الدالة التي لا تزال تشير إلى نسخة الوحدة الخاصة بها من <code>spam</code>، وعلى ذلك فقد أنشأنا متغير spam جديد ليس لديه تأثير على الدالة المشار إليها بالاسم <code>print42</code>. يشرح المخطط التالي هذا لكلا النوعين من الاستيراد، ويمكنك ملاحظة كيف يكرر الاستيراد الثاني الاسم <code>print42</code> من <code>first.py</code> إلى <code>second.py</code>:
</p>

<p style="text-align: center;">
	<img alt="namespaces.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81194" data-unique="jnxzbz3f3" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_10/namespaces.png.c8a22fe1e9ece24880a5c82385adfb1e.png">
</p>

<p>
	ينبغي أن يكون هذا اللبس قد شرح سهولة الوصول إلى الأسماء في الوحدات المستوردة باستخدام ترميز النقطة dot notation. رغم أننا سنكتب شيفرةً أكثر، لكن توجد وحدات قليلة -مثل <code>Tkinter</code> الذي سنتعرض لها لاحقًا-، تُستخدم لاستيراد جميع الأسماء، لكنها تُكتب بطريقة تقلل خطر تعارض الأسماء رغم وجود الخطورة على أي حال، كما قد تنشأ عنها زلات برمجية bugs يصعب العثور عليها، وعلى أي حال توجد طريقة أكثر أمانًا لاستيراد اسم وحيد من وحدة ما، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4048_11" style=""><span class="pln">from sys </span><span class="kwd">import</span><span class="pln"> exit</span></pre>

<p>
	وهنا نأتي بدالة <code>exit</code> فقط إلى فضاء الاسم المحلي، لكن لا نستطيع استخدام أسماء أخرى من <code>sys</code>، ولا حتى <code>sys</code> نفسها.
</p>

<h3>
	تجنب تعارض الأسماء
</h3>

<p>
	إذا كانت الدالة تشير إلى متغير اسمه X، مع وجود X آخر في الدالة أي في النطاق المحلي، فسيكون هذا الأخير هو الذي ستراه بايثون وتستخدمه، وهنا يقع على عاتق المبرمج تجنب تعارض الأسماء، بحيث إذا كان لدينا متغيران أحدهما محلي والآخر متغير وحدة لهما الاسم نفسه، فلا نطلبهما في نفس الدالة، إذ سيغطي المتغير المحلى على اسم الوحدة.
</p>

<p>
	ولن نواجه مشكلةً إذا أردنا قراءة متغير عام داخل دالة، إذ ستبحث بايثون عن الاسم محليًا، فإذا لم تجده فستبحث في النطاق العام، بل وفي النطاق المضمَّن كذلك إذا دعت الحاجة، وإنما ستظهر المشكلة عندما نريد إسناد قيمة إلى متغير عام، إذ سينشئ هذا متغيرًا محليًا جديدًا داخل الدالة، فكيف نسند القيمة إلى متغير عام دون إنشاء متغير محلي بنفس الاسم إذًا؟ يمكن تنفيذ هذا باستخدام الكلمة المفتاحية <code>global</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4048_15" style=""><span class="kwd">var</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
def modGlobal</span><span class="pun">():</span><span class="pln">
   global </span><span class="kwd">var</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">محلي</span><span class="pln"> </span><span class="kwd">var</span><span class="pln"> </span><span class="pun">تمنع</span><span class="pln"> </span><span class="pun">إنشاء</span><span class="pln">
   </span><span class="kwd">var</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">var</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">21</span><span class="pln">

def modLocal</span><span class="pun">():</span><span class="pln">
   </span><span class="kwd">var</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">101</span><span class="pln">

print</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">var</span><span class="pln"> </span><span class="pun">)</span><span class="pln">   </span><span class="pun">#</span><span class="pln"> </span><span class="pun">تطبع</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
modGlobal</span><span class="pun">()</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">var</span><span class="pln"> </span><span class="pun">)</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">تطبع</span><span class="pln"> </span><span class="lit">21</span><span class="pln">
modLocal</span><span class="pun">()</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">var</span><span class="pln"> </span><span class="pun">)</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">تطبع</span><span class="pln"> </span><span class="lit">21</span></pre>

<p>
	نرى هنا كيف غيرت الدالة <code>modGlobal</code> من المتغير العام، على عكس الدالة <code>modLocal</code> التي لم تغيره، لأنها تنشئ متغيرها الداخلي الخاص بها وتسند قيمةً إليه، ثم يُجمع هذا المتغير في نهاية الدالة ليُحذف، ويكون غير مرئي في مستوى الوحدة، لكن عمومًا ينبغي أن نقلل من استخدام تعليمات <code>global</code>، فمن الأفضل أن نمرر المتغير معامِلًا للدالة، ثم نعيد المتغير المعدَّل. يعيد المثال التالي كتابة دالة <code>modGlobal</code> دون استخدام تعليمة <code>global</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4048_17" style=""><span class="kwd">var</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
def modGlobal</span><span class="pun">(</span><span class="pln">aVariable</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> aVariable </span><span class="pun">-</span><span class="pln"> </span><span class="lit">21</span><span class="pln">

print</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">var</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> modGlobal</span><span class="pun">(</span><span class="kwd">var</span><span class="pun">)</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">var</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	في هذه الحالة نسند القيمة التي أعادتها الدالة إلى المتغير الأصلي في نفس الوقت الذي نمررها فيه وسيطًا، وتكون النتيجة نفسها، لكن لا تعتمد الدالة الآن على أي شيفرة خارجها، مما يسهل إعادة استخدامها في برامج أخرى، كما يسهل رؤية كيف تتغير القيمة العامة global value، حيث نستطيع أن نرى حدوث الإسناد الصريح هنا، ويطبق المثال التالي كل ذلك عمليًا، إذ يوضح النقاط التي شرحناها إلى الآن، لهذا ادرسه جيدًا حتى تعرف استخدام الأسماء والقيم في كل خطوة فيه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4048_19" style=""><span class="pun">#</span><span class="pln"> </span><span class="pun">متغيرات</span><span class="pln"> </span><span class="pun">نطاقها</span><span class="pln"> </span><span class="pun">الوحدة</span><span class="pln">
W </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
Y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln">

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">المعامِلات</span><span class="pln"> </span><span class="pun">تشبه</span><span class="pln"> </span><span class="pun">متغيرات</span><span class="pln"> </span><span class="pun">الدوال</span><span class="pln"> 
</span><span class="pun">#</span><span class="pln"> </span><span class="pun">نطاق</span><span class="pln"> </span><span class="pun">محلي</span><span class="pln"> X </span><span class="pun">وعليه</span><span class="pln"> </span><span class="pun">يكون</span><span class="pln"> </span><span class="pun">لـ</span><span class="pln"> 
def spam</span><span class="pun">(</span><span class="pln">X</span><span class="pun">):</span><span class="pln">

   </span><span class="pun">#</span><span class="pln"> </span><span class="pun">أخبر</span><span class="pln"> </span><span class="pun">الدالة</span><span class="pln"> </span><span class="pun">أن</span><span class="pln"> </span><span class="pun">تنظر</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">مستوى</span><span class="pln"> </span><span class="pun">الوحدة</span><span class="pln"> 
   </span><span class="pun">#</span><span class="pln"> </span><span class="pun">خاصة</span><span class="pln"> </span><span class="pun">بها</span><span class="pln"> w </span><span class="pun">وألا</span><span class="pln"> </span><span class="pun">تنشئ</span><span class="pln"> </span><span class="pun">وحدة</span><span class="pln"> 
   global W

   Z </span><span class="pun">=</span><span class="pln"> X</span><span class="pun">*</span><span class="lit">2</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">الذي</span><span class="pln"> </span><span class="pun">له</span><span class="pln"> </span><span class="pun">نطاق</span><span class="pln"> </span><span class="pun">محلي</span><span class="pln"> Z </span><span class="pun">أنشأنا</span><span class="pln"> </span><span class="pun">متغير</span><span class="pln"> 
   W </span><span class="pun">=</span><span class="pln"> X</span><span class="pun">+</span><span class="lit">5</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">كما</span><span class="pln"> </span><span class="pun">شرحنا</span><span class="pln"> </span><span class="pun">أعلاه</span><span class="pln"> w </span><span class="pun">استخدم</span><span class="pln"> </span><span class="pun">الوحدة</span><span class="pln"> 

   </span><span class="kwd">if</span><span class="pln"> Z </span><span class="pun">&gt;</span><span class="pln"> W</span><span class="pun">:</span><span class="pln">
      </span><span class="pun">#</span><span class="pln"> </span><span class="pun">هو</span><span class="pln"> </span><span class="pun">اسم</span><span class="pln"> </span><span class="pun">نطاق</span><span class="pln"> </span><span class="pun">مضمَّن</span><span class="pln"> pow
      print</span><span class="pun">(</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">Z</span><span class="pun">,</span><span class="pln">W</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> Z
   </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> Y </span><span class="pun">#</span><span class="pln"> </span><span class="pun">محلي</span><span class="pln"> Y </span><span class="pun">لا</span><span class="pln"> </span><span class="pun">يوجد</span><span class="pln">
                 </span><span class="pun">#</span><span class="pln"> </span><span class="pun">لذا</span><span class="pln"> </span><span class="pun">نستخدم</span><span class="pln"> </span><span class="pun">نسخة</span><span class="pln"> </span><span class="pun">الوحدة</span><span class="pln">

print</span><span class="pun">(</span><span class="str">"W,Y = "</span><span class="pun">,</span><span class="pln"> W</span><span class="pun">,</span><span class="pln"> Y </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> n in </span><span class="pun">[</span><span class="lit">2</span><span class="pun">,</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">]:</span><span class="pln">
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Spam(%d) returned: "</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> n</span><span class="pun">,</span><span class="pln"> spam</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"W,Y = "</span><span class="pun">,</span><span class="pln"> W</span><span class="pun">,</span><span class="pln"> Y </span><span class="pun">)</span></pre>

<h3>
	فضاء الاسم في VBScript
</h3>

<p>
	إذا صرحنا عن متغير خارج الدالة أو البرنامج الفرعي في VBScript، فسيكون عامًا globally أما إذا صرحنا عنه داخل الدالة أو البرنامج الفرعي، فسيكون محليًا في الوحدة وسيخفي أي متغير عام له نفس الاسم، كما سيكون المبرمج هنا هو المسؤول عن إدارة التعارض بين هذه الأسماء، وبما أن متغيرات VBScript تُنشأ باستخدام تعليمة <code>Dim</code> فلن يحدث غموض أو لبس حول المتغير المقصود على عكس بايثون، وبهذا نرى أن منظور VBScript لقواعد النطاقات أبسط وأوضح من بايثون، لكن هناك بعض الأمور الخاصة بصفحات الويب، حيث ستكون المتغيرات العامة مرئيةً في كامل الملف، وليس داخل حدود الوسم <code>script</code> الذي عُرَّفت فيه فقط، وتوضح الشيفرة التالية ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4048_21" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> aVariable
</span><span class="typ">Dim</span><span class="pln"> another
aVariable </span><span class="pun">=</span><span class="pln"> </span><span class="str">"This is global in scope"</span><span class="pln">
another </span><span class="pun">=</span><span class="pln"> </span><span class="str">"A Global can be visible from a function"</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Sub</span><span class="pln"> aSubroutine
   </span><span class="typ">Dim</span><span class="pln"> aVariable
   aVariable </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Defined within a subroutine"</span><span class="pln">
   </span><span class="typ">MsgBox</span><span class="pln"> aVariable
   </span><span class="typ">MsgBox</span><span class="pln"> another  </span><span class="str">'</span><span class="pln"> uses global name
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> aVariable
aSubroutine
</span><span class="typ">MsgBox</span><span class="pln"> aVariable
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	توجد بعض مزايا النطاقات في VBScript، والتي نتيح بها إمكانية الوصول إلى المتغيرات بين الملفات المختلفة في صفحة ويب -من الفهرس مثلًا إلى المحتوى والعكس-، لكن لن نتحدث عن هذا المستوى من برمجة صفحات الويب هنا، لذا سنكتفي بالإشارة إلى وجود كلمات مفتاحية مثل <code>Public</code> و<code>Private</code>.
</p>

<h3>
	فضاء الاسم في جافاسكربت
</h3>

<p>
	تتبع جافاسكربت نفس القواعد تقريبًا، إذ تكون المتغيرات المصرح عنها داخل الدوال مرئيةً داخل تلك الدوال فقط؛ أما المتغيرات التي خارج الدوال فيمكن أن تراها الشيفرة التي خارج <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1233/" rel="">الدوال</a>، إضافةً إلى إمكانية رؤيتها داخل الدوال أيضًا. وكما هو الحال في VBScript؛ ليس هناك تعارض أو غموض بشأن المتغير المقصود، لأن المتغيرات تُنشأ صراحةً باستخدام تعليمة <code>var</code>، والمثال التالي شبيه بمثال VBScript السابق لكنه مكتوب بلغة جافاسكربت:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4048_23" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> aVariable</span><span class="pun">,</span><span class="pln"> another</span><span class="pun">;</span><span class="pln">  </span><span class="com">// متغيرات عامة</span><span class="pln">
aVariable </span><span class="pun">=</span><span class="pln"> </span><span class="str">"This is Global in scope&lt;BR&gt;"</span><span class="pun">;</span><span class="pln">
another </span><span class="pun">=</span><span class="pln"> </span><span class="str">"A global variable can be seen inside a function&lt;BR&gt;"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> aSubroutine</span><span class="pun">(){</span><span class="pln">
   </span><span class="kwd">var</span><span class="pln"> aVariable</span><span class="pun">;</span><span class="pln">        </span><span class="com">// متغير محلي</span><span class="pln">
   aVariable </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Defined within a function&lt;BR&gt;"</span><span class="pun">;</span><span class="pln">
   document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">aVariable</span><span class="pun">);</span><span class="pln">
   document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">another</span><span class="pun">);</span><span class="pln">  </span><span class="com">// يستخدم متغيرًا عامًا</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">aVariable</span><span class="pun">);</span><span class="pln">
aSubroutine</span><span class="pun">();</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">aVariable</span><span class="pun">);</span><span class="pln">

</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ولا أظننا بحاجة إلى تكرار شرح المثال مرةً أخرى هنا.
</p>

<h2>
	خاتمة
</h2>

<p>
	نرجو في نهاية هذا المثال أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		النطاقات وفضاءات الأسماء وجهان لعملة واحدة، ويشيران إلى نفس الشيء.
	</li>
	<li>
		المفاهيم واحدة بين اللغات المختلفة، لكن الذي يختلف هو التطبيق الدقيق لها وفق قواعد كل لغة.
	</li>
	<li>
		تحتوي بايثون على خمسة نطاقات هي: النطاق المضمَّن built in، ونطاق الصنف class، والنطاق المتشعب nested، ونطاق الملف أو النطاق العام global، ونطاق الدالة أو النطاق المحلي function، وهذه النطاقات الثلاثة الأخيرة هي أهم نطاقات فيها من حيث كثرة الاستخدام في البرمجة.
	</li>
	<li>
		تحتوي كل من جافاسكربت وVBScript على نطاقين لكل واحدة منهما، هما نطاق الملف أو النطاق العام file، ونطاق الدالة أو النطاق المحلي function.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutname.htm" rel="external nofollow">للفصل الخامس عشر: Namespaces من كتاب Learn To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1374/" rel="">التعابير النمطية في البرمجة</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">كيفية التعامل مع الأخطاء البرمجية</a><span style="display: none;"> </span>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/%D9%81%D8%B6%D8%A7%D8%A1-%D8%A7%D9%84%D8%A3%D8%B3%D9%85%D8%A7%D8%A1-namespaces-%D9%81%D9%8A-php-r1082/" rel="">فضاء الأسماء (namespaces) في PHP</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1362</guid><pubDate>Thu, 28 Oct 2021 15:00:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x623;&#x62E;&#x637;&#x627;&#x621; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/615ffc674b537_---.png.93a7b99319e23ea0f82fefb650dd5116.png" /></p>
<p>
	نقصد بمعالجة الأخطاء عملية التقاط الأخطاء التي تولدها برامجنا وإخفائها عن المستخدم، فرسائل الأخطاء لا تخيف المبرمجين بل يمكن توقعها أحيانًا، إلا أن المستخدم لا يتوقع رؤيتها، وهي تربكه وتسبب له حيرةً، فإن كان سيرى رسالة خطأ للضرورة، فلتكن رسالةً سهلة الفهم، وحتى في هذه الحالة سيرغب المستخدم في أن يحل المبرمج المشكلة، وهنا يأتي دور التعامل مع الأخطاء ومعالجتها، حيث توفر كل لغة تقريبًا آليةً لالتقاط الأخطاء عند حدوثها لمعرفة الأجزاء التي تعطلت، واتخاذ الإجراء المناسب لإصلاح المشكلة، وقد تطورت عدة طرق لمعالجة هذه الأخطاء، والتي سننظر فيها هنا متبعين تطورها التاريخي مع تطور التقنية لنعرف الأسباب التي أدت إلى ظهور منظور جديد رغم وجودها سابقًا، ونرجو أن تكون قادرًا في نهاية المقال على كتابة برامج لا تسمح بظهور رسائل خطأ للمستخدم.
</p>

<p>
	تجدر الإشارة إلى أن لغة VBScript هي أكثر لغة غريبة من اللغات الثلاثة التي ندرسها في معالجة الأخطاء، لأنها بُنيت على لغة BASIC، التي إحدى أوائل لغات البرمجة التي خرجت في عام 1963، وسنرى كيف ألقى تراثها بظلاله على VBScript فيما يتعلق بمعالجة الأخطاء، لكن هذا لا يؤثر على سياق شرحنا، بل سيعطينا الفرصة لشرح سبب سلوك VBScript بتعقب تاريخ معالجة الأخطاء، بدءًا من لغة BASIC، مرورًا بلغة Visual Basic حتى VBSCript، ثم ننظر بعدها إلى منظور أحدث، ونرى أمثلةً له في بايثون وجافاسكربت.
</p>

<p>
	لقد كُتبَت البرامج في لغة BASIC مع أرقام للأسطر لتمييزها، حيث يُنقل التحكم بالقفز إلى سطر بعينه باستخدام تعليمة GOTO التي رأينا مثالًا لها في مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/" rel="">مقدمة في البرمجة الشرطية</a>، وقد كانت هذه صورة التحكم الوحيدة المتاحة وقتها، حيث كان الأسلوب الشائع لمعالجة الأخطاء حينئذ هو التصريح عن متغير <code>errorcode</code> الذي يخزن قيمةً عدديةً، وكلما حدث خطأ في البرنامج، سيُضبط المتغير <code>errorcode</code> ليعكس المشكلة. فإما أن يخبرنا أنه لم يستطع فتح الملف، أو أن النوع غير متطابق، أو حدث طفح للعوامل operator overflow، أو غير ذلك، وقد أدى هذا إلى شيفرة تشبه المثال التالي من برنامج وهمي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7960_7" style=""><span class="lit">1010</span><span class="pln"> LET DATA </span><span class="pun">=</span><span class="pln"> INPUT FILE
</span><span class="lit">1020</span><span class="pln"> CALL DATA_PROCESSING_FUNCTION
</span><span class="lit">1030</span><span class="pln"> IF NOT ERRORCODE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> GOTO </span><span class="lit">5000</span><span class="pln">
</span><span class="lit">1040</span><span class="pln"> CALL ANOTHER_FUNCTION
</span><span class="lit">1050</span><span class="pln"> IF NOT ERRORCODE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> GOTO </span><span class="lit">5000</span><span class="pln">
</span><span class="lit">1060</span><span class="pln"> REM CONTINUE PROCESSING LIKE THIS
</span><span class="pun">...</span><span class="pln">
</span><span class="lit">5000</span><span class="pln"> IF ERRORCODE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> GOTO </span><span class="lit">5100</span><span class="pln">
</span><span class="lit">5010</span><span class="pln"> IF ERRORCODE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> GOTO </span><span class="lit">5200</span><span class="pln">
</span><span class="lit">5020</span><span class="pln"> REM MORE IF STATEMENTS
</span><span class="pun">...</span><span class="pln">
</span><span class="lit">5100</span><span class="pln"> REM HANDLE ERROR CODE </span><span class="lit">1</span><span class="pln"> HERE
</span><span class="pun">...</span><span class="pln">
</span><span class="lit">5200</span><span class="pln"> REM HANDLE ERROR CODE </span><span class="lit">2</span><span class="pln"> HERE</span></pre>

<p>
	يفحص نصف البرنامج الرئيسي وجود خطأ، لكن ظهرت مع الوقت آلية أفضل، حيث تولى مفسر اللغة عملية التقاط الأخطاء ومعالجتها؛ ولو جزئيًا، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7960_9" style=""><span class="lit">1010</span><span class="pln"> LET DATA </span><span class="pun">=</span><span class="pln"> INPUTFILE
</span><span class="lit">1020</span><span class="pln"> ON ERROR GOTO </span><span class="lit">5000</span><span class="pln">
</span><span class="lit">1030</span><span class="pln"> CALL DATA_PROCESSING_FUNCTION
</span><span class="lit">1040</span><span class="pln"> CALL ANOTHER_FUNCTION
</span><span class="pun">...</span><span class="pln">
</span><span class="lit">5000</span><span class="pln"> IF ERRORCODE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> GOTO </span><span class="lit">5100</span><span class="pln">
</span><span class="lit">5010</span><span class="pln"> IF ERRORCODE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> GOTO </span><span class="lit">5200</span></pre>

<p>
	سمح هذا بالإشارة إلى المكان الذي توجد فيه شيفرة الخطأ بواسطة سطر واحد، ورغم أننا لا زلنا بحاجة إلى الدوال التي اكتشفت الخطأ لضبط قيمة <code>ERRORCODE</code>، إلا أنها جعلت كتابة الشيفرة وقراءتها أسهل بكثير، لكن كيف يتأثر المبرمجون بهذا الأمر؟ توفر Viusal Basic إلى الآن هذا النوع من معالجة الأخطاء -على الرغم من استخدامنا حاليًا طريقةً أفضل من أرقام الأسطر-، وبما أن VBScript تنحدر من Visual Basic، فإنها توفر نسخةً مختصرةً للغاية من هذه الطريقة، وهي تخيّرنا بين معالجة الأخطاء محليًا أو تجاهلها تمامًا، ونستخدم الشيفرة التالية لتجاهل الأخطاء:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7960_11" style=""><span class="typ">On</span><span class="pln"> </span><span class="typ">Error</span><span class="pln"> </span><span class="typ">Goto</span><span class="pln"> </span><span class="lit">0</span><span class="pln">  </span><span class="str">' 0 implies go nowhere
SomeFunction()
SomeOtherFunction()
....</span></pre>

<p>
	أما لمعالجتها محليًا فنستخدم ما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7960_13" style=""><span class="typ">On</span><span class="pln"> </span><span class="typ">Error</span><span class="pln"> </span><span class="typ">Resume</span><span class="pln"> </span><span class="typ">Next</span><span class="pln">
</span><span class="typ">SomeFunction</span><span class="pun">()</span><span class="pln">
</span><span class="typ">If</span><span class="pln"> </span><span class="typ">Err</span><span class="pun">.</span><span class="typ">Number</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln"> </span><span class="typ">Then</span><span class="pln">
   </span><span class="str">' handle the error here
SomeOtherFunction()
...</span></pre>

<p>
	يبدو هذا المنطق معكوسًا، لكنه يوضح العملية تاريخيًا كما أوضحنا أعلاه، فالسلوك الافتراضي للمفسر هو توليد رسالة إلى المستخدم، وإيقاف تنفيذ البرنامج إذا اكتشف خطأً ما، وهذا ما يحدث مع معالجة خطأ <code>GoTo 0</code>، فما هي إلا طريقة لإيقاف التحكم المحلي والسماح للمفسر بالعمل كالمعتاد.
</p>

<p>
	تسمح لنا تعليمة <code>Resume Next</code> بالتظاهر وكأن الخطأ لم يحدث، أو أن التحقق من كائن الخطأ -الذي يسمى <code>Err</code>-، وسمة العدد -مثل تقنية errorcode الأولى-، كما أن للكائن <code>Err</code> أجزاء معلومات أخرى قد تفيدنا في التعامل مع الموقف بطريقة أفضل من مجرد إيقاف البرنامج، بحيث نستطيع معرفة مصدر الخطأ مثلًا، سواءً كان كائنًا أم دالةً أم غير ذلك، كما نستطيع الحصول على وصف نصي نستخدمه في تعبئة رسالة تخبر المستخدم بما يحدث، أو كتابة ملاحظة في ملف السجل.
</p>

<p>
	كما يمكن تغيير نوع الخطأ باستخدام التابع <code>Raise</code> للكائن <code>Err</code>، إلى جانب استخدامنا له لتوليد أخطائنا من داخل دوالنا، لننظر في مثال حالة القسمة على الصفر؛ وهي حالة شائعة، لنرى معالجة الأخطاء في VBScript:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7960_15" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> x</span><span class="pun">,</span><span class="pln">y</span><span class="pun">,</span><span class="typ">Result</span><span class="pln">
x </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Cint</span><span class="pun">(</span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Enter the number to be divided"</span><span class="pun">))</span><span class="pln">
y </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CINt</span><span class="pun">(</span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Enter the number to divide by"</span><span class="pun">))</span><span class="pln">
</span><span class="typ">On</span><span class="pln"> </span><span class="typ">Error</span><span class="pln"> </span><span class="typ">Resume</span><span class="pln"> </span><span class="typ">Next</span><span class="pln">
</span><span class="typ">Result</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">/</span><span class="pln">y
</span><span class="typ">If</span><span class="pln"> </span><span class="typ">Err</span><span class="pun">.</span><span class="typ">Number</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">11</span><span class="pln"> </span><span class="typ">Then</span><span class="pln"> </span><span class="str">'</span><span class="pln"> </span><span class="typ">Divide</span><span class="pln"> by zero
   </span><span class="typ">Result</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Null</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">If</span><span class="pln">
</span><span class="typ">On</span><span class="pln"> </span><span class="typ">Error</span><span class="pln"> </span><span class="typ">GoTo</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="str">'</span><span class="pln"> turn error handling off again
</span><span class="typ">If</span><span class="pln"> </span><span class="typ">VarType</span><span class="pun">(</span><span class="typ">Result</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> vbNull </span><span class="typ">Then</span><span class="pln">
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"ERROR: Could not perform operation"</span><span class="pln">
</span><span class="typ">Else</span><span class="pln">
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="typ">CStr</span><span class="pun">(</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">" divided by "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">CStr</span><span class="pun">(</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">" is "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">CStr</span><span class="pun">(</span><span class="typ">Result</span><span class="pun">)</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">If</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	هذا الأسلوب غير مثالي، ورغم أن تقدير التراث البرمجي هنا جميل ولطيف، إلا أن لغات البرمجة الحديثة -بما فيها <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت</a>- لديها طرق أفضل لمعالجة الأخطاء، كما سنشرح في الجزئية الموالية من المقال، لكن قبل ذلك، ننصحك بالاطلاع على الفيديو الآتي لفهم الأخطاء البرمجية والتعرف على كيفية التعامل معها مهما اختلف نوعها ولغتها:
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="653" id="ips_uid_7049_6" src="https://academy.hsoub.com/applications/core/interface/index.html" title="كيفية التعامل مع الأخطاء البرمجية" width="1161" data-embed-src="https://www.youtube.com/embed/Pgje6nWuDkg"></iframe>
</p>

<h2>
	معالجة الأخطاء في بايثون
</h2>

<p>
	سنعرض فيما يلي آليات التعامل مع الأخطاء والاستثناءات التي تحصل أثناء تنفيذ شيفرة البرنامج وكيفية معالجتها في بايثون.
</p>

<h3>
	التعامل مع الاستثناءات
</h3>

<p>
	تتعامل لغات البرمجة الحديثة مع الاستثناءات exceptions وتعالجها بجعل الدوال ترفع الاستثناء raise أو تلقيه throw، ثم يفرض النظام قفزةً إلى خارج كتلة التعليمات البرمجية الحالية إلى أقرب كتلة معالجة استثناءات، ويوفر النظام معالجًا افتراضيًا يلتقط جميع الاستثناءات التي لم تعالَج في مكان آخر، كما يطبع رسالة خطأ ثم يخرج. انظر  إلى مقال  <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%AF%D8%A7%D9%8A%D8%A9-%D8%B1%D8%AD%D9%84%D8%A9-%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1280/" rel="">بداية رحلة تعلم البرمجة </a>لمراجعة كيفية قراءة رسائل الخطأ في بايثون وتفسيرها، حيث تتمثل إحدى مزايا هذا النمط من معالجة الأخطاء في سهولة رؤية الوظيفة الأساسية للبرنامج، لأنها غير مختلطة بشيفرة معالجة الأخطاء، إذ نستطيع قراءة الكتلة الرئيسية دون الحاجة إلى النظر إلى شيفرة الخطأ مطلقًا. لننظر في كيفية عمل هذا النمط عمليًا:
</p>

<h4>
	استثناءات Try/Except
</h4>

<p>
	تُكتب كتلة معالجة الاستثناءات على شكل كتلة <code>if ...then...else</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7960_17" style=""><span class="kwd">try</span><span class="pun">:</span><span class="pln">
   </span><span class="com"># منطق البرنامج هنا</span><span class="pln">
</span><span class="kwd">except</span><span class="pln"> </span><span class="typ">ExceptionType</span><span class="pun">:</span><span class="pln">
   </span><span class="com"># معالجة الاستثناءات للاستثناء المسمى هنا</span><span class="pln">
</span><span class="kwd">except</span><span class="pln"> </span><span class="typ">AnotherType</span><span class="pun">:</span><span class="pln">
   </span><span class="com"># معالجة الاستثناءات لاستثناءات أخرى هنا</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
   </span><span class="com"># هنا نقوم بالترتيب إذا لم تُرفع استثناءات</span></pre>

<p>
	تحاول بايثون أن تنفذ التعليمات بين <code>try</code> وأول تعليمة <code>except</code>، فإذا واجهت خطأً ما، فستوقف تنفيذ شيفرة <code>block</code> وتقفز إلى تعليمات <code>except</code> حتى تجد واحدةً تطابق نوع الخطأ أو الاستثناء، فإذا وجدت مطابقةً، فستنفذ الشيفرة التي في الكتلة التي بعد هذا الاستثناء مباشرةً؛ أما إذا لم توجد تعليمة <code>except</code> مطابِقة، فسيُنشر الخطأ إلى المستوى التالي للبرنامج، إلى أن توجد مطابقة، أو أن يكتشف مفسر المستوى الأعلى في بايثون هذا الخطأ ويعرض رسالة خطأ ويوقف تنفيذ البرنامج، وهو ما رأيناه في برامجنا إلى الآن.
</p>

<p>
	أما إذا لم يوجد خطأ في كتلة <code>try</code>، فستنفَّذ كتلة <code>else</code> الأخيرة، رغم أن هذه الخاصية لا تُستخدم إلا نادرًا. لاحظ أن تعليمة <code>except</code> التي ليس فيها نوع خطأ محدد، إذ ستلتقط كل أنواع الأخطاء التي لم تعالَج بعد، وهذا سيئ إلا في حالة المستوى الأعلى في برنامجك حين تريد تجنب عرض رسائل بايثون التقنية إلى المستخدمين، حيث يمكن استخدام تعليمة استثناء عامة لالتقاط أي أخطاء غير ملتقطة، وعرض رسالة "إغلاق" مناسبة للمستخدم، ويجب الانتباه إلى تسجيل بيانات الخطأ في ملف السجل للتحليل في المستقبل.
</p>

<p>
	توفر لغة بايثون وحدة <code>traceback</code> التي تمكنك من استخراج أجزاء من المعلومات من مصدر الخطأ، وقد يكون هذا مفيدًا في إنشاء ملفات السجلات وما شابهها، لكننا لن نشرح هذه الوحدة، فإذا احتجت إليها فسيوفر توثيق الوحدات القياسي قائمةً كاملةً من المزايا والخصائص المتوفرة لها.
</p>

<p>
	لننظر الآن في مثال حقيقي لتوضيح الشرح:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7960_19" style=""><span class="pln">value </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Type a divisor: "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
   value </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"42 / %d = %d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> </span><span class="lit">42</span><span class="pun">/</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">except</span><span class="pln"> </span><span class="typ">ValueError</span><span class="pun">:</span><span class="pln"> 
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"I can't convert the value to an integer"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">except</span><span class="pln"> </span><span class="typ">ZeroDivisionError</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Your value should not be zero"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">except</span><span class="pun">:</span><span class="pln"> 
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Something unexpected happened"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Program completed successfully"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	إذا شغلنا هذا البرنامج وأدخلنا قيمةً ليست برقم مثل إدخال سلسلة نصية في المحث، فسنحصل على رسالة <code>ValueError</code>؛ أما إذا أدخلنا <code>0</code> فنحصل على رسالة <code>ZeroDivisionError</code>، وإذا ضغطنا <code>Ctrl+C</code> فسنرفع استثناء <code>KeyboardInterrupt</code> ونرى رسالةً تقول "Something unexpected happened"؛ أما إذا كتبنا عددًا صالحًا فسنحصل على النتيجة مع رسالة "Program Completed successfully".
</p>

<h4>
	استثناءات Try/Finally
</h4>

<p>
	ثمة نوع آخر من كتل الاستثناءات التي تسمح لنا بالترتيب بعد حدوث خطأ ما، وتسمى <code>try...finally</code>، كما تُستخدم لإغلاق الملفات واتصالات الشبكات أو قواعد البيانات، وتنفَّذ كتلة <code>finally</code> في النهاية بغض النظر عما يحدث في قسم <code>try</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7960_21" style=""><span class="kwd">try</span><span class="pun">:</span><span class="pln">
   </span><span class="com"># المنطق المعتاد للبرنامج</span><span class="pln">
</span><span class="kwd">finally</span><span class="pun">:</span><span class="pln">
   </span><span class="com"># try هنا نرتب بغض النظر عن نجاح كتلة</span><span class="pln">
   </span><span class="com"># أو فشلها</span></pre>

<p>
	تصبح الكتلة قويةً للغاية إذا جمعناها مع <code>try/except</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7960_23" style=""><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Program starting"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
   data </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"data.dat"</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"data file opened"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
   value </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">data</span><span class="pun">.</span><span class="pln">readline</span><span class="pun">().</span><span class="pln">split</span><span class="pun">()[</span><span class="lit">2</span><span class="pun">])</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"The calculated value is %s"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">/(</span><span class="lit">42</span><span class="pun">-</span><span class="pln">value</span><span class="pun">))</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">except</span><span class="pln"> </span><span class="typ">ZeroDivisionError</span><span class="pun">:</span><span class="pln"> 
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Value read was 42"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">finally</span><span class="pun">:</span><span class="pln">
   data</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"data file closed"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Program completed"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ أن ملف البيانات يجب أن يحتوي على سطر مع رقم في الحقل الثالث، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-perl prettyprinted" id="ips_uid_7960_25" style=""><span class="typ">Foo</span><span class="pln"> bar </span><span class="lit">42</span></pre>

<p>
	هنا يُغلق ملف البيانات دومًا بغض النظر عن رفع الاستثناء في كتلة <code>try/except</code> أو لا. لاحظ أن هذا السلوك مختلف عن شرط <code>else</code> لكتلة <code>try/except</code>، لأنه يُستدعى فقط عند عدم رفع استثناءات، كما يعني وضع الشيفرة خارج كتلة <code>try/except</code> أن الملف لم يغلَق إذا كان الاستثناء شيئًا غير <code>ZeroDivisionError</code>، ولا نضمن أن الملف مغلق إلا بإضافة كتلة <code>finally</code>. كذلك وضعنا تعليمة <code>open()‎</code> داخل كتلة <code>try/except</code>، فإذا أردنا التقاط خطأ فتح ملف، فسنحتاج إلى إضافة كتلة <code>except</code> أخرى لـ <code>IOError</code>. جرب هذا بنفسك ثم افتح ملفًا غير موجود لترى ذلك عمليًا.
</p>

<h3>
	توليد الأخطاء
</h3>

<p>
	إذا أردنا توليد استثناءات ليلتقطها غيرنا في وحدة ما، فنستخدم الكلمة المفتاحية <code>raise</code> في بايثون:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7960_27" style=""><span class="pln">numerator </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
denominator </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"What value will I divide 42 by?"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> denominator </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">ZeroDivisionError</span></pre>

<p>
	يرفع هذا استثناء <code>ZeroDivisionError</code> الذي يمكن التقاطه بواسطة كتلة <code>try/except</code>، أما بالنسبة لبقية البرنامج فسيبدو كما لو أن بايثون ولّدت هذا الخطأ داخليًا.
</p>

<p>
	يمكن استخدام كلمة <code>raise</code> في توليد خطأ لمستوى أعلى في البرنامج من داخل كتلة الاستثناء، فقد نرغب في أخذ إجراء محلي، مثل تسجيل خطأ في ملف، ثم نسمح للمستوى الأعلى من البرنامج أن يقرر الإجراء النهائي، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4669_6" style=""><span class="kwd">def</span><span class="pln"> div127by</span><span class="pun">(</span><span class="pln">datum</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">127</span><span class="pun">/(</span><span class="lit">42</span><span class="pun">-</span><span class="pln">datum</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">ZeroDivisionError</span><span class="pun">:</span><span class="pln">
      logfile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"errorlog.txt"</span><span class="pun">,</span><span class="str">"a"</span><span class="pun">)</span><span class="pln">
      logfile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"datum was 42\n"</span><span class="pun">)</span><span class="pln">
      logfile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
      </span><span class="kwd">raise</span><span class="pln">

</span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
   div127by</span><span class="pun">(</span><span class="lit">42</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">except</span><span class="pln"> </span><span class="typ">ZeroDivisionError</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"You can't divide by zero, try another value"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ كيف تلتقط الدالة <code>div127by()‎</code> الخطأ، وتسجل رسالةً في ملف الخطأ، ثم تمرر الاستثناء مرةً أخرى إلى كتلة <code>try/except</code> الخارجية لتتعامل معه باستدعاء <code>raise</code> دون كائن خطأ محدد. لنجمع هذين الجزأين معًا في برنامج واحد يوضح معالجة الأخطاء عمليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4669_8" style=""><span class="kwd">def</span><span class="pln"> div127by</span><span class="pun">(</span><span class="pln">datum</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">127</span><span class="pun">/(</span><span class="lit">42</span><span class="pun">-</span><span class="pln">datum</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">ZeroDivisionError</span><span class="pun">:</span><span class="pln">
      logfile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"errorlog.txt"</span><span class="pun">,</span><span class="str">"a"</span><span class="pun">)</span><span class="pln">
      logfile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"datum was 42\n"</span><span class="pun">)</span><span class="pln">
      logfile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
      </span><span class="kwd">raise</span><span class="pln">

</span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
   divisor </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"What value will I divide by?"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> divisor </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">ZeroDivisionError</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"The result is: "</span><span class="pun">,</span><span class="pln"> div127by</span><span class="pun">(</span><span class="pln">divisor</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">except</span><span class="pln"> </span><span class="typ">ZeroDivisionError</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"You can't divide by zero, try another value"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	فإذا أدخل المستخدم <code>42</code> أو <code>0</code> فسينتِج <code>ZeroDivisionError</code>، مع أن 0 قيمة آمنة في هذه الحالة؛ أما غير ذلك فنطبع نتيجة القسمة ونسجل قيمة الدخل في الملف <code>errorlog.txt</code>.
</p>

<h3>
	الاستثناءات المعرفة من قبل المستخدم
</h3>

<p>
	توفر بايثون نطاقًا واسعًا من <a href="https://docs.python.org/3/library/exceptions.html" rel="external nofollow">أنواع الأخطاء القياسية</a>، ويجب أن نعيد استخدام هذه الأخطاء ما أمكن، لكن قد لا نجد خطأً يناسب احتياجنا، عندئذ نستطيع تعريف أنواع الاستثناءات الخاصة بنا للتحكم في برامجنا تحكمًا دقيقًا، وقد مررنا على تعريف الأصناف في مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r1287/" rel="">البيانات وأنواعها</a> مرورًا سريعًا، وسنعود إليها مرةً أخرى في جزئية لاحقة من هذه السلسلة.
</p>

<p>
	لا يحتوي صنف الاستثناء عادةً على محتوىً خاص به، وإنما نعرف صنفًا فرعيًا من <code>Exception</code>، ونستخدمه مثل نوع من الملصقات الذكية التي يمكن التقاطها بواسطة تعليمات <code>except</code>. لننظر في هذا المثال القصير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4669_10" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">BrokenError</span><span class="pun">(</span><span class="typ">Exception</span><span class="pun">):</span><span class="pln"> </span><span class="kwd">pass</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">BrokenError</span><span class="pln">
</span><span class="pun">...</span><span class="pln"> </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">BrokenError</span><span class="pun">:</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"We found a Broken Error"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	لاحظ أننا نستخدم اصطلاح تسمية نضيف فيه <code>Error</code> إلى نهاية اسم الصنف، وأننا نكتسب سلوك صنف <code>Exception</code> العام بإدراجه في أقواس بعد الاسم، كما سنتعلم الاكتساب أو الوراثة inheritance في البرمجة كائنية التوجه.
</p>

<p>
	يجب ملاحظة نقطة أخيرة في رفع الأخطاء، وهي أننا كنا ننهي برامجنا باستيراد <code>sys</code> واستدعاء الدالة <code>exit()‎</code>، لكن يمكن استخدام أسلوب آخر يحقق نفس النتيجة، عن طريق رفع خطأ <code>SystemExit()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4669_12" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">SystemExit</span></pre>

<p>
	وميزة هذا الأسلوب أننا لا نحتاج إلى <code>import sys</code> في البداية.
</p>

<h2>
	جافاسكربت
</h2>

<p>
	تعالج جافاسكربت الأخطاء بطريقة تشبه طريقة بايثون، باستخدام الكلمات المفتاحية <code>try</code> و<code>catch</code> و<code>throw</code> مقابل كلمات بايثون <code>try</code> و<code>except</code> و<code>raise</code>، وسننظر الآن في بعض الأمثلة، كما سنرى استخدام المبادئ نفسها التي كانت في بايثون، وقد أدخلت الإصدارات الأخيرة من جافاسكربت بنية <code>finally</code>، كما يمكن استخدام شرط <code>finally</code> في جافاسكربت مع كتلة <code>try/catch</code> في بنية واحدة. انظر توثيق جافاسكربت لمزيد من التفاصيل.
</p>

<h3>
	التقاط الأخطاء
</h3>

<p>
	تُلتقَط الأخطاء باستخدام كتلة <code>try</code> مع مجموعة من تعليمات <code>catch</code> تكاد تكون مطابقةً لما رأيناه في بايثون:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4669_14" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">try</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">var</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="typ">NonExistentFunction</span><span class="pun">();</span><span class="pln">
   document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">x</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">err</span><span class="pun">){</span><span class="pln">
   document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"We got an error in the code"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	يكمن الاختلاف الأساسي في أننا نستخدم تعليمة <code>catch</code> واحدةً فقط لكل بنية <code>try</code>، وعلينا أن نفحص الخطأ الممرَّر داخل كتلة <code>catch</code> لنرى نوعه، وهذا فوضوي موازنةً بأسلوب <code>except</code> المتعدد في بايثون والمبني على نوع الاستثناء، وسنرى مثالًا بسيطًا لاختبار قيم الأخطاء في الشيفرة التالية.
</p>

<h3>
	رفع الأخطاء
</h3>

<p>
	يمكن رفع الأخطاء باستخدام الكلمة <code>throw</code> كما استخدمنا كلمة <code>raise</code> في بايثون، كما نستطيع إنشاء أنواع الخطأ الخاصة بنا في جافاسكربت كما فعلنا في بايثون، لكن الأسهل هو استخدام سلسلة نصية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4669_16" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">try</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">throw</span><span class="pun">(</span><span class="str">"New Error"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">e</span><span class="pun">){</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e </span><span class="pun">==</span><span class="pln"> </span><span class="str">"New Error"</span><span class="pun">)</span><span class="pln">
      document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"We caught a new error"</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">
      document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"An unexpected error found"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	هذا كل ما سنشرحه حول معالجة الأخطاء، وسنرى أمثلةً عمليةً لها في المقالات التالية، كما سنرى بعض المفاهيم الأساسية التي تحدثنا عنها من قبل، مثل التسلسلات والحلقات التكرارية والفروع، مما يعني أن لديك جميع الأدوات اللازمة لإنشاء برامج قوية. يفضل الآن أن تأخذ وقتًا تحاول فيه إنشاء بعض البرامج بنفسك -ربما بضعة برامج فقط-، لتثبت تلك المفاهيم في رأسك قبل الانتقال إلى مجموعة المقالات التالية، وتستطيع البدء بالبرامج التالية:
</p>

<ul>
	<li>
		لعبة بسيطة مثل OXO.
	</li>
	<li>
		قاعدة بيانات بسيطة، ربما مبنية على دليل جهات الاتصال الخاص بنا، ولكن لتخزين مجموعة أقراصك أو مقاطع الفيديو.
	</li>
	<li>
		أداة تسجيل يوميات تتيح لك إمكانية تخزين الأحداث أو التواريخ المهمة، وربما تخرج لك إشعارًا تذكيريًا.
	</li>
</ul>

<p>
	ستحتاج إلى استخدام جميع الخصائص التي شرحناها من قبل، وربما بعض وحدات اللغات كذلك، وهنا تذكر أن تعود إلى التوثيق كل فترة، إذ ستجد أدوات أخرى تعينك على إنشاء مثل هذه البرامج، ولا تنسى أيضًا قوة محث بايثون. جرب برامجك هناك إلى أن تفهم كيفية عملها، ثم انقل ذلك إلى البرنامج الخاص بك.
</p>

<h2>
	خاتمة
</h2>

<p>
	نرجو في نهاية المقال أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		التحقق من شيفرات أخطاء VBScript باستخدام تعليمة <code>if</code>.
	</li>
	<li>
		التقاط الاستثناءات بشرط <code>except</code> في بايثون أو <code>catch</code> في جافاسكربت.
	</li>
	<li>
		توليد الاستثناءات باستخدام كلمة <code>raise</code> المفتاحية في بايثون أو <code>throw</code> في جافاسكربت.
	</li>
	<li>
		أنه يمكن أن تكون أنواع الأخطاء أصنافًا في بايثون أو سلسلةً بسيطةً في جافاسكربت.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tuterrors.htm" rel="external nofollow">للفصل الرابع عشر: Handling Errors من كتاب Learning To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D9%81%D8%B6%D8%A7%D8%A1%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D9%85%D8%A7%D8%A1-namespaces-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1362/" rel="">فضاءات الأسماء Namespaces في البرمجة</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1341/" rel="">كيفية التعامل مع النصوص في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1334/" rel="">التعامل مع الملفات في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B2%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1245/" rel="">الزلات البرمجية والأخطاء في جافاسكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1342</guid><pubDate>Fri, 22 Oct 2021 15:00:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x646;&#x635;&#x648;&#x635; &#x641;&#x64A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1341/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/615ff73767092_----.png.e79ced7d14ad3896d458c76ce28bf8f9.png" /></p>
<p>
	لا شك أن التعامل مع النصوص هو أكثر ما يفعله المبرمج في عمله لأنه يبرمج بلغات تتكون من كلمات ورموز، وهي نصوص في النهاية، لذلك توجد أدوات كثيرة جدًا في أغلب لغات البرمجة لتسهيل التعامل مع هذه النصوص، وسننظر في كيفية استخدام تلك الأدوات في تنفيذ المهام البرمجية المعتادة التي تشمل ما يلي:
</p>

<ul>
	<li>
		تقسيم الأسطر إلى مجموعات من المحارف.
	</li>
	<li>
		البحث عن سلاسل نصية داخل سلاسل أخرى.
	</li>
	<li>
		استبدال سلسلة نصية بأخرى.
	</li>
	<li>
		تغيير حالة الأحرف.
	</li>
</ul>

<p>
	سننظر في كيفية تنفيذ كل مهمة من هذه المهام باستخدام بايثون، ثم نمر عليها سريعًا في جافاسكربت وVBScript، وتُستخدم توابع <a href="https://academy.hsoub.com/programming/python/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r412/" rel="">السلاسل النصية في بايثو</a>ن للتعامل مع السلاسل النصية، فلعلك تذكر من مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r1287/" rel="">البيانات وأنواعها</a> أن التوابع تشبه الدوال المرتبطة ببيانات، ونستطيع الوصول إلى التوابع باستخدام نفس الترميز النقطي dot notation الذي نستخدمه للوصول إلى الدوال في الوحدات modules، لكننا سنستخدم البيانات نفسها بدلًا من استخدام اسم الوحدة. لننظر الآن في ذلك.
</p>

<h2>
	تقسيم السلاسل النصية
</h2>

<p>
	أولًا سنقسم <a href="https://academy.hsoub.com/programming/python/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r407/" rel="">سلسلةً نصيةً</a> إلى عدة أجزاء، والذي نحتاج إليه عند معالجة الملفات لأننا نقرأ الملف سطرًا سطرًا، لكن قد يحتوي جزء من السطر فقط على البيانات المطلوبة. من أمثلة ذلك برنامج دليل جهات الاتصال الذي نعود إليه كل حين، فقد نرغب في الوصول إلى حقول بعينها من مدخل ما، دون الحاجة لطباعة المدخل كله، وسنستخدم لهذا الغرض التابع <code>split()‎</code> في بايثون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2709_13" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Here is a (short) String"</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">split</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'Here'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'is'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'a'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'(short)'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'String'</span><span class="pun">]</span></pre>

<p>
	لاحظ كيف حصلنا على قائمة تحتوي الكلمات التي في <code>aString</code> مع حذف جميع المسافات، لأن الفاصل الافتراضي للدالة <code>‎''.split()‎</code> هو المسافة البيضاء، سواءً كانت سطرًا جديدًا، أم مسافةً عادية، أم مسافة جدول tab. لنجرب الآن استخدامه مرةً أخرى بجعل الفاصل قوسًا افتتاحيًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_16" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">'('</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="str">'Here is a '</span><span class="pun">,</span><span class="pln"> </span><span class="str">'short) String'</span><span class="pun">]</span></pre>

<p>
	يكمن الفرق هنا في أننا حصلنا على عنصرين فقط في القائمة، وقد حُذف القوس الافتتاحي من بداية <code>‎'short)'‎</code>، وهذه ملاحظة مهمة حول <code>‎''.split()‎</code>، وهي حذفه للمحارف الفاصلة، الذي نريده غالبًا مع استثناءات قليلة.
</p>

<p>
	كذلك لدينا التابع <code>‎''.join()‎</code> الذي يأخذ قائمةً -أو أي نوع آخر- من التسلسلات النصية ويدمجها معًا، لكن له خاصية قد تسبب حيرةً عند استخدامه، وهو استخدامه السلسلة التي نستدعي التابع عليها محرفًا للدمج، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_18" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> lst </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'here'</span><span class="pun">,</span><span class="str">'is'</span><span class="pun">,</span><span class="str">'a'</span><span class="pun">,</span><span class="str">'list'</span><span class="pun">,</span><span class="str">'of'</span><span class="pun">,</span><span class="str">'words'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">'-+-'</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">lst</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
here</span><span class="pun">-+-</span><span class="pln">is</span><span class="pun">-+-</span><span class="pln">a</span><span class="pun">-+-</span><span class="pln">list</span><span class="pun">-+-</span><span class="pln">of</span><span class="pun">-+-</span><span class="pln">words
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">' '</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">lst</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
here is a list of words</span></pre>

<p>
	رغم منطقية هذا السلوك، إلا أنه يبدو غريبًا عند رؤيته لأول مرة، كما أنه سلوك مناقض لما هو موجود في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-strings-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r817/" rel="">جافاسكربت</a> التي تحوي تابع مصفوفة اسمه <code>join</code>، وتكون السلسلة الدامجة فيه معامِلًا.
</p>

<h3>
	عد الكلمات
</h3>

<p>
	سنعيد النظر مرةً أخرى في برنامج عد الكلمات الذي أوردناه في مقال <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-r1333/" rel="">البرمجة باستخدام الوحدات</a>، الذي كانت الشيفرة الوهمية فيه كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2709_20" style=""><span class="kwd">def</span><span class="pln"> numwords</span><span class="pun">(</span><span class="pln">aString</span><span class="pun">):</span><span class="pln">
    list </span><span class="pun">=</span><span class="pln"> split</span><span class="pun">(</span><span class="pln">aString</span><span class="pun">)</span><span class="pln"> </span><span class="com"># قائمة بكل عنصر وكلمة</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">list</span><span class="pun">)</span><span class="pln"> </span><span class="com"># تعيد عددًا من العناصر في القائمة</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> file</span><span class="pun">:</span><span class="pln">
    total </span><span class="pun">=</span><span class="pln"> total </span><span class="pun">+</span><span class="pln"> numwords</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln"> </span><span class="com"># accumulate totals for each line</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"File had %d words"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> total </span><span class="pun">)</span></pre>

<p>
	لننظر إلى متن دالة <code>numwords()‎</code> بما أننا شرحنا كيفية جلب الأسطر من الملف، حيث نريد أن ننشئ قائمةً من الكلمات في سطر، وذلك باستخدام التابع <code>‎''.split()‎</code> الافتراضي. وإذا نظرنا في توثيق <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> فسنجد أن دالة <code>len()‎</code> المضمَّنة تعيد عدد العناصر في قائمة ما، ويجب أن يكون ذلك العدد في حالتنا عدد الكلمات في السلسلة النصية، وهو ما نريده بالضبط، وعلى ذلك تبدو الشيفرة النهائية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2709_26" style=""><span class="kwd">def</span><span class="pln"> numwords</span><span class="pun">(</span><span class="pln">aString</span><span class="pun">):</span><span class="pln">
    lst </span><span class="pun">=</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">split</span><span class="pun">()</span><span class="pln"> </span><span class="com"># split() aString هو تابع كائن السلسلة </span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">lst</span><span class="pun">)</span><span class="pln">       </span><span class="com"># أعد عدد العناصر في القائمة</span><span class="pln">

</span><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"menu.txt"</span><span class="pun">,</span><span class="str">"r"</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
   total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">  </span><span class="com"># initialize to zero; also creates variable</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
      total </span><span class="pun">+=</span><span class="pln"> numwords</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">  </span><span class="com"># راكم إجمالي كل سطر</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"File had %d words"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> total </span><span class="pun">)</span></pre>

<p>
	لكن هذه الشيفرة تحسب محارفًا مثل <code>&amp;</code> على أنها كلمات، وهذا ليس صحيحًا، كما أنه لا يمكن استخدامها إلا على ملف واحد فقط هو menu.txt، رغم إمكانية تحويلها لتقرأ اسم الملف من سطر الأوامر <code>argv[1]‎</code>، أو عبر <code>input()‎</code> كما رأينا في مقال <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-r1311/" rel="">كيفية قراءة البرامج لمدخلات المستخدم</a>، وسنترك هذا تدريبًا للقارئ.
</p>

<h2>
	البحث في النصوص
</h2>

<p>
	ستكون العملية التالية التي ننظر فيها هي البحث عن سلسلة فرعية داخل سلسلة أكبر منها، وتدعم بايثون هذا من خلال تابع السلسلة <code>‎''.find()‎</code> الخاص بها، وأبسط استخدامات هذا التابع تزويده بسلسلة للبحث، وتعيد بايثون فهرس أول محرف من السلسلة الفرعية إذا وجدتها داخل السلسلة الرئيسية، أما إذا لم تجدها فستعيد <code>‎-1</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_28" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"here is a long string with a substring inside it"</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="str">'long'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="lit">10</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="str">'oxen'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">-</span><span class="lit">1</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="str">'string'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="lit">15</span></pre>

<p>
	لقد كان المثالان الأولان واضحين ومباشرين، فالأول يعيد فهرس بداية <code>‎'long'‎</code>، أما الثاني فيعيد <code>-1</code>، وذلك لأن <code>‎'oxen'‎</code> غير موجودة داخل <code>aString</code>؛ بينما المثال الثالث ففيه أمر مثير للاهتمام، إذ لا تحدد <code>find</code> إلا الورود الأول لسلسلة البحث فقط، لكن ماذا لو كانت سلسلة البحث مكررةً أكثر من مرة في السلسلة الأصلية؟ من الممكن هنا أن نستخدم فهرس المرة الأولى لورود سلسلة البحث لنقسم السلسلة الأصلية إلى جزأين ونبحث مرةً أخرى، ونكرر ذلك إلى أن نحصل على النتيجة <code>‎-1</code>، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_30" style=""><span class="pln">aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bow wow says the dog, how many ow's are in this string?"</span><span class="pln">
temp </span><span class="pun">=</span><span class="pln"> aString</span><span class="pun">[:]</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">استخدم</span><span class="pln"> </span><span class="pun">التقسيم</span><span class="pln"> </span><span class="pun">لصنع</span><span class="pln"> </span><span class="pun">نسخة</span><span class="pln">
count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
index </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="str">'ow'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> index </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">:</span><span class="pln">
    count </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    temp </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">[</span><span class="pln">index </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:]</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">استخدم</span><span class="pln"> </span><span class="pun">التقسيم</span><span class="pln"> </span><span class="pun">هنا.</span><span class="pln">
    index </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="str">'ow'</span><span class="pun">)</span><span class="pln">

print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"We found %d occurrences of 'ow' in %s"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">count</span><span class="pun">,</span><span class="pln"> aString</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	وهنا نكون قد عددنا مرات الحدوث فقط، لكن كان بإمكاننا جمع نتائج الفهرس في قائمة من أجل المعالجة لاحقًا.
</p>

<p>
	يستطيع التابع <code>find()‎</code> أن يسرّع من هذه العملية قليلًا باستخدام أحد المعامِلات الاختيارية الخاصة به، وهو موضع البداية في السلسلة الأصلية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_32" style=""><span class="pln">aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bow wow says the dog, how many ow's are in this string?"</span><span class="pln">
count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
index </span><span class="pun">=</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="str">'ow'</span><span class="pun">)</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">استخدم</span><span class="pln"> </span><span class="pun">البدء</span><span class="pln"> </span><span class="pun">الافتراضي</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> index </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">:</span><span class="pln">
    count </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    index </span><span class="pun">=</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="str">'ow'</span><span class="pun">,</span><span class="pln"> index</span><span class="pun">+</span><span class="lit">1</span><span class="pun">)</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">اضبط</span><span class="pln"> </span><span class="pun">بدءًا</span><span class="pln"> </span><span class="pun">جديدًا</span><span class="pln">

print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"We found %d occurrences of 'ow' in %s"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">count</span><span class="pun">,</span><span class="pln"> aString</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	يلغي هذا الحل الحاجة إلى إنشاء سلسلة نصية جديدة في كل مرة، وهو الأمر الذي قد يبطئ العملية إذا كانت السلسلة طويلةً، وإذا علمنا أن السلسلة الفرعية ستكون في بداية السلسلة الأصلية، أو لم نهتم لمرات الحدوث الأخرى، فمن الممكن أن نحدد قيمتي بداية ونهاية البحث، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_34" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">قصر</span><span class="pln"> </span><span class="pun">البحث</span><span class="pln"> </span><span class="pun">على</span><span class="pln"> </span><span class="pun">أول</span><span class="pln"> </span><span class="lit">20</span><span class="pln"> </span><span class="pun">محرف</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bow wow says the dog, how many ow's are in the string?"</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="str">'the'</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">20</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span></pre>

<p>
	توفر بايثون عدة توابع أخرى لمواقف البحث الشائعة، مثل <code>‎''.startswith()‎</code> و<code>‎''.endswith()‎</code>، ونستطيع أن نخمن وظائف هذه التوابع بمجرد قراءة أسمائها، وهي تعيد إما <code>True</code> أو <code>False</code> بناءً على بدء السلسلة بسلسلة نصية معطاة أو انتهائها بها، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_36" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Python rocks!"</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">"Perl"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Python rocks!"</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'Python'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Python rocks!"</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'sucks!'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Python rocks!"</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'cks!'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">True</span></pre>

<p>
	لاحظ أنها تعطينا نتائج بوليانيةً، حيث سنعلم أين نبحث إذا كانت الإجابة <code>True</code>. كذلك لاحظ أن سلسلة البحث لا يجب أن تكون كلمةً كاملة، بل تكفي سلسلة نصية فرعية. يمكن تزويد موضعي البدء <code>start</code> والانتهاء <code>stop</code> داخل السلسلة النصية، تمامًا مثل <code>‎''.find()‎</code>، لنتحقق من وجود سلسلة نصية فرعية في أي موضع معطىً داخل السلسلة النصية، ولا تستخدَم هذه الخاصية الأخيرة في البرمجة العملية كثيرًا. كما يمكن استخدام عامل <code>in</code> الخاص ببايثون لإجراء اختبار بسيط للتحقق من وجود سلسلة نصية فرعية في أي مكان داخل سلسلة أخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_38" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="str">'foo'</span><span class="pln"> in </span><span class="str">'foobar'</span><span class="pun">:</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">'True'</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="str">'baz'</span><span class="pln"> in </span><span class="str">'foobar'</span><span class="pun">:</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">'True'</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="str">'bar'</span><span class="pln"> in </span><span class="str">'foobar'</span><span class="pun">:</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">'True'</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">True</span></pre>

<h2>
	استبدال النصوص
</h2>

<p>
	بما أننا عثرنا على النص الذي نريده، فلنغيره الآن إلى شيء آخر. توفر توابع <a href="https://academy.hsoub.com/programming/python/%D8%A2%D9%84%D9%8A%D8%A9-%D9%81%D9%87%D8%B1%D8%B3%D8%A9-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D8%B3%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%8A%D8%A9-%D9%88%D8%B7%D8%B1%D9%8A%D9%82%D8%A9-%D8%AA%D9%82%D8%B3%D9%8A%D9%85%D9%87%D8%A7-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r417/" rel="">السلاسل النصية في بايثون</a> لهذا حلًا متمثلًا في التابع <code>‎''.replace()‎</code> الذي يأخذ وسيطين، هما سلسلتا البحث والاستبدال، وتكون القيمة المعادة هي السلسلة الجديدة الناتجة عن الاستبدال.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2709_40" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Mary had a little lamb, its fleece was dirty!"</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'dirty'</span><span class="pun">,</span><span class="str">'white'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="str">"Mary had a little lamb, its fleece was white!"</span></pre>

<p>
	إن الفرق الأساسي بين <code>‎''.find()‎</code> و<code>‎''.replace‎</code> هو أن الأخير يستبدل جميع مرات الحدوث في سلسلة البحث، وليس المرة الأولى فقط، ويُستخدم الوسيط الاختياري <code>count</code> لتقييد عدد مرات الاستبدال، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_42" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Bow wow wow said the little dog"</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'ow'</span><span class="pun">,</span><span class="str">'ark'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">Bark</span><span class="pln"> wark wark said the little dog
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">'ow'</span><span class="pun">,</span><span class="str">'ark'</span><span class="pun">,</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">واحد</span><span class="pln"> </span><span class="pun">فقط</span><span class="pln">
</span><span class="typ">Bark</span><span class="pln"> wow wow said the little dog</span></pre>

<p>
	من الممكن إجراء عمليات بحث واستبدال معقدة باستخدام ما يسمى بالتعبير النمطي regular expression، لكنها معقدة وسنتحدث عنها في مقال آخر لاحقًا.
</p>

<h2>
	تغيير حالة الأحرف
</h2>

<p>
	مما يجب مراعاته في النصوص هو كيفية التحويل من الحالة الصغرى للحروف إلى الحالة الكبرى، وإن كان هذا غير شائع، إلا أن بايثون توفر بعض التوابع المساعدة لذلك على أي حال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_44" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"MIXed Case"</span><span class="pun">.</span><span class="pln">lower</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
mixed </span><span class="kwd">case</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"MIXed Case"</span><span class="pun">.</span><span class="pln">upper</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
MIXED CASE
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"MIXed Case"</span><span class="pun">.</span><span class="pln">swapcase</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
mixED cASE
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"MIXed Case"</span><span class="pun">.</span><span class="pln">capitalize</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">Mixed</span><span class="pln"> </span><span class="kwd">case</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">'MIXed Case'</span><span class="pun">.</span><span class="pln">title</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">Mixed</span><span class="pln"> </span><span class="typ">Case</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"TEST"</span><span class="pun">.</span><span class="pln">isupper</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"TEST"</span><span class="pun">.</span><span class="pln">islower</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">False</span></pre>

<p>
	لاحظ أن التابع <code>‎''.capitalize()‎</code> يغير حالة الأحرف إلى الحالة الكبرى للسلسلة النصية كلها، وليس لكل كلمة فيها؛ أما تغيير حالة كل كلمة فينفذها التابع <code>title()‎</code>.
</p>

<p>
	انتبه أيضًا إلى سلوك دالتي الاختبار <code>‎''.isupper()‎</code> و<code>‎''.islower()‎</code>، إذ توفر <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a> دوالًا توكيديةً مثل هذه لاختبار السلاسل النصية، منها: <code>‎''.isdigit()‎</code> و<code>‎''.isalpha()‎</code> و<code>‎''.isspace()‎</code>، وتتحقق الدالة الأخيرة من جميع أنواع المسافات البيضاء، لا محارف المسافة العادية فقط.
</p>

<p>
	وسنستخدم عدة توابع من هذا النمط، خاصةً في عد الكلمات.
</p>

<h2>
	التعامل مع النصوص في VBScript
</h2>

<p>
	تنحدر VBScript من لغة BASIC القديمة، لذا تحتوي على الكثير من دوال معالجة النصوص المدمجة فيها، وقد تجد 20 دالةً أو تابعًا في توثيقها، بالإضافة إلى الدوال الموجودة لمعالجة محارف اليونيكود، مما يعني أننا نستطيع فعل كل ما فعلناه في بايثون باستخدام VBScript، وسنمر عليها سريعًا فيما يلي:
</p>

<h3>
	تقسيم النصوص
</h3>

<p>
	نبدأ بدالة <code>split</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_46" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> s
</span><span class="typ">Dim</span><span class="pln"> lst
s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Here is a string of words"</span><span class="pln">
lst </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Split</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln"> </span><span class="str">'</span><span class="pln"> returns an array
</span><span class="typ">MsgBox</span><span class="pln"> lst</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	كما في بايثون، نستطيع إضافة قيمة فاصلة إذا أردنا، غير فاصل المسافة البيضاء العادي، كذلك لدينا دالة <code>Join</code> لعكس هذه العملية.
</p>

<h3>
	البحث عن النصوص واستبدالها
</h3>

<p>
	نبحث باستخدام <code>InStr</code>، وهو اختصار لـ In String:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_48" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> s</span><span class="pun">,</span><span class="pln">n
s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Here is a long string of text"</span><span class="pln">
n </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InStr</span><span class="pun">(</span><span class="pln">s</span><span class="pun">,</span><span class="pln"> </span><span class="str">"long"</span><span class="pun">)</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"long is found at position: "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">CStr</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	القيمة المعادة هنا هي الموضع الذي تبدأ فيه السلسلة الفرعية داخل السلسلة الأصلية، فإذا لم توجد السلسلة الفرعية فستعيد صفرًا، وهذه ليست مشكلةً بما أن VBScript تبدأ فهارسها بواحد وليس صفر، لذا لا يُعَد الصفر هنا فهرسًا صالحًا؛ أما إذا كانت إحدى السلسلتين <code>Null</code>، فستعيد القيمة <code>Null</code>، مما يجعل عملية اختبار شروط الخطأ أكثر صعوبةً وتحتاج إلى عدة اختبارات معًا.
</p>

<p>
	يمكن تحديد نطاق فرعي من السلسلة الأصلية للبحث فيه باستخدام قيمة بادئة، كما فعلنا في بايثون، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_50" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> s</span><span class="pun">,</span><span class="pln">n
s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Here is a long string of text"</span><span class="pln">
n </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InStr</span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">,</span><span class="pln"> </span><span class="str">"long"</span><span class="pun">)</span><span class="pln"> </span><span class="str">'</span><span class="pln"> start at position </span><span class="lit">6</span><span class="pln">
</span><span class="typ">If</span><span class="pln"> n </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> or n </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Null</span><span class="pln"> </span><span class="typ">Then</span><span class="pln"> </span><span class="str">'</span><span class="pln"> check </span><span class="kwd">for</span><span class="pln"> errors
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"long was not found"</span><span class="pln">
</span><span class="typ">Else</span><span class="pln">
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"long is found at position: "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">CStr</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">If</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ونستطيع تحديد كون البحث حساسًا لحالة الأحرف أم لا، وهذا غير موجود في بايثون، والوضع الافتراضي للبحث هو أن يكون حساسًا لحالة الأحرف.
</p>

<p>
	تستبدَل النصوص باستخدام الدالة <code>Replace</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_52" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> s
s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"The quick yellow fox jumped over the log"</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="typ">Replace</span><span class="pun">(</span><span class="pln">s</span><span class="pun">,</span><span class="pln"> </span><span class="str">"yellow"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"brown"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ونستطيع توفير وسيط اختياري ليحدد عدد مرات الحدوث في سلسلة البحث التي يجب استبدالها، والوضع الافتراضي هو استبدالها جميعًا، لكن يمكن تحديد موضع بدء كما في <code>InStr</code> أعلاه.
</p>

<h3>
	تغيير الحالة
</h3>

<p>
	تغيّر الحالة في VBScript بواسطة <code>UCase</code> و<code>LCase</code>، لكن لا يوجد فيها ما يكافئ التابعين <code>capitalize</code> و<code>title</code> الموجودين في بايثون:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted" id="ips_uid_2709_54" style=""><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/vbscript"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> s
s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"MIXed Case"</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="typ">LCase</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="typ">UCase</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	وهذا ما سنغطيه من معالجة النصوص في VBScript، فإذا أردت المزيد فارجع إلى ملف مساعدة VBScript لترى القائمة الكاملة للدوال.
</p>

<h2>
	التعامل مع النصوص في جافاسكربت
</h2>

<p>
	تُعَد جافاسكربت أقل اللغات الثلاث تجهيزًا للتعامل مع النصوص، لكن العمليات الأساسية موجودة إلى حد ما، رغم افتقارها إلى العدد الكبير من التوابع والدوال الموجودة في بايثون وVBScript للتعامل مع النصوص، وهي تعوض ذلك بدعم قوي <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-regular-expressions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1278/" rel="">للتعابير النمطية</a>، حيث تعوض بدائية الدوال الموجودة كثيرًا، لكن على حساب تعقيد التعابير النمطية، وهي تأخذ المنظور كائني التوجه، مثل بايثون في التعامل مع السلاسل النصية، حيث تُنفَّذ المهام باستخدام توابع الصنف <code>String</code>.
</p>

<h3>
	تقسيم النصوص
</h3>

<p>
	تقسَّم النصوص في جافاسكربت باستخدام التابع <code>split</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_56" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> aList</span><span class="pun">,</span><span class="pln"> aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Here is a short string"</span><span class="pun">;</span><span class="pln">
aList </span><span class="pun">=</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">" "</span><span class="pun">);</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">aList</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]);</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لاحظ أن جافاسكربت تتطلب تزويدها بمحرف الفصل، فليس لديها قيمة افتراضية له، والفاصل هنا هو تعبير نمطي، مما يجعل عمليات الفصل المعقدة ممكنةً. وقد ذكرنا سابقًا أن النصوص تُدمج باستخدام تابع المصفوفة <code>Join</code>، لذا فإن عكس عملية التقسيم أعلاه سيكون كما يلي:
</p>

<pre class="ipsCode">  aList.join(" ")  // ادمج عناصر مفصولة بمسافات
</pre>

<h3>
	 البحث في النصوص
</h3>

<p>
	نبحث في النصوص في جافاسكربت باستخدام التابع <code>search()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_58" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Round and Round the ragged rock ran a rascal"</span><span class="pun">;</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln"> </span><span class="str">"ragged is at position: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> aString</span><span class="pun">.</span><span class="pln">search</span><span class="pun">(</span><span class="str">"ragged"</span><span class="pun">));</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	وهنا يكون وسيط سلسلة البحث تعبيرًا نمطيًا أيضًا كي نتمكن من إجراء عمليات بحث معقدة، لكن انتبه إلى عدم وجود طريقة لتقييد نطاق السلسلة الأصلية الذي يُبحث فيه، وذلك من خلال تمرير موضع بدء، رغم إمكانية محاكاة ذلك باستخدام التعابير النمطية على أي حال.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		توفر جافاسكربت عملية بحث أخرى لها سلوك مختلف تسمى <code>match()‎</code>، لكننا لن نشرح استخدامها هنا.
	</p>
</blockquote>

<h3>
	استبدال النصوص
</h3>

<p>
	يُستخدم التابع <code>replace()‎</code> لاستبدال النصوص كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_60" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Humpty Dumpty sat on a cat"</span><span class="pun">;</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">aString</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">"cat"</span><span class="pun">,</span><span class="str">"wall"</span><span class="pun">));</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	يمكن أن تكون سلسلة البحث تعبيرًا نمطيًا بحيث نرى هنا السلوك المتوقع، إذ تستبدل عملية الاستبدال جميع نسخ سلسلة البحث، ونستطيع القول أنه لا توجد طريقة تقيد عملية الاستبدال في جزء من السلسلة أو مرة حدوث واحدة دون تقسيم السلسلة أولًا ثم إعادة دمجها مرةً أخرى.
</p>

<h3>
	تغيير الحالة
</h3>

<p>
	تغيَّر حالة الأحرف في جافاسكربت باستخدام دالتين هما <code>toLowerCase()‎</code> و<code>toUpperCase()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2709_62" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> aString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"This string has Mixed Case"</span><span class="pun">;</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">aString</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">()+</span><span class="pln"> </span><span class="str">"&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">aString</span><span class="pun">.</span><span class="pln">toUpperCase</span><span class="pun">()+</span><span class="pln"> </span><span class="str">"&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	تغني بساطة هذين التابعين عن شرحهما، والجدير فقط بالذكر هنا أن جافاسكربت على عكس اللغات الأخرى، توفر دوالًا كثيرةً لمعالجة HTML، لأنها لغة برمجة ويب بالأساس، ويمكن الرجوع إلى تلك الدوال في توثيق اللغة، إذ هي خارج مجال حديثنا.
</p>

<h2>
	خاتمة
</h2>

<p>
	مررنا على الدوال والتوابع المستخدمة للتعامل مع النصوص التي قد تراها في مشاريعك، ونود الإشارة هنا إلى وجوب النظر في التوثيق الرسمي للغة التي تعمل بها عند معالجة النصوص، إذ توجد أدوات قوية لمثل هذه العمليات والمهام الضرورية في البرمجة، وننصح بالبحث أولًا في <a href="https://wiki.hsoub.com/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" rel="external">التوثيقات المتوفرة في موسوعة حسوب</a>، وهي توثيقات عربية مترجمة من التوثيقات الرسمية للغات أو من أمهات الكتب فيها، ونود أن تخرج من هذا المقال بما يلي:
</p>

<ul>
	<li>
		معالجة النصوص عملية شائعة لها دعم قوي مضمَّن في أغلب اللغات.
	</li>
	<li>
		أكثر المهام شيوعًا هي تقسيم النصوص والبحث فيها، واستبدالها، وتغيير حالة الأحرف فيها.
	</li>
	<li>
		توفر كل لغة مستويات مختلفة من الدعم، لكن العمليات الثلاث الأساسية متاحة دومًا.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tuttext.htm" rel="external nofollow">للفصل الثالث عشر: Manipulating Text من كتابة Learning To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1342/" rel="">كيفية التعامل مع الأخطاء البرمجية</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1334/" rel="">التعامل مع الملفات في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">ما هي البرمجة ومتطلبات تعلمها؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1341</guid><pubDate>Sat, 16 Oct 2021 15:04:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x645;&#x644;&#x641;&#x627;&#x62A; &#x641;&#x64A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1334/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/615816bf33340_----.png.d3b31cbe6527aded8e7f5e7d7ed7c16f.png" /></p>
<p>
	لا تختلف الملفات من منظور برمجي عن الملفات التي نستخدمها في برامج معالجة الكلمات أو أي برامج أخرى، والتي نفتحها ونكتب فيها بعض المهام أو التعليمات ثم نغلقها مرةً أخرى، لكن أحد الفروق الرئيسية هنا هو أننا نقرأ الملف تتابعيًا، أي نقرأ سطرًا واحدًا في كل مرة من بدايته، ورغم أن برامج معالجة الكلمات تنتهج هذا النهج أيضًا، إلا أنها تحتفظ بالملف كله في الذاكرة أثناء عملنا عليه، ثم تنفذ عملية الكتابة كلها عند إغلاقها، وهناك فرق آخر بين الملفات البرمجية والعادية، وهو أننا حين نبرمج فإننا نفتح الملف للقراءة فقط أو الكتابة فقط، وننفذ الكتابة بإنشاء ملف جديد من الصفر أو إلغاء ملف موجود والكتابة فوقه، أو بإلحاق الملف الجديد إلى ملف موجود من قبل، كما يمكن العودة في الملفات البرمجية إلى بداية الملف أثناء معالجته.
</p>

<h2>
	الدخل والخرج بالملفات
</h2>

<p>
	لنطبق مثالًا عمليًا، ولنفترض وجود ملف اسمه <code>menu.txt</code>، يحتوي على قائمة من الوجبات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8059_15" style=""><span class="pln">steak &amp; eggs
steak &amp; chips
steak &amp; steak</span></pre>

<p>
	لنكتب برنامجًا يقرأ الملف ويعرض الخرج كما يفعل أمر <code>cat</code> في صدفة يونكس، وأمر <code>type</code> في صدفة ويندوز.
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_8059_17" style=""><span class="com"># (r) افتح الملف للقراءة</span><span class="pln">
inp </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"menu.txt"</span><span class="pun">,</span><span class="str">"r"</span><span class="pun">)</span><span class="pln">
</span><span class="com"># اقرأ الملف سطرًا سطرًا</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> line </span><span class="pun">)</span><span class="pln">
</span><span class="com"># أغلق الملف مرة أخرى</span><span class="pln">
inp</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	تأخذ <code>open()‎</code> وسيطين، الأول هو اسم الملف الذي يمكن أن يكون متغيرًا أو سلسلةً نصيةً مجردةً literal string كما فعلنا هنا، والوسيط الثاني هو الوضع الذي نفتح به الملف، حيث يمكن فتحه للقراءة فقط <code>r</code> أو للكتابة <code>w</code>، كما نحدد هل هو للاستخدام النصي أم للاستخدام الثنائي binary، وذلك بإضافة محرف <code>b</code> إلى <code>r</code> أو <code>w</code> في حالة الاستخدام الثنائي، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_19" style=""><span class="pln">open</span><span class="pun">(</span><span class="pln">fn</span><span class="pun">,</span><span class="str">"rb"</span><span class="pun">)</span></pre>

<p>
	لاحظ أننا نقرأ الملف في حلقة <code>for</code>، التي تتصرف في بايثون مثل حلقة foreach في تجميعة، إذ تعيد كل عنصر في التجميعة، ويمكن النظر إلى الملف النصي على أنه تجميعة من الأسطر، وهكذا تقرأ الحلقة كل سطر على حدة.
</p>

<p>
	ثم نغلق الملف باستخدام دالة مسبوقة بمتغير ملف، وتُعرف هذه الصياغة باستدعاء التابع method invocation كما شرحنا في <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-r1333/" rel="">المقال السابق</a> حول البرمجة باستخدام الوحدات، ويمكن تقريب مفهوم متغير الملف بأنه وحدة تحتوي الدوال التي تعمل على الملفات، ونستوردها في كل مرة ننشئ متغيرًا من نوع ملف.
</p>

<p>
	تُغلَق الملفات تلقائيًا في بايثون في نهاية البرنامج، لكن من الأفضل أن نتعود على إغلاق الملفات إغلاقًا صريحًا، لأن نظام التشغيل قد لا يكتب البيانات إلى الملف إلا عند إغلاقه لأسباب تتعلق بتسريع أدائه، مما يعني أن بياناتنا قد لا تكتَب إلى الملف إذا خرج البرنامج فجأةً، لذا يفضَّل التعود على إغلاق الملف بمجرد الانتهاء من الكتابة فيه.
</p>

<p>
	كما أننا لم نحدد المسار الكامل للملف الموجود في الشيفرة أعلاه، لذا سنتعامل مع الملف على أنه موجود في المجلد الحالي، لكن يمكن تمرير الاسم الكامل للمسار إلى <code>open()‎</code> بدلًا من اسم الملف مجردًا. قد نواجه مشكلةً بسيطةً في هذا الشأن في <a href="https://academy.hsoub.com/apps/windows/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-windows-10-r172/" rel="">نظام ويندوز</a>، إذ يُستخدم المحرف <code>\</code> لفصل المجلدات في مسارات ويندوز، لكن نفس المحرف له معنىً خاص آخر في سلاسل بايثون، لذلك يفضل استخدام المحرف <code>/</code> عند تحديد المسارات في بايثون لضمان عملها على أي نظام تشغيل بما فيها ويندوز.
</p>

<p>
	عند التعامل مع ملف طويل لن نستطيع عرضه كاملًا على الشاشة مرةً واحدةً، وعلينا التوقف بعد كل شاشة كاملة، لذا نستخدم المتغير <code>line_count</code> ونزيده بعد قراءة كل سطر، ثم نتحقق هل يساوي 25 -إذا كانت الشاشة تحتوي على 25 سطرًا- أم لا، ثم سنطلب من المستخدم أن يضغط على زر ما عندما يساوي 25، وليكن زر الإدخال مثلًا، قبل إعادة ضبط عداد <code>line_count</code> إلى الصفر والمتابعة بعد ذلك.
</p>

<p>
	توجد طريقة أخرى لقراءة الملفات باستخدام حلقة <code>while</code> وتابع لكائن الملف اسمه <code>readline()‎</code>، وتمتاز هذه الطريقة بأننا نستطيع التوقف عن معالجة الملف بمجرد العثور على البيانات التي نريدها، مما يسرع الأداء كثيرًا إذا كنا نتعامل مع ملفات طويلة، لكنها أعقد، لذا سننظر في مثالنا السابق باستخدام هذه الطريقة لنشرحها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_21" style=""><span class="com"># افتح الملف للقراءة</span><span class="pln">
inp </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"menu.txt"</span><span class="pun">,</span><span class="str">"r"</span><span class="pun">)</span><span class="pln">
</span><span class="com"># اقرأ الملف واطبع كل سطر</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
    line </span><span class="pun">=</span><span class="pln"> inp</span><span class="pun">.</span><span class="pln">readline</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> line</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">break</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> line </span><span class="pun">)</span><span class="pln">
</span><span class="com"># أغلق الملف</span><span class="pln">
inp</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	لاحظ أننا استخدمنا تقنية <code><a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-break-%D9%88-continue-%D9%88-pass-%D8%B9%D9%86%D8%AF-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r511/" rel="">break</a></code> التي ذكرناها في مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/" rel="">مقدمة في البرمجة الشرطية</a>، وذلك للخروج من الحلقة إذا كان السطر فارغًا، إذ يَعُد السطر الفارغ بالاصطلاح البولياني قيمة <code>false</code>، ثم طبعنا كل سطر وكررنا الحلقة مرةً أخرى، ثم أغلقنا الملف بعد الخروج من حلقة <code>while</code>. وإذا رغبنا في التوقف عند نقطة ما في الملف، فسيكون ذلك بشرط فرع branch condition داخل حلقة <code>while</code>، فإذا اكتشفنا شرط الإيقاف فسنستدعي <code>break</code> أيضًا لتنتهي الحلقة.
</p>

<p>
	هذا كل ما يتعلق بفتح الملف وقراءته والتعامل معه بالطريقة التي تريدها مما سبق، لكن في المثال السابق ملاحظة صغيرة، فالأسطر المقروءة من الملف لها محرف سطر جديد في نهايتها، لذا سيكون لدينا أسطر فارغة إذا استخدمنا <code>print()‎</code> التي تضيف محرف السطر الجديد الخاص بها، ولتجنب هذا الأمر وفّرت بايثون تابع سلسلة نصية اسمه <code>strip()‎</code> يحذف المسافات البيضاء أو المحارف التي لا تُطبع من كلا طرفي السلسلة النصية، كما توجد توابع مثل <code>rstrip</code> و<code>lstrip</code> اللذين يُحذفان المسافات من جانب واحد فقط، وبناءً عليه نستطيع إصلاح مشكلة المسافات إذا استبدلنا السطر التالي بسطر <code>print()‎</code> السابق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_23" style=""><span class="pln">    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> line</span><span class="pun">.</span><span class="pln">rstrip</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">  </span><span class="com"># احذف الجانب الأيمن فقط</span><span class="pln">
    end</span></pre>

<p>
	إذا أردنا إنشاء أمر نسخ في بايثون، فإننا نفتح ملفًا جديدًا في وضع الكتابة ثم نكتب الأسطر إليه بدلًا من طباعتها، سننشئ ملفًا اسمه <code>MENU.BAK</code> يكافئ الملف <code>MENU.TXT</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_27" style=""><span class="com"># افتح الملفين للقراءة والكتابة على الترتيب</span><span class="pln">
inp </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"menu.txt"</span><span class="pun">,</span><span class="str">"r"</span><span class="pun">)</span><span class="pln">
outp </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"menu.bak"</span><span class="pun">,</span><span class="str">"w"</span><span class="pun">)</span><span class="pln">

</span><span class="com"># اقرأ الملف ناسخًا كل سطر إلى الملف الجديد</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
    outp</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"1 file copied..."</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

</span><span class="com"># أغلق الملفات</span><span class="pln">
inp</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
outp</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	لاحظ أننا أضفنا تعليمة <code>print()‎</code> في النهاية كي نطمئن المستخدم بحدوث شيء ما، لأن التغذية الراجعة للمستخدم تنفع ولا تضر، ولم نتعرض هنا لمشاكل مع محارف الأسطر الجديدة لأننا كتبنا نفس السطر <code>line</code> الذي قرأناه، لكن إذا كنا نكتب سلاسل نصيةً ننشئها بأنفسنا، أو سلاسل حذفنا منها محارف الأسطر الجديدة من قبل، فسيكون علينا إضافة سطر جديد إلى نهاية سلسلة الخرج، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_29" style=""><span class="pln">outp</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">line </span><span class="pun">+</span><span class="pln"> </span><span class="str">'\n'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># \n =&gt; سطر جديد</span></pre>

<p>
	لننظر في كيفية تطبيق هذا في برنامج النسخ. سنضيف تاريخ اليوم في الأعلى بدلًا من مجرد نسخ القائمة، وبهذا نستطيع إنشاء قائمة يومية من ملف نصي للوجبات يسهل تعديله، وكل ما علينا فعله هو كتابة بعض الأسطر في بداية الملف الجديد قبل نسخ ملف menu.txt، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_31" style=""><span class="kwd">import</span><span class="pln"> time
</span><span class="com"># MENU.TXT أنشئ القائمة اليومية وفقًا لـ</span><span class="pln">
</span><span class="com"># افتح الملفات للقراءة والكتابة على الترتيب</span><span class="pln">
inp </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"menu.txt"</span><span class="pun">,</span><span class="str">"r"</span><span class="pun">)</span><span class="pln">
outp </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"menu.prn"</span><span class="pun">,</span><span class="str">"w"</span><span class="pun">)</span><span class="pln">

</span><span class="com"># أنشئ سلسلة تاريخ اليوم </span><span class="pln">
today </span><span class="pun">=</span><span class="pln"> time</span><span class="pun">.</span><span class="pln">localtime</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="pln">time</span><span class="pun">())</span><span class="pln">
theDate </span><span class="pun">=</span><span class="pln"> time</span><span class="pun">.</span><span class="pln">strftime</span><span class="pun">(</span><span class="str">"%A %B %d"</span><span class="pun">,</span><span class="pln"> today</span><span class="pun">)</span><span class="pln">

</span><span class="com"># أضف نص الإعلان وسطرًا فارغًا</span><span class="pln">
outp</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"Menu for %s\n\n"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> theDate</span><span class="pun">)</span><span class="pln"> 

</span><span class="com"># إلى ملف جديد menu.txt انسخ كل سطر من </span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
    outp</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Menu created for %s..."</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> theDate </span><span class="pun">)</span><span class="pln">

</span><span class="com"># أغلق الملفات</span><span class="pln">
inp</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
outp</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	لاحظ أننا نستخدم وحدة <code>time</code> للحصول على تاريخ اليوم <code>time.time()‎</code>، وتحويله إلى صف tuple من القيم <code>‎(time.localtime())‎</code> التي تُستخدم لاحقًا بواسطة <code>time.strftime()‎</code> -انظر <a href="https://www.google.com/url?q=https://wiki.hsoub.com/Python/datetime%23.D8.A7.D9.84.D8.AA.D8.A7.D8.A8.D8.B9.D8.A7.D9.86_strftime.28.29_.D9.88_strptime.28.29&amp;sa=D&amp;source=editors&amp;ust=1628037107629000&amp;usg=AOvVaw2Cm6fBrlAVlL939kENSHcS" rel="external nofollow">توثيق الوقت والتاريخ في بايثون من موسوعة حسوب</a>- لإنتاج سلسلة نصية تبدو بالشكل التالي عندما ندخلها في رسالة عنوان باستخدام تنسيق السلاسل النصية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8059_33" style=""><span class="typ">Menu</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="typ">Sunday</span><span class="pln"> </span><span class="typ">September</span><span class="pln"> </span><span class="lit">19</span><span class="pln">

</span><span class="typ">Spam</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">Eggs</span><span class="pln">
</span><span class="typ">Spam</span><span class="pln"> </span><span class="pun">&amp;...</span></pre>

<p>
	لم يُطبع إلا سطر واحد فارغ رغم إضافتنا لمحرفين <code>‎\n</code> في نهاية السلسلة النصية، وذلك لأن أحدهما كان السطر الجديد عند نهاية العنوان نفسه، وهذا يظهر جانبًا مزعجًا في إدارة عملية إنشاء محارف الأسطر الجديدة وحذفها.
</p>

<h3>
	إلحاق البيانات
</h3>

<p>
	ثمة أمر آخر في معالجة الملفات، إذ قد نرغب في إلحاق بيانات بنهاية ملف موجود، ويمكن فعل هذا بفتح الملف للإدخال، وقراءة البيانات إلى قائمة، ثم إلحاق البيانات إليها، ثم كتابة القائمة كلها إلى إصدار جديد من الملف القديم، ولن يُحدث هذا مشكلةً إذا كان الملف قصيرًا؛ أما إذا كان كبيرًا -أكبر من 100 ميجا بايت مثلًا-، فستنفد الذاكرة التي يجب أن تحتفظ بالقائمة، وسيستغرق الأمر زمنًا طويلًا. لحسن الحظ لدينا وضع يسمى <code>"a"</code> والذي نستطيع تمريره إلى <code>open()‎</code>، فيسمح لنا بإلحاق البيانات مباشرةً إلى ملف موجود بمجرد كتابتها، وإذا لم يكن الملف موجودًا، فسيُفتح ملف جديد كما لو كنا قد حددنا الوضع <code>"w"</code>.
</p>

<p>
	لنفترض أن لدينا ملف سجل نستخدمه لالتقاط رسائل الخطأ، ولا نريد أن نحذف رسائل الخطأ الموجودة كلما جاءت رسالة جديدة، لذا يمكن إلحاق الخطأ في الملف كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_35" style=""><span class="kwd">def</span><span class="pln"> logError</span><span class="pun">(</span><span class="pln">msg</span><span class="pun">):</span><span class="pln">
   err </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"Errors.log"</span><span class="pun">,</span><span class="str">"a"</span><span class="pun">)</span><span class="pln">
   err</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">msg</span><span class="pun">)</span><span class="pln">
   err</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	قد نرغب -من الناحية العملية- بتقييد حجم الملف بشكل ما، والتقنية الشائعة لذلك هي إنشاء اسم ملف مبني على التاريخ، فإذا تغير التاريخ فسننشئ ملفًا جديدًا، مما يسهل على مشرفي النظام أن يجدوا أخطاء يوم بعينه، وأرشفة ملفات الأخطاء القديمة إذا لم نعد بحاجة إليها. تذكر أن وحدة <code>time</code> من مثال القائمة أعلاه يمكن استخدامها لإيجاد التاريخ الحالي.
</p>

<h3>
	بنية With في بايثون
</h3>

<p>
	قدم الإصدار الثالث من بايثون طريقةً جديدةً سهلةً للعمل مع الملفات، لا سيما عند التكرار على محتوياتها، وتستخدم هذه الطريقة بنيةً جديدةً اسمها <code>with</code>، بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_37" style=""><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'Errors.log'</span><span class="pun">,</span><span class="str">"r"</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> line </span><span class="pun">)</span><span class="pln">   </span></pre>

<p>
	لاحظ أننا لم نستخدم <code>close()‎</code>، إذ تضمن <code>with</code> إغلاق الملف في نهايتها، وهكذا يكون التعامل مع الملفات أكثر موثوقيةً، وهذه الطريقة هي التي يُنصح بها لفتح الملفات في الإصدار الثالث من بايثون، وقد اخترنا استخدام الأسلوب القديم <code>open/close</code> لأن أغلب لغات البرمجة تستخدمه، وهو أكثر وضوحًا وصراحةً من أسلوب <code>with</code>، لكن إذا أردت أن تستخدم بايثون خاصةً فمن الأفضل استخدام <code>with</code>.
</p>

<h2>
	بعض العثرات في أنظمة التشغيل
</h2>

<p>
	تتعامل أنظمة التشغيل مع الملفات بطرق مختلفة، مما قد يسبب مشاكل في برامجنا إذا أردناها أن تعمل على عدة أنظمة تشغيل، ونخص بالذكر منها مشكلتين اثنتين:
</p>

<h3>
	الأسطر الجديدة
</h3>

<p>
	تشكل الملفات النصية والأسطر الجديدة منطقةً غامضةً تختلف فيها أنظمة التشغيل من حيث كيفية تنفيذها، وتمتد جذور تلك الاختلافات إلى الأيام الأولى لتواصل البيانات والتحكم في الآلات الكاتبة البرقية teleprinters الميكانيكية، وملخص الأمر أن لدينا ثلاثة طرق مختلفة للإشارة إلى السطر الجديد:
</p>

<ol>
	<li>
		<code>‎\r</code>: محرف إعادة العربة (CR: Carriage Return).
	</li>
	<li>
		<code>‎\n</code>: محرف تغذية السطر (LF: Line Feed).
	</li>
	<li>
		<code>‎\r\n</code> زوج CR/LF.
	</li>
</ol>

<p>
	تُستخدم التقنيات الثلاث في أنظمة تشغيل مختلفة، فنظام MS DOS مثلًا -وويندوز بالتبعية- يستخدم التقنية الثالثة، أما يونكس -بما في ذلك لينكس- فيستخدم الطريقة الثانية، بينما تستخدم أبل الطريقة الأولى في نظام ماك أو إس القديم، وتستخدم الطريقة الثانية في نظام MacOS X وما بعده بما أن هذا النظام ما هو إلا يونكس. وعلى المبرمج أن يجري اختبارات كثيرةً ويتخذ إجراءات مختلفةً لكل نظام تشغيل، ليتعامل مع هذا التعدد لنهايات الأسطر. لكن اللغات الحديثة -بما في ذلك بايثون- توفر تسهيلات للتعامل مع هذه الفوضى بالنيابة عنا، وتحل بايثون هذه المشكلة في وحدة <code>os</code> التي تعرّف متغيرًا اسمه <code>linesep</code> يُضبط على محرف السطر الجديد الذي يستخدمه نظام التشغيل، مما يسهل عملية إضافة الأسطر الجديدة، كما ينتبه التابع <code>rstrip()‎</code> إلى نظام التشغيل عندما يحذف هذه المحارف، وهكذا نستخدم هذا التابع لنريح أنفسنا من عناء التفكير في الأسطر الجديدة التي تُحذف من الأسطر المقروءة من الملف، كما نضيف <code>os.linesep</code> إلى السلاسل النصية التي تُكتب إلى الملف.
</p>

<p>
	فإذا أنشأنا ملفًا على نظام تشغيل ثم عالجناه على نظام تشغيل آخر غير متوافق مع الأول، فلا نستطيع إلا أن نوازن نهاية السطر مع <code>os.linesep</code> لنعرف الفرق.
</p>

<h3>
	تحديد المسارات
</h3>

<p>
	هذه المشكلة تخص مستخدمي ويندوز أكثر من غيرهم، فقد ذكرنا سابقًا أن كل نظام تشغيل يحدد مسارات الملفات باستخدام محارف مختلفة لفصل الأقراص والمجلدات والملفات عن بعضها، وأن الحل العام لهذا هو استخدام وحدة <code>os</code> التي توفر متغير <code>os.sep</code> لتعريف محرف فصل المسار الخاص بالمنصة الحالية، ولن نحتاج إلى ذلك كثيرًا في المواقف العملية، لأن المسار سيختلف لكل حاسوب على أي حال، لذا سنُدخِل المسار الكامل مباشرةً في سلسلة نصية -ربما سلسلة لكل نظام تشغيل نعمل عليه-، لكن لهذا عقبة كبيرة بالنسبة لمستخدمي ويندوز، فقد رأينا في القسم السابق أن بايثون تتعامل مع السلسلة <code>‎'\n'‎</code> على أنها محرف السطر الجديد، أي أنها تأخذ محرفين وتعاملهما مثل محرف واحد، ولدينا كثير من مثل هذه التسلسلات الخاصة من المحارف التي تبدأ بشرطة مائلة خلفية <code>\</code>، ومنها:
</p>

<ul>
	<li>
		<code>‎\n</code>: سطر جديد.
	</li>
	<li>
		<code>‎\r</code>: إعادة العربة.
	</li>
	<li>
		<code>‎\t</code>: جدول أفقي.
	</li>
	<li>
		<code>‎\v</code>: جدول رأسي، يعني أحيانًا صفحةُ جديدة.
	</li>
	<li>
		<code>‎\b</code>: زر backspace.
	</li>
	<li>
		<code>‎\0nn</code>: أي شيفرة ثمانية عشوائية، مثل <code>‎\033</code> التي تشير إلى زر الهروب Esc.
	</li>
</ul>

<p>
	فإذا كان لدينا ملف اسمه <code>test.dat</code> ونريد فتحه في بايثون من خلال تحديد مسار ويندوز كامل، فستكون الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_39" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> f </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'C:\test.dat'</span><span class="pun">)</span></pre>

<p>
	لكن ما يحدث هو أن بايثون سترى الزوج <code>‎\t</code> على أنه محرف جدول وستخبرنا أنها لا تستطيع إيجاد ملف باسم <code><span class="ipsEmoji">?</span> est.dat</code>، ولحل هذه المشكلة لدينا ثلاث طرق، هي:
</p>

<ol>
	<li>
		نضع <code>r</code> أمام السلسلة النصية، لنخبر بايثون أن تتجاهل أي شرطة مائلة خلفية، وتعاملها على أنها سلسلة نصية خام.
	</li>
	<li>
		نستخدم شرطات مائلة أمامية <code>/</code> بدلًا من الخلفية، وستتوافق بايثون مع ويندوز ليخرجا لنا المسار، وهذا الحل يجعل الشيفرة قابلةً للعمل على أنظمة التشغيل الأخرى.
	</li>
	<li>
		استخدام شرطتين خلفيتين <code>\\</code> بما أن بايثون ترى محرفي الشرطتين المزدوجتين على أنهما شرطة خلفية واحدة.
	</li>
</ol>

<p>
	وعلى ذلك سيفتح أي سطر مما يلي ملف البيانات الخاص بنا بشكل سليم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_41" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> f </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">r</span><span class="str">'C:\test.dat'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> f </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'C:/test.dat'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> f </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'C:\\test.dat'</span><span class="pun">)</span></pre>

<p>
	لاحظ أن هذه المشكلة مقصورة على السلاسل المجردة التي نكتبها في شيفرة برنامجنا، أما إذا قرئت سلاسل المسار من ملف أو من المستخدم، فستفسر بايثون محارف <code>\</code> وتستخدمها كما هي دون مشاكل.
</p>

<h2>
	دليل جهات الاتصال
</h2>

<p>
	لقد كتبنا دليل جهات اتصال في مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r1287/" rel="">البيانات وأنواعها</a>، ثم زدنا عليه وطورناه في فصل <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-r1311/" rel="">قراءة البيانات من المستخدم</a>، وسنجعله في هذا المقال تطبيقًا مفيدًا بحفظه في ملف، إلى جانب قراءة ذلك الملف عند بدء التشغيل، وبما أننا سنفعل ذلك من خلال كتابة بعض الدوال، فسنستخدم بعضًا مما شرحناه في المقالات السابقة من هذه السلسلة. سيحتاج التصميم الأولي دالةً لقراءة الملف عند بدء التشغيل، ودالةً أخرى عند نهاية البرنامج، كما سننشئ دالةً تزود المستخدم بقائمة من الخيارات، ودالةً مستقلة لكل خيار في تلك القائمة، ستسمح القائمة للمستخدم بما يلي:
</p>

<ul>
	<li>
		إضافة مدخل في دليل جهات الاتصال.
	</li>
	<li>
		حذف مدخل منه.
	</li>
	<li>
		البحث عن مدخل موجود من قبل وعرضه.
	</li>
	<li>
		الخروج من البرنامج.
	</li>
</ul>

<h3>
	تحميل دليل جهات الاتصال
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_43" style=""><span class="kwd">import</span><span class="pln"> os
filename </span><span class="pun">=</span><span class="pln"> </span><span class="str">"addbook.dat"</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> readBook</span><span class="pun">(</span><span class="pln">book</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">exists</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">,</span><span class="str">'r'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> store</span><span class="pun">:</span><span class="pln">
          </span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> store</span><span class="pun">:</span><span class="pln">
             name </span><span class="pun">=</span><span class="pln"> line</span><span class="pun">.</span><span class="pln">rstrip</span><span class="pun">()</span><span class="pln">
             entry </span><span class="pun">=</span><span class="pln"> next</span><span class="pun">(</span><span class="pln">store</span><span class="pun">).</span><span class="pln">rstrip</span><span class="pun">()</span><span class="pln">
             book</span><span class="pun">[</span><span class="pln">name</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> entry</span></pre>

<p>
	نلاحظ هنا أننا نستورد الوحدة <code>os</code> التي نستخدمها للتحقق من أن مسار الملف موجود قبل فتحه، ونعرِّف اسم الملف مثل متغير مستوى وحدة module level variable لنستخدمه في تحميل البيانات وحفظها.
</p>

<p>
	سنستخدم أيضًا <code>rstrip()‎</code> لحذف محرف السطر الجديد من نهاية السطر، ودالة <code>next()‎</code> التي تجلب السطر التالي من الملف إلى داخل الحلقة، وهذا يعني أننا نقرأ سطرين في نفس الوقت أثناء عمل الحلقة، ودالة <code>next</code> هي جزء من خاصية في بايثون تسمى بالمكرر، وهي خاصية لن نشرحها في هذه السلسلة بما أنها خاصة ببايثون كلغة برمجة، لكننا سنقول أن كل تجميعات بايثون وملفاتها وبعض الأمور الأخرى يُنظر إليها على أنها مكرَّرات أو أنواع قابلة للتكرار، ويمكن معرفة المزيد عن هذه الخاصية في <a href="https://docs.python.org/3/library/stdtypes.html#iterator-types" rel="external nofollow">توثيق بايثون</a>.
</p>

<h3>
	حفظ دليل جهات الاتصال
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_45" style=""><span class="kwd">def</span><span class="pln"> saveBook</span><span class="pun">(</span><span class="pln">book</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">,</span><span class="pln"> </span><span class="str">'w'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> store</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> name</span><span class="pun">,</span><span class="pln">entry </span><span class="kwd">in</span><span class="pln"> book</span><span class="pun">.</span><span class="pln">items</span><span class="pun">():</span><span class="pln">
         store</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">name </span><span class="pun">+</span><span class="pln"> </span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">
         store</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">entry </span><span class="pun">+</span><span class="pln"> </span><span class="str">'\n'</span><span class="pun">)</span></pre>

<p>
	لاحظ أننا نحتاج إلى إضافة محرف السطر الجديد <code>‎'\n'‎</code> عندما نكتب البيانات، وأننا نكتب سطرين لكل إدخال، فهذا يعكس حقيقة أننا عالجنا سطرين عند قراءة الملف.
</p>

<h3>
	الحصول على مدخلات المستخدم
</h3>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8059_47" style=""><span class="pln">def getChoice</span><span class="pun">(</span><span class="pln">menu</span><span class="pun">,</span><span class="pln"> length</span><span class="pun">):</span><span class="pln">
    print</span><span class="pun">(</span><span class="pln"> menu </span><span class="pun">)</span><span class="pln">
    prompt </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Select a choice(1-%d): "</span><span class="pln">  </span><span class="pun">%</span><span class="pln"> length
    choice </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">(</span><span class="pln"> input</span><span class="pun">(</span><span class="pln">prompt</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> choice</span></pre>

<p>
	نلاحظ أننا نستقبل معامِل طول يخبرنا عدد المداخل الموجودة، مما يسمح لنا بإنشاء محث يحدد نطاق الأعداد المناسب.
</p>

<h3>
	إضافة مدخل
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_49" style=""><span class="kwd">def</span><span class="pln"> addEntry</span><span class="pun">(</span><span class="pln">book</span><span class="pun">):</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln">  input</span><span class="pun">(</span><span class="str">"Enter a name: "</span><span class="pun">)</span><span class="pln">
    entry </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Enter street, town and phone number: "</span><span class="pun">)</span><span class="pln">
    book</span><span class="pun">[</span><span class="pln">name</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> entry</span></pre>

<h3>
	حذف مدخل
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_51" style=""><span class="kwd">def</span><span class="pln"> removeEntry</span><span class="pun">(</span><span class="pln">book</span><span class="pun">):</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Enter a name: "</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">del</span><span class="pun">(</span><span class="pln">book</span><span class="pun">[</span><span class="pln">name</span><span class="pun">])</span></pre>

<h3>
	العثور على مدخل
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_53" style=""><span class="kwd">def</span><span class="pln"> findEntry</span><span class="pun">(</span><span class="pln">book</span><span class="pun">):</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Enter a name: "</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> name </span><span class="kwd">in</span><span class="pln"> book</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> book</span><span class="pun">[</span><span class="pln">name</span><span class="pun">]</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Sorry, no entry for: "</span><span class="pun">,</span><span class="pln"> name </span><span class="pun">)</span></pre>

<h3>
	الخروج من البرنامج
</h3>

<p>
	لن نكتب دالةً مستقلةً للخروج من البرنامج، بل سنجعل خيار الإنهاء اختبارًا في حلقة <code>while</code> الخاصة بالقائمة، لذا سيكون البرنامج الرئيسي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_55" style=""><span class="kwd">def</span><span class="pln"> main</span><span class="pun">():</span><span class="pln">
    theMenu </span><span class="pun">=</span><span class="pln"> </span><span class="str">'''
    1) إضافة مدخل
    2) حذف مدخل
    3) العثور على مدخل
    4) الخروج والحفظ
    '''</span><span class="pln">
    theBook </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    readBook</span><span class="pun">(</span><span class="pln">theBook</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
        choice </span><span class="pun">=</span><span class="pln"> getChoice</span><span class="pun">(</span><span class="pln">theMenu</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="lit">4</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">break</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
            addEntry</span><span class="pun">(</span><span class="pln">theBook</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">elif</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
            removeEntry</span><span class="pun">(</span><span class="pln">theBook</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">elif</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
            findEntry</span><span class="pun">(</span><span class="pln">theBook</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Invalid choice, try again"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    saveBook</span><span class="pun">(</span><span class="pln">theBook</span><span class="pun">)</span></pre>

<p>
	لم يبق الآن إلا استدعاء <code>main()‎</code> عند تشغيل البرنامج، وهنا سنستخدم القليل من سحر بايثون:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_57" style=""><span class="kwd">if</span><span class="pln"> __name__ </span><span class="pun">==</span><span class="pln"> </span><span class="str">"__main__"</span><span class="pun">:</span><span class="pln">
    main</span><span class="pun">()</span></pre>

<p>
	تسمح لنا هذه الشيفرة الغامضة باستخدام أي ملف بايثون مثل وحدة، وذلك باستيراده <code>import</code> أو مثل برنامج عبر تشغيله، والفرق هنا هو أن بايثون تضبط المتغير الداخلي <code>__name__</code> عند استيراد البرنامج على اسم الوحدة، لكن إذا شغّلنا الملف مثل برنامج، فستُضبط قيمة <code>__name__</code> على <code>"__main__"</code>، هذا يعني أن دالة <code>main()‎</code> لا تُستدعى إلا إذا شغلنا الملف مثل برنامج وليس عند استيراده.
</p>

<p>
	إذا كتبنا هذه الشيفرة في ملف نصي وحفظناه باسم addressbook.py، فيجب أن يكون قابلًا للتشغيل في أي محث لنظام تشغيل بكتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_59" style=""><span class="pln">C</span><span class="pun">:</span><span class="pln">\PROJECTS</span><span class="pun">&gt;</span><span class="pln"> python addressbook</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	أو بالنقر المزدوج عليه مثل أي ملف في مدير الملفات في ويندوز، ليشغَّل في نافذة CMD خاصة به، تُغلَق عند تحديد خيار الإغلاق، أو باستخدام ما يلي في لينكس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_61" style=""><span class="pln">$ python addressbook</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	يُعَد هذا البرنامج المكون من ستين سطرًا نموذجًا لما يجب أن تكون قادرًا على كتابته الآن بنفسك، وهو أداة مفيدة على حالته تلك، رغم أننا سنضيف إليه بعض الأشياء التي ستحسّنه في المقال التالي.
</p>

<h2>
	جافاسكربت وVBScript
</h2>

<p>
	ليس لدى جافاسكربت وVBScript القدرة على معالجة الملفات، وذلك لمنع أي أحد من قراءة ملفاتك عند تحميلك لصفحة ويب مثلًا، لكن هذا يقيد فائدة اللغة نفسها ونطاق استخدامها من ناحية أخرى. توجد طريقة لجعلهما تعالجان الملفات باستخدام WSH كما فعلنا في الوحدات القابلة لإعادة الاستخدام من قبل، إذ توفر WSH كائن <code>FileSystem</code> يسمح لأي لغة WSH بقراءة الملفات. سننظر في مثال جافاسكربت بالتفصيل، ثم نعرض شيفرةً مشابهةً من لغة VBScript من أجل الموازنة بينهما، وكما رأينا من قبل فإن العناصر الأساسية ما هي إلا استدعاءات لكائنات WScript.
</p>

<p>
	لربما يجب أن نشرح نموذج الكائن <code>FileSystem</code> قبل أن ننظر في الشيفرة، فنموذج الكائن هو مجموعة من الكائنات المرتبطة ببعضها، والتي يمكن للمبرمج استخدامها. يتكون نموذج كائن <code>FileSystem</code> من كائن <code>FSO</code> وعدد من كائنات <code>File</code>، بما في ذلك كائن <code>TextFile</code> الذي سنستخدمه، كما توجد بعض الكائنات المساعدة مثل <code>TextStream</code>.
</p>

<p>
	ما سنفعله هنا هو إنشاء نسخة من كائن <code>FSO</code> ثم نستخدمها لإنشاء كائنات <code>TextFile</code>، ثم ننشئ كائنات <code>TextStream</code> كي نستطيع قراءة النصوص فيها وكتابتها أيضًا، كذلك فكائنات <code>TextStream</code> نفسها هي التي نقرؤها من الملفات أو نكتبها.
</p>

<p>
	اكتب الشيفرة أدناه في ملف باسم <code>testFiles.js</code> وشغله باستخدام <code>cscript</code> كما ذكرنا في قسم WSH من المقال السابق.
</p>

<h3>
	فتح ملف
</h3>

<p>
	يجب أن ننشئ كائن FSO أولًا، ثم ننشئ كائن TextFile منه كي نتمكن من فتح ملف في WSH:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_63" style=""><span class="pln">var fileName</span><span class="pun">,</span><span class="pln"> fso</span><span class="pun">,</span><span class="pln"> txtFile</span><span class="pun">,</span><span class="pln"> outFile</span><span class="pun">,</span><span class="pln"> line</span><span class="pun">;</span><span class="pln">

</span><span class="pun">//</span><span class="pln"> </span><span class="pun">احصل</span><span class="pln"> </span><span class="pun">على</span><span class="pln"> </span><span class="pun">اسم</span><span class="pln"> </span><span class="pun">الملف</span><span class="pln">
fso </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">ActiveXObject</span><span class="pun">(</span><span class="str">"Scripting.FileSystemObject"</span><span class="pun">);</span><span class="pln">
</span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">Echo</span><span class="pun">(</span><span class="str">"What file name? "</span><span class="pun">);</span><span class="pln">
fileName </span><span class="pun">=</span><span class="pln"> </span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">StdIn</span><span class="pun">.</span><span class="typ">Readline</span><span class="pun">();</span><span class="pln">

</span><span class="pun">//</span><span class="pln"> </span><span class="pun">للقراءة</span><span class="pln"> inFile </span><span class="pun">افتح</span><span class="pln"> 
</span><span class="pun">//</span><span class="pln"> </span><span class="pun">للكتابة</span><span class="pln"> outFile </span><span class="pun">افتح</span><span class="pln">
inFile </span><span class="pun">=</span><span class="pln"> fso</span><span class="pun">.</span><span class="typ">OpenTextFile</span><span class="pun">(</span><span class="pln">fileName</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span><span class="pun">//</span><span class="pln"> mode </span><span class="lit">1</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Read</span><span class="pln">
fileName </span><span class="pun">=</span><span class="pln"> fileName </span><span class="pun">+</span><span class="pln"> </span><span class="str">".BAK"</span><span class="pln">
outFile </span><span class="pun">=</span><span class="pln"> fso</span><span class="pun">.</span><span class="typ">CreateTextFile</span><span class="pun">(</span><span class="pln">fileName</span><span class="pun">);</span></pre>

<h3>
	إغلاق الملفات
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_65" style=""><span class="pln">inFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln">
outFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span></pre>

<h3>
	شرح المثال في VBScript
</h3>

<p>
	احفظ ما يلي في <code>testFiles.ws</code> وشغله باستخدام:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_67" style=""><span class="pln">cscript testfiles</span><span class="pun">.</span><span class="pln">ws</span></pre>

<p>
	أو ضع الجزء الذي بين وسوم <code>script</code> في ملف باسم <code>testFile.vbs</code> وشغله، حيث تسمح صيغة <code>ws.</code> بدمج شيفرة جافاسكربت وVBScript في نفس الملف باستخدام عدة وسوم <code>script</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_69" style=""><span class="pun">&lt;?</span><span class="pln">xml version</span><span class="pun">=</span><span class="str">"1.0"</span><span class="pun">?&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">job</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="typ">Dim</span><span class="pln"> fso</span><span class="pun">,</span><span class="pln"> inFile</span><span class="pun">,</span><span class="pln"> outFile</span><span class="pun">,</span><span class="pln"> inFileName</span><span class="pun">,</span><span class="pln"> outFileName
      </span><span class="typ">Set</span><span class="pln"> fso </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CreateObject</span><span class="pun">(</span><span class="str">"Scripting.FileSystemObject"</span><span class="pun">)</span><span class="pln">

      </span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">Echo</span><span class="pln"> </span><span class="str">"Type a filename to backup"</span><span class="pln">
      inFileName </span><span class="pun">=</span><span class="pln"> </span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">StdIn</span><span class="pun">.</span><span class="typ">ReadLine</span><span class="pln">
      outFileName </span><span class="pun">=</span><span class="pln"> inFileName </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">".BAK"</span><span class="pln">

      </span><span class="str">' open the files
      Set inFile = fso.OpenTextFile(inFileName, 1)
      Set outFile = fso.CreateTextFile(outFileName)

      '</span><span class="pln"> read the file </span><span class="kwd">and</span><span class="pln"> write to the backup copy
      </span><span class="typ">Do</span><span class="pln"> </span><span class="typ">While</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> inFile</span><span class="pun">.</span><span class="typ">AtEndOfStream</span><span class="pln">
         line </span><span class="pun">=</span><span class="pln"> inFile</span><span class="pun">.</span><span class="typ">ReadLine</span><span class="pln">
         outFile</span><span class="pun">.</span><span class="typ">WriteLine</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">
      </span><span class="typ">Loop</span><span class="pln">

      </span><span class="str">' close both files
      inFile.Close
      outFile.Close

      WScript.Echo inFileName &amp; " backed up to " &amp; outFileName
  &lt;/script&gt;
&lt;/job&gt;</span></pre>

<h2>
	التعامل مع الملفات غير النصية
</h2>

<p>
	يُعَد التعامل مع الملفات النصية أكثر ما يفعله المبرمج، غير أننا قد نحتاج إلى معالجة بيانات ثنائية أحيانًا، وسنشرح هذا الجزء في بايثون فقط لندرة حدوثه في جافاسكربت وVBScript.
</p>

<h3>
	الترميز الثنائي للبيانات
</h3>

<p>
	يجب أن ننظر في كيفية تمثيل البيانات وتخزينها على الحاسوب قبل أن نتحدث عن كيفية الوصول إليها داخل ملف ثنائي، حيث تُخزَّن البيانات في هيئة تسلسلات من الأرقام الثنائية أو البتات، والتي تُجمع في مجموعات من 8 بتات تسمى البايت، أو 16بتًا تسمى الكلمة، في حين أن المجموعة التي تتكون من 4 بتات تسمى أحيانًا بالحلمة. قد يكون للبايت الواحد نمط من 256 نمط للبتات، وتعطى هذه الأنماط قيمًا من 0 إلى 255، كما يجب أن تُحوَّل المعلومات التي نعالجها في برامجنا من سلاسل نصية وأعداد وغيرها إلى سلاسل من تلك البايتات، لذا يخصَّص نمط بايت معين لكل محرف نستخدمه في السلاسل النصية، ورغم وجود عدة نظم ترميز للبيانات، إلا أن أشهرها هو ترميز آسكي ASCII، لكن هذا الترميز لا يحوي إلا 128 محرفًا فقط، وهذا بالكاد يكفي للغة الإنجليزية فقط، لذا طوِّر معيار ترميز جديد سمي <a href="http://www.unicode.org/" rel="external nofollow">بالترميز الموحد أو اليونيكود Unicode</a>، والذي يَستخدم كلمات البيانات لتمثيل المحارف بدلًا من البايتات، ويشتمل على أكثر من مليون محرف، ثم يمكن بعد ذلك ترميز تلك المحارف في مجرى بيانات مضغوط أكثر.
</p>

<p>
	إن أكثر ترميزات اليونيكود شيوعًا هو UTF-8، ويتوافق توافقًا كبيرًا مع آسكي، بحيث أن أي ملف متوافق مع آسكي يتوافق أيضًا مع UTF-8، رغم أن العكس قد لا يكون صحيحًا. يوفر اليونيكود عددًا من الترميزات التي يعرِّف كل منها البايت الذي يمثل قيمةً عدديةً من اليونيكود، أو "نقطةً رمزيةً" وفق اصطلاح اليونيكود. وهذا النظام المعقد هو الثمن الذي كان يجب دفعه من أجل بناء شبكة حواسيب عالمية تعمل بمختلف اللغات التي يستخدمها البشر، لكن المتحدثين بالإنجليزية لم يكن عليهم القلق بشأن اليونيكود إلا عند قراءة البيانات من ملف ثنائي، على الرغم من أن الإصدار الثالث لبايثون يَعُد السلاسل النصية سلاسل يونيكود، لذا يجب أن نعلم الترميز المستخدم من أجل تفسير البيانات الثنائية تفسيرًا صحيحًا.
</p>

<p>
	تدعم بايثون نصوص اليونيكود دعمًا كاملًا، فتنظر إلى سلسلة المحارف المرمَّزة على أنها سلسلة بايتات لها النوع <code>bytes</code>، بينما يكون للسلسلة غير المرمزة النوع <code>str</code>، ويكون الترميز الافتراضي هو UTF-8، ولهذا بعض شواذ، نظريًا على الأقل، ولن نشرح استخدام المحارف التي ليست UTF-8 في هذه السلسلة، لكن يمكن مراجعة <a href="http://docs.python.org/3.0/howto/unicode.html#unicode-howto" rel="external nofollow">مستند How-To</a> في موقع بايثون.
</p>

<p>
	ما نريد الإشارة إليه من كل هذا هو أن المجرى الثنائي لنص اليونيكود المرمَّز يعامَل مثل سلسلة من البايتات، وتوفر بايثون دوالًا لتحويل (أو فك ترميز) قيم <code>bytes</code> لتكون قيم <code>str</code>، بالمثل يجب أن تحوَّل الأعداد إلى ترميزات ثنائية أيضًا، فعلى الرغم من أن قيم البايتات تكفي في حالة الأعداد الصغيرة، إلا أن الأعداد الأكبر من 255 أو الأعداد السالبة أو الكسور تحتاج إلى عمل آخر، وقد ظهرت عدة ترميزات معيارية للبيانات العددية، والتي تستخدمها أغلب لغات البرمجة ونظم التشغيل، فمثلًا: يعرِّف المعهد الأمريكي للهندسة الكهربية والإلكترونية IEEE عدة ترميزات للأعداد ذات الفاصلة العائمة floating point numbers، وتهدف هذه الجهود إلى حل مشكلة التفسير الصحيح للبيانات الثنائية، فمن المهم للغاية أن نحولها إلى النوع الصحيح عند قراءتها، بما أنه يتعين علينا تفسير أنماط البتات الخام إلى النوع الصحيح المناسب للبرنامج الذي نعمل عليه، وعلى ذلك من الممكن أن نفسر مجرى بيانات كُتب أصلأ على أنه سلسلة نصية في صورة مجموعة من الأعداد ذات الفاصلة العائمة، ورغم أن المعنى الأصلي له سيُفقد، إلا أن أنماط البتات يمكن أن تمثل أي واحد منهما.
</p>

<h3>
	فتح الملفات الثنائية وإغلاقها
</h3>

<p>
	يتمثل الفرق الجوهري بين الملفات النصية والثنائية في أن الملفات النصية تتكون من ثمانيات octets -جمع ثُماني، وهو الشيء المكون من ثمانية أجزاء-، لكن الاسم الأشهر لها هو بايتات، ويمثل كل بايت حرفًا. تُحدَّد نهاية الملف بنمط بايت خاص يُعرف باسم EOF، وهو اختصار لعبارة نهاية الملف End Of File؛ بينما يحتوي الملف الثنائي على بيانات ثنائية عشوائية، ومن ثم لا يمكن استخدام قيمة بعينها لتحديد نهاية الملف، لذا نحتاج إلى وضع عمليات مختلف لقراءة تلك الملفات، فعند فتح ملف ثنائي في بايثون أو في أي لغة أخرى، فيجب أن نحدد أنه يُفتَح في الوضع الثنائي، أو المخاطرة بقطع البيانات التي نقرؤها عند أول محرف <code>eof</code> تجده بايثون في تلك البيانات. يمكن تنفيذ ذلك في بايثون بإضافة <code>b</code> إلى معامِل الوضع mode parameter كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_71" style=""><span class="pln">binfile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"aBinaryFile.bin"</span><span class="pun">,</span><span class="str">"rb"</span><span class="pun">)</span></pre>

<p>
	لا يختلف هذا عن فتح ملف نصي إلا في قيمة الوضع <code>"rb"</code>، ونستطيع استخدام أي وضع آخر، لكن مع إضافة حرف <code>b</code>، فنستخدم <code>"wb"</code> للكتابة، و<code>"ab"</code> للإلحاق، كما لا يختلف إغلاق الملف الثنائي عن الملف النصي، فنستدعي التابع <code>close()‎</code> لكائن الملف المفتوح:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_75" style=""><span class="pln">binfile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	وبما أننا فتحنا الملف في الوضع الثنائي، فلا داعي لإعطاء بايثون أي معلومات إضافية، فهي تعرف كيف تغلق الملف.
</p>

<h3>
	الوحدة struct
</h3>

<p>
	توفّر بايثون وحدةً اسمها <code>struct</code> لترميز البيانات الثنائية وفك ترميزها، وهي تتصرف مثل سلاسل التنسيق التي استخدمناها لطباعة البيانات المختلطة، إذ توفر سلسلةً تمثل البيانات التي نقرؤها وتطبقها على مجرى البايتات الذي نحاول تفسيره، ومن الممكن استخدام هذه الوحدة لتحويل مجموعة من البيانات إلى مجرى البايت للكتابة، إما إلى ملف ثنائي أو حتى خط اتصالات communications line.
</p>

<p>
	هناك الكثير من رموز تنسيق التحويل المختلفة، لكننا لن نستخدم إلا رموز الأعداد الصحيحة integers والسلاسل النصية strings هنا؛ أما البقية فيمكن قراءة المزيد عنها في <a href="https://docs.python.org/3.0/library/struct.html" rel="external nofollow">توثيق بايثون الرسمي</a>. إن رمز تنسيق التحويل للأعداد الصحيحة هو <code>i</code>، ورمز السلاسل النصية <code>s</code>، وتتكون سلاسل تنسيق الوحدة <code>struct</code> من سلاسل من الرموز فيها أرقام مسبقة التعليق pre-pended، حيث توضح عدد العناصر التي نحتاج إليها، مع استثناء لرمز <code>s</code> الذي يشير العدد مسبق التعليق فيه إلى طول السلسلة النصية، حيث تعني <code>4s</code> مثلًا سلسلةً من أربعة محارف (أربعة محارف وليس أربعة سلاسل نصية).
</p>

<p>
	لنفترض أننا نريد كتابة تفاصيل العنوان، في برنامج دليل جهات الاتصال الذي شرحناه أعلاه، في صورة بيانات ثنائية، حيث يكون رقم الشارع فيها عددًا صحيحًا والبقية سلسلةً نصيةً. رغم أن هذا الاختيار سيء لأن أرقام الشوارع تتضمن حروفًا أحيانًا، إلا أن سلسلة التنسيق ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8059_77" style=""><span class="str">'i34s'</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">نفترض</span><span class="pln"> </span><span class="pun">وجود</span><span class="pln"> </span><span class="lit">34</span><span class="pln"> </span><span class="pun">محرف</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">العنوان</span></pre>

<p>
	ولكي نعالج مسألة الأطوال المختلفة للعناوين، فسنكتب دالةً تنشئ السلسلة الثنائية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_79" style=""><span class="kwd">def</span><span class="pln"> formatAddress</span><span class="pun">(</span><span class="pln">address</span><span class="pun">):</span><span class="pln"> 
    fields </span><span class="pun">=</span><span class="pln"> address</span><span class="pun">.</span><span class="pln">split</span><span class="pun">()</span><span class="pln">
    number </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">fields</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])</span><span class="pln">
    rest </span><span class="pun">=</span><span class="pln"> bytes</span><span class="pun">(</span><span class="str">' '</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">fields</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:],</span><span class="str">'utf8'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># أنشئ سلسلة بايت</span><span class="pln">
    format </span><span class="pun">=</span><span class="pln"> </span><span class="str">"i%ds"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">rest</span><span class="pun">)</span><span class="pln"> </span><span class="com"># أنشئ سلسلة التنسيق</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> struct</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">format</span><span class="pun">,</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> rest</span><span class="pun">)</span></pre>

<p>
	لقد استخدمنا تابع السلسلة <code>split()‎</code> أعلاه لتقسيم سلسلة العنوان النصية إلى أجزائها، وقسمناها في حالتنا إلى قائمة من الكلمات، ثم استخرجنا الجزء الأول ليكون رقم الشارع، بعد ذلك استخدمنا تابع سلسلةٍ نصية آخر هو <code>join</code> لدمج الحقول المتبقية معًا مع الفصل بينها بمسافة. كذلك نحتاج إلى تحويل السلسلة النصية إلى مصفوفة <code>bytes</code> لأن هذا هو ما تستخدمه وحدة <code>srtuct</code>، ويكون طول تلك السلسلة هو ما نحتاج إليه في سلسلة تنسيق <code>struct</code>، لذا نستخدم دالة <code>len()‎</code> بالتوازي مع سلسلة تنسيق عادية لبناء سلسلة تنسيق <code>struct</code>.
</p>

<p>
	ستعيد <code>formatAddress()‎</code> تسلسلًا من البايتات يحتوي على التمثيل الثنائي لعنواننا، وبما أن لدينا البيانات الثنائية فسنرى كيف نستطيع كتابتها إلى ملف ثنائي، ثم قراءتها مرةً أخرى.
</p>

<h3>
	القراءة والكتابة باستخدام struct
</h3>

<p>
	لننشئ ملفًا ثنائيًا يحتوي على سطر عنوان واحد باستخدام الدالة <code>formatAddress()‎</code> المعرَّفة أعلاه، وهنا سنحتاج إلى فتح الملف للكتابة في وضع <code>'wb'</code>، وترميز البيانات وكتابتها إلى الملف، ثم إغلاق الملف.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8059_81" style=""><span class="kwd">import</span><span class="pln"> </span><span class="kwd">struct</span><span class="pln">
f </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'address.bin'</span><span class="pun">,</span><span class="str">'wb'</span><span class="pun">)</span><span class="pln">
data </span><span class="pun">=</span><span class="pln"> </span><span class="str">"10 Some St, Anytown, 0171 234 8765"</span><span class="pln">
bindata </span><span class="pun">=</span><span class="pln"> formatAddress</span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Binary data before saving: "</span><span class="pun">,</span><span class="pln"> repr</span><span class="pun">(</span><span class="pln">bindata</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
f</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">bindata</span><span class="pun">)</span><span class="pln">
f</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	نستطيع التحقق من أن البيانات في صورة ثنائية بفتح <code>address.bin</code> في محرر نصي، وسنرى حينها أن المحارف لا زالت قابلةً للقراءة لكن الرقم اختفى، فإذا فتحنا الملف في محرر نصي يدعم الملفات الثنائية مثل ViM أو Emacs، فسنجد أن بداية الملف فيها 4 بايت، حيث سيبدو الأول منها مثل محرف سطر جديد، أما البقية فتبدو أصفارًا، وذلك لأن القيمة العددية للسطر الجديد هي 10، كما نرى هنا باستخدام بايثون:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8059_83" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> ord</span><span class="pun">(</span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">10</span></pre>

<p>
	تعيد الدالة <code>ord()‎</code> في هذا المثال القيمة العددية لأي محرف، لذا فإن أول أربعة بايتات هي <code>10,0,0,0</code> في النظام العشري، أو <code>0xA,0x0,0x0,0x0</code> في النظام الست عشري، وهو النظام المستخدم عادةً في عرض البيانات الثنائية بما أنه أكثر اختصارًا من استخدام الأرقام الثنائية الخالصة.
</p>

<p>
	يُأخذ العدد الصحيح في حاسوب ذي معمارية 32 بت أربعة بايتات، لذا فإن القيمة العددية "10" قد حُولت بواسطة وحدة <code>struct</code> إلى تسلسل من 4 بايتات هو <code>10,0,0,0</code>. وتضع معالجات إنتل البايت الأقل أهميةً في البداية، وهنا سنحصل على القيمة الثنائية الحقيقية من خلال قراءة التسلسل عكسيًا <code>0,0,0,10</code>، وهي القيمة الصحيحة 10 ممثلةً بأربعة بايتات عشرية؛ أما بقية البيانات فهي السلسلة النصية الأصلية، لذا تظهر بصيغتها المحرفية العادية.
</p>

<p>
	يجب الانتباه إلى عدم حفظ الملف من داخل محرر Notepad، فرغم أنه يستطيع تحميل بعض الملفات الثنائية، إلا أنه لا يستطيع حفظ الملفات الثنائية، لذا سيحول القيم الثنائية إلى نصوص، مما سيؤدي إلى تخريب البيانات الحقيقية.
</p>

<p>
	لم يكن امتداد الملف الذي استخدمناه <code>.bin</code> إلا للشرح، إذ ليس له تأثير حقيقي في كون الملف نصيًا أم ثنائيًا، وتستخدم بعض أنظمة التشغيل هذه الامتدادات لتحديد البرنامج الذي يفتح الملفات، لكن يمكن تغيير الامتداد بإعادة تسمية الملف ببساطة، ولن يتغير المحتوى الذي فيه، إذ سيظل ثنائيًا أو نصيًا كما كان، فإذا أعدنا تسمية ملف نصي بحيث نجعل امتداده <code>.exe</code> مثلًا، فسيعامله ويندوز على أنه ملف ثنائي تنفيذي، لكننا سنحصل على خطأ عند محاولة تشغيله مثل ملف تنفيذي، وذلك لأن النص الموجود فيه ليس شيفرةً ثنائيةً تنفيذية، فإذا أرجعناه إلى التسمية الأصلية له ثم فتحناه في Notepad، فسنجده كما كان قبل التسمية بالضبط، بل لو فتحناه في Notepad أثناء تسميته بامتداد <code>.exe</code> لفتحه المحرر مثل ملف نصي أيضًا.
</p>

<p>
	نحتاج إلى أن فتح الملف في وضع <code>rb</code> لقراءة بياناتنا الثنائية مرةً أخرى، فنقرأ البيانات في تسلسل من البايتات ثم نغلق الملفK ونفك البيانات باستخدم سلسلة تنسيق <code>struct</code>. سيبقى السؤال هنا حول كيفية معرفة شكل سلسلة التنسيق، والإجابة هنا هي أننا نحتاج إلى إيجاد السلسلة الثنائية من تعريف الملف، وتوفر عدة مواقع على الويب هذه المعلومات، فشركة أدوبي مثلًا تنشر تعريف تنسيقها الثنائي لصيغة PDF الخاصة بها، وفي حالتنا هذه سنعرف أنها يجب أن تكون السلسلة التي أنشأناها في <code>formatAddress()‎</code>، وهي <code>'iNs'</code>، حيث N رقم متغير.
</p>

<p>
	توفر وحدة <code>struct</code> بعض الدوال المساعدة التي تعيد حجم كل نوع من أنواع البيانات، لذلك فإن شغلنا محث بايثون وأجرينا بعض التجارب، فسنستطيع معرفة عدد بايتات البيانات التي سنحصل عليها لكل نوع بيانات، وهكذا نستطيع تحديد قيمة N:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_85" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> struct
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pln"> struct</span><span class="pun">.</span><span class="pln">calcsize</span><span class="pun">(</span><span class="str">'i'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">4</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pln"> struct</span><span class="pun">.</span><span class="pln">calcsize</span><span class="pun">(</span><span class="str">'s'</span><span class="pun">)</span><span class="pln">
</span><span class="lit">1</span></pre>

<p>
	وبما أننا نعرف أن بياناتنا ستترك 4 بايتات للعدد وبايتًا واحدًا لكل محرف، فستكون N هي إجمالي طول البيانات ناقصًا منه 4، لنجرب استخدام هذا لقراءة ملفنا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_87" style=""><span class="kwd">import</span><span class="pln"> struct
f </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'address.bin'</span><span class="pun">,</span><span class="str">'rb'</span><span class="pun">)</span><span class="pln">
data </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">read</span><span class="pun">()</span><span class="pln">
f</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">

fmtString </span><span class="pun">=</span><span class="pln"> </span><span class="str">"i%ds"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln">
number</span><span class="pun">,</span><span class="pln"> rest </span><span class="pun">=</span><span class="pln"> struct</span><span class="pun">.</span><span class="pln">unpack</span><span class="pun">(</span><span class="pln">fmtString</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">)</span><span class="pln">
rest </span><span class="pun">=</span><span class="pln"> rest</span><span class="pun">.</span><span class="pln">decode</span><span class="pun">(</span><span class="str">'utf8'</span><span class="pun">)</span><span class="pln"> </span><span class="com">#convert bytes to string</span><span class="pln">
address </span><span class="pun">=</span><span class="pln"> </span><span class="str">' '</span><span class="pun">.</span><span class="pln">join</span><span class="pun">((</span><span class="pln">str</span><span class="pun">(</span><span class="pln">number</span><span class="pun">),</span><span class="pln">rest</span><span class="pun">))</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Address after restoring data:"</span><span class="pun">,</span><span class="pln"> address </span><span class="pun">)</span></pre>

<p>
	لاحظ أننا اضطررنا إلى تحويل <code>rest</code> إلى سلسلة نصية باستخدام دالة <code>decode()‎</code> لأن بايثون رأتها من النوع <code>bytes</code> الذي لن يعمل مع <code>join()‎</code>.
</p>

<p>
	وهكذا نكون قد شرحنا ملفات البيانات الثنائية بما يكفي في هذا المقال، وقد بينا أنها تأتي بعدة تعقيدات، ولا ننصح باستخدامها ما لم يكن ثمة سبب مقنع، لكن هذا الشرح كاف لتستطيع قراءة الملفات الثنائية عند الحاجة إلى ذلك، طالما عرفت ما هي البيانات الممثلة في تلك الملفات ابتداءً.
</p>

<h2>
	الوصول العشوائي إلى الملفات
</h2>

<p>
	يشير الوصول العشوائي إلى التحرك مباشرةً إلى جزء بعينه من الملف، دون قراءة البيانات التي بين نقطة البدء والبيانات المطلوبة، وتوفر بعض لغات البرمجة نوع ملف مفهرس خاص يستطيع فعل ذلك بسرعة عالية، لكنه مبني في أغلب اللغات على الوصول المتتابع للملفات، الذي كنا نستخدمه منذ بداية هذه السلسلة إلى الآن.
</p>

<p>
	يقوم الوصول العشوائي على مفهوم مؤشر يشير إلى الموضع الحالي في الملف، أي عدد البايتات التي تفصلنا عن البداية حرفيًا، ونستطيع تحريك هذا المؤشر بالنسبة إلى موضعه الحالي أو نسبةً إلى بداية الملف، كما نستطيع أن نطلب من الملف أن يخبرنا بالمكان الحالي للمؤشر.
</p>

<p>
	ونستخدم طول سطر ثابت -ربما بحشو سلاسل البيانات الخاصة بنا بمسافات أو بعض المحارف الأخرى عند الحاجة- كي نقفز إلى بداية سطر ما، من خلال ضرب طول السطر بعدد الأسطر، وهذا ما يوحي بالوصول العشوائي للبيانات في الملف.
</p>

<h3>
	أين أنا؟
</h3>

<p>
	لتحديد مكاننا في ملف ما نستخدم التابع <code>tell()‎</code> الخاص بالملف، فإذا فتحنا ملفًا وقرأنا ثلاثة أسطر، فعندها سنستطيع أن نسأل الملف حينها كم قرأنا من الملف حتى الآن.
</p>

<p>
	لننظر في مثال ليتضح المعنى، حيث سننشئ ملفًا بخمسة أسطر نصية لها نفس الطول -وتساوي الطول هنا ليس ضروريًا وإنما هو لتوضيح المثال-، بعدها سنقرأ ثلاثة أسطر ونسأل أين نحن، ثم نعود إلى البداية ونقرأ سطرًا واحدًا ونقفز إلى السطر الثالث ونطبعه، ثم نعود إلى السطر الثاني، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8059_89" style=""><span class="com"># (+ \n) أنشئ 5 أسطر من عشرين محرفًا </span><span class="pln">
testfile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'testfile.txt'</span><span class="pun">,</span><span class="str">'w'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">5</span><span class="pun">):</span><span class="pln">
    testfile</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">str</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">20</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">
testfile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">

</span><span class="com"># اقرأ ثلاثة أسطر واسأل أين نحن</span><span class="pln">
testfile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'testfile.txt'</span><span class="pun">,</span><span class="str">'r'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">3</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> testfile</span><span class="pun">.</span><span class="pln">readline</span><span class="pun">().</span><span class="pln">strip</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
position </span><span class="pun">=</span><span class="pln"> testfile</span><span class="pun">.</span><span class="pln">tell</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"At position: "</span><span class="pun">,</span><span class="pln"> position</span><span class="pun">,</span><span class="pln"> </span><span class="str">"bytes"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

</span><span class="com"># عد إلى البداية</span><span class="pln">
testfile</span><span class="pun">.</span><span class="pln">seek</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> testfile</span><span class="pun">.</span><span class="pln">readline</span><span class="pun">().</span><span class="pln">strip</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="com"># كرر السطر الأول</span><span class="pln">
lineLength </span><span class="pun">=</span><span class="pln"> testfile</span><span class="pun">.</span><span class="pln">tell</span><span class="pun">()</span><span class="pln">
testfile</span><span class="pun">.</span><span class="pln">seek</span><span class="pun">(</span><span class="lit">2</span><span class="pun">*</span><span class="pln">lineLength</span><span class="pun">)</span><span class="pln">  </span><span class="com"># اذهب إلى نهاية السطر 2</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> testfile</span><span class="pun">.</span><span class="pln">readline</span><span class="pun">().</span><span class="pln">strip</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="com"># السطر الثالث</span><span class="pln">
testfile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	لقد استخدمنا الدالة <code>seek()‎</code> لتحريك المؤشر، والعملية الافتراضية هنا هي تحريكه إلى رقم البايت المحدد كما رأينا هنا، لكن يمكن إضافة وسطاء آخرين لتغيير تابع الفهرسة المستخدم.
</p>

<p>
	لاحظ أيضًا أن القيمة التي طبعتها <code>tell()‎</code> الأولى تعتمد على طول السطر الجديد على نظامك، فنظام وندوز 10 مثلًا يطبع 66 ليشير إلى أن تسلسل السطر الجديد طوله 2 بايت، لكن بما أن هذه القيمة تتوقف على نظام التشغيل ونحن نريد أن نجعل الشيفرة محمولةً قدر الإمكان؛ فقد استخدمنا <code>tell()‎</code> مرةً ثانيةً بعد قراءة سطر واحد لحساب طول كل سطر، وسترى أن مثل تلك الحيل ضرورية عند التعامل مع مشاكل المنصات المختلفة.
</p>

<h2>
	خاتمة
</h2>

<p>
	في نهاية هذا المقال نرجو أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		ضرورة فتح الملفات قبل استخدامها.
	</li>
	<li>
		قراءة الملفات أو الكتابة فيها، إذ لا يمكن تنفيذ العمليتين معًا.
	</li>
	<li>
		الدالة <code>readlines()‎</code> في بايثون التي تقرأ جميع الأسطر الموجودة في ملف ما، والدالة <code>readline()‎</code> التي تقرأ سطرًا واحدًا في كل مرة، وهذا يوفر في الذاكرة.
	</li>
	<li>
		عدم الحاجة إلى استخدام أي من الدالتين السابقتين بما أن دالة <code>open</code> الخاصة ببايثون تعمل مع حلقات <code>for</code>.
	</li>
	<li>
		ضرورة غلق الملفات بعد استخدامها.
	</li>
	<li>
		ضرورة إضافة <code>b</code> إلى نهاية راية الوضع mode flag الخاصة بالملفات الثنائية، وتحتاج البيانات إلى تفسير بعد قراءتها، وذلك بواسطة وحدة <code>struct</code> عادةً.
	</li>
	<li>
		تفعّل كل من <code>tell()‎</code> و<code>seek()‎</code> الوصول شبه العشوائي pseudo-random إلى الملفات متسلسلة الوصول sequential files.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutfiles.htm" rel="external nofollow">للفصل الثاني عشر: Handling Files من كتاب Learning To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1341/" rel="">كيفية التعامل مع النصوص في البرمجة</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-r1333/" rel="">البرمجة باستخدام الوحدات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">ما هي البرمجة ومتطلبات تعلمها؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1334</guid><pubDate>Fri, 08 Oct 2021 15:02:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x648;&#x62D;&#x62F;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-r1333/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/615810e80dbdb_--.png.5d3f80ab86d71e853814413e36efda5d.png" /></p>
<p>
	إن العنصر الرابع من عناصر البرمجة هو الوحدات، ومع أنك تستطيع كتابة بعض البرامج الرائعة بما تعلمته من بداية هذه الدروس إلى الآن دون تعلم الوحدات، إلا أن تتبع ما يحدث في البرامج -مع زيادة حجمها- يصبح صعبًا جدًا، وسنحتاج إلى طريقة لاستخلاص بعض التفاصيل لنستطيع التفكير في المشكلات التي تواجهنا ونريد حلها، بدلًا من صرف الجهد والوقت في التفاصيل الدقيقة المتعلقة بكيفية عمل الحاسوب. توفر بايثون وجافاسكربت وVBScript ذلك إلى حد ما بما فيها من إمكانيات مضمّنة تلقائيًا، فهي تجنبنا التعامل مع عتاد الحواسيب والنظر في كيفية قراءة كل مفتاح على لوحة المفاتيح على حدة، وغير ذلك من الأمور التي تستنزف موارد المبرمجين.
</p>

<p>
	وتعتمد فكرة البرمجة باستخدام الوحدات على السماح للمبرمج بتوسيع الإمكانيات الموجودة في لغة البرمجة، عبر تجميع أجزاء من البرنامج في وحدات يمكن توصيلها ببرامجنا، وقد كانت الصورة الأولى للوحدات هي البرامج الفرعية subroutines التي تمثل كتلةً من الشيفرة نستطيع القفز إليها، بدلًا من استخدام <code>GOTO</code> التي ذكرناها في <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/" rel="">المقال السابق</a>، لكنها تقفز عند تمام الكتلة عائدةً إلى المكان الذي استدعيت منه، ويُعرف هذا الأسلوب من الوحدات بالإجراء procedure أو الدالة function، بل إن مفهوم الوحدة module نفسه يتغير في بعض اللغات مثل بايثون، ليأخذ معنىً أكثر دقة.
</p>

<h2>
	استخدام الدوال
</h2>

<p>
	لننظر أولًا في كيفية استخدام الدوال functions الكثيرة التي تأتي في أي لغة برمجة، حيث تسمى مجموعة الدوال القياسية المضمّنة في اللغة باسم المكتبة القياسية، وقد رأينا استخدام بعض الدوال، وذكرناه في قسم العوامل في مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r1287/" rel="">البيانات وأنواعها</a>؛ أما الآن فسننظر في الأمور المشتركة بينها، وكيف يمكن أن نستخدمها في برامجنا.
</p>

<p>
	للدالة الهيكل الأساسي التالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_1066_15" style=""><span class="pln">aValue </span><span class="pun">=</span><span class="pln"> someFunction </span><span class="pun">(</span><span class="pln"> anArgument</span><span class="pun">,</span><span class="pln"> another</span><span class="pun">,</span><span class="pln"> etc</span><span class="pun">...</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	يأخذ المتغير <code>aValue</code> القيمة التي نحصل عليها باستدعاء الدالة <code>someFunction</code>، والتي تقبل عدة وسطاء arguments بين القوسين -وقد لا يوجد أي وسيط-، وتعاملها على أنها متغيرات داخلية، وتستطيع الدوال أن تستدعي دوالًا أخرى داخلها.
</p>

<p>
	تفرض بعض اللغات وضع القوسين للدالة عند استدعائها حتى لو لم يكن لها وسطاء، وقد ذكرنا أنه يفضل تعويد النفس على استخدام الأقواس حتى في لغات مثل VBScript التي لا تشترط استخدامها حتى مع وجود الوسطاء.
</p>

<p>
	لننظر الآن في بعض الأمثلة في لغاتنا الثلاث، ولنرى الدوال عمليًا:
</p>

<h3>
	الدالة Mid في VBScript
</h3>

<p>
	تعيد الدالة <code>Mid(aString, start, length)‎</code> مجموعة المحارف من <code>aString</code> بدءًا من <code>start</code> وبعدد محارف <code>length</code>، حيث ستعرض الشيفرة التالية "Good EVENING" مثلًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_17" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> time
time </span><span class="pun">=</span><span class="pln"> </span><span class="str">"MORNING EVENING AFTERNOON"</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"Good"</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">Mid</span><span class="pun">(</span><span class="pln">time</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	نلاحظ أن VBScript لا تتطلب أقواسًا لجمع وسطاء الدالة بل تكتفي بالمسافات كما كنا نفعل مع <code>MsgBox</code>، لكن عند جمعنا دالتين -كما فعلنا هنا- فيجب أن تستخدم الدالة الداخلية أقواسًا، والنصيحة العامة هي استخدام الأقواس عندما نشك هل يجب استخدامها أم لا.
</p>

<h3>
	الدالة Date في VBScript
</h3>

<p>
	تعيد الشيفرة التالية التاريخ الحالي للنظام:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_19" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="typ">Date</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	بما أن المثال بسيط فلا يوجد ما يمكن شرحه هنا، لكن تجدر الإشارة إلى وجود مجموعة كاملة من دوال التاريخ الأخرى التي تستخرج اليوم والأسبوع والساعة.
</p>

<h3>
	الدالة startString.replace في جافاسكربت
</h3>

<p>
	تعيد دالة <code>startString.replace(searchString, newString)‎</code> سلسلةً نصيةً جديدةً مع وضع <code>newString</code> بدلًا من <code>searchString‎</code> في <code>startString</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_21" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> r</span><span class="pun">,</span><span class="pln">s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"A long and winding road"</span><span class="pun">;</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"Original = "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> s </span><span class="pun">+</span><span class="pln"> </span><span class="str">"&lt;BR&gt;"</span><span class="pun">);</span><span class="pln">
r </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">replace</span><span class="pun">(</span><span class="str">"long"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"short"</span><span class="pun">);</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"Result  = "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> r</span><span class="pun">);</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لاحظ أن الدوال في جافاسكربت ما هي إلا مثال لنوع خاص يسمى بالتابع method، وهو دالة ترتبط بكائن، كما شرحنا في مقال البيانات وأنواعها المذكور أعلاه، وكما سنشرح لاحقًا. وما نريد قوله، هو أن الدالة ترتبط بالسلسلة النصية <code>s</code> بواسطة عامل النقطة <code>.</code>، وهذا يعني أن <code>s</code> هي السلسلة التي سننفذ عليها الاستبدال، وهذا أمر عرضناه من قبل باستخدام التابع <code>write()‎</code> الخاص بالكائن <code>document</code> الذي استخدمناه لعرض الخرج من برامج جافاسكربت باستخدام <code>document.write()‎</code>، لكننا لم نشرح السبب وراء صيغة الاسم المزدوجة حتى الآن.
</p>

<h3>
	الدالة Math.pow في جافاسكربت
</h3>

<p>
	نستخدم الدالة <code>pow(x,y)‎</code> في وحدة Math -التي ذكرناها في مقال الخامس: البيانات وأنواعها- لرفع x إلى الأس y:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_23" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">pow</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<h3>
	الدالة pow في بايثون
</h3>

<p>
	تستخدم بايثون دالة <code>pow(x,y)‎</code> لرفع x إلى الأس y:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_25" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln">   </span><span class="pun">#</span><span class="pln">  </span><span class="pun">سنستخدم</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">كرقم</span><span class="pln"> </span><span class="pun">قاعدة</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> y in range</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">11</span><span class="pun">):</span><span class="pln">
</span><span class="pun">...</span><span class="pln">    print</span><span class="pun">(</span><span class="pln"> pow</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">    </span><span class="pun">#</span><span class="pln"> y </span><span class="pun">ارفع</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">الأس</span><span class="pln">
                            </span><span class="pun">#</span><span class="pln"> </span><span class="pun">أي</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="lit">0</span><span class="pun">-</span><span class="lit">10</span></pre>

<p>
	نولد هنا قيم y من 0 إلى 10، ونستدعي الدالة المضمنة <code>pow()‎</code> لتمرير وسيطين هما x وy، ونستبدل القيم الحالية لكل منهما في استدعاء <code>pow()‎</code> في كل مرة، ثم نطبع النتيجة.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		تجدر الإشارة إلى أن العامل الأسي <code>**</code> في بايثون يكافئ الدالة <code>pow()‎</code>.
	</p>
</blockquote>

<h3>
	الدالة dir في بايثون
</h3>

<p>
	إحدى الدوال المفيدة المضمنة في بايثون هي دالة <code>dir</code>، والتي تعرض جميع الأسماء المصدَّرة داخل وحدة ما إذا مررنا اسم الوحدة إليها، بما في ذلك جميع المتغيرات والدوال التي يمكن استخدامها، وعلى الرغم من أننا لم نشرح إلا بضع وحدات في بايثون، إلا أنها تأتي بوحدات كثيرة. تعيد الدالة <code>dir</code> قائمةً من الأسماء الصالحة في الوحدة، والتي تكون دوالًا في الغالب. لنجرب هذه الدالة على بعض الدوال المضمنة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_27" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> print</span><span class="pun">(</span><span class="pln"> dir</span><span class="pun">(</span><span class="pln">__builtins__</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ أن <code>builtins</code> هي إحدى الكلمات السحرية في بايثون، وعلى ذلك يجب إحاطتها بزوج من شرطتين سفليتين على كل جانب. وإذا أردنا استخدام <code>dir()‎</code> على أي وحدة، فسنحتاج إلى استيرادها أولًا باستخدام <code>import</code>، وإلا فستخبرنا بايثون أنها لا تتعرف عليها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_29" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> sys
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> dir</span><span class="pun">(</span><span class="pln">sys</span><span class="pun">)</span></pre>

<p>
	لقد استوردنا وحدة <code>sys</code> في المثال أعلاه، وهي الوحدة التي ذكرناها أول مرة في مقال <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B3%D9%84%D8%B3%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B3%D9%8A%D8%B7%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1281/" rel="">التسلسلات البسيطة</a>، ونستطيع أن نرى كلًا من <code>exit</code> و<code>argv</code> و<code>stdin</code> و<code>stdout</code> في الخرج الأخير لدالة <code>dir</code>، بين الأشياء الأخرى الموجودة في وحدة <code>sys</code>.
</p>

<p>
	لننظر الآن في وحدات بايثون بقليل من التفصيل قبل أن ننتقل إلى ما بعدها.
</p>

<h2>
	استخدام الوحدات في بايثون
</h2>

<p>
	تتميز لغة بايثون بقابليتها الكبيرة للتوسع، حيث نستطيع إضافة وحدات جديدة باستيرادها بواسطة <code>import</code>، وفيما يلي بعض الوحدات التي تأتي افتراضيًا مع بايثون.
</p>

<h3>
	الوحدة sys
</h3>

<p>
	رأينا <code>sys</code> سابقًا عند الخروج من بايثون، وهي تحتوي على مجموعة من الدوال المفيدة كدالة <code>dir</code> التي سبق شرحها، ويجب أن نستورد وحدة <code>sys</code> أولًا لنصل إلى تلك الدوال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_31" style=""><span class="kwd">import</span><span class="pln"> sys        </span><span class="pun">#</span><span class="pln"> </span><span class="pun">نجعل</span><span class="pln"> </span><span class="pun">الدوال</span><span class="pln"> </span><span class="pun">متاحة</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> sys</span><span class="pun">.</span><span class="pln">path </span><span class="pun">)</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">نرى</span><span class="pln"> </span><span class="pun">أين</span><span class="pln"> </span><span class="pun">تبحث</span><span class="pln"> </span><span class="pun">بايثون</span><span class="pln"> </span><span class="pun">عن</span><span class="pln"> </span><span class="pun">الدوال</span><span class="pln">
sys</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">()</span><span class="pln">        </span><span class="pun">#</span><span class="pln"> </span><span class="str">'sys'</span><span class="pln"> </span><span class="pun">أسبقها</span><span class="pln"> </span><span class="pun">بـ</span></pre>

<p>
	وإذا علمنا أننا سنستخدم الدوال بكثرة وأنها لن تحمل نفس أسماء الدوال التي استوردناها أو أنشأناها؛ فعندئذ نستطيع فعل ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_33" style=""><span class="pln">from sys </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> sys </span><span class="pun">استورد</span><span class="pln"> </span><span class="pun">جميع</span><span class="pln"> </span><span class="pun">الأسماء</span><span class="pln"> </span><span class="pun">في</span><span class="pln">  
print</span><span class="pun">(</span><span class="pln"> path </span><span class="pun">)</span><span class="pln">      </span><span class="pun">#</span><span class="pln"> </span><span class="pun">يمكن</span><span class="pln"> </span><span class="pun">استخدامها</span><span class="pln"> </span><span class="pun">دون</span><span class="pln"> </span><span class="pun">تحديد</span><span class="pln"> </span><span class="pun">السابقة</span><span class="pln"> </span><span class="str">'sys'</span><span class="pln">
exit</span><span class="pun">()</span><span class="pln"> </span></pre>

<p>
	يتمثل خطر هذا النهج في إمكانية وجود دوال بنفس الاسم في وحدتين مختلفتين، وبالتالي لن نستطيع الوصول إلا إلى الدوال التي استوردناها ثانيًا، لأننا بهذه الطريقة سنلغي الدالة التي استوردناها أولًا، فإذا أردنا أن نستخدم بعض العناصر فقط، فيفضل أن ننفذ ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_35" style=""><span class="pln">from sys </span><span class="kwd">import</span><span class="pln"> path</span><span class="pun">,</span><span class="pln"> exit  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">استورد</span><span class="pln"> </span><span class="pun">الدوال</span><span class="pln"> </span><span class="pun">التي</span><span class="pln"> </span><span class="pun">تحتاجها</span><span class="pln"> </span><span class="pun">فقط</span><span class="pln">
exit</span><span class="pun">()</span><span class="pln">                      </span><span class="pun">#</span><span class="pln"> </span><span class="pun">استخدم</span><span class="pln"> </span><span class="pun">دون</span><span class="pln"> </span><span class="pun">تحديد</span><span class="pln"> </span><span class="pun">السابقة</span><span class="pln"> </span><span class="str">'sys'</span></pre>

<p>
	لاحظ أن الأسماء التي نحددها لا تحتوي على أقواسًا تليها، ففي تلك الحالة سنحاول تنفيذ الدوال بدلًا من استيرادها، ولا يُعطى هنا إلا اسم الدالة فقط.
</p>

<p>
	نريد الآن أن نشرح طريقةً مختصرةً توفر علينا القليل من الكتابة، وهي أننا نستطيع إعادة تسمية الوحدة عند استيرادها إذا كان لها اسم طويل جدًا، مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_38" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">SimpleXMLRPCServer</span><span class="pln"> as s
s</span><span class="pun">.</span><span class="typ">SimpleXMLRPCRequestHandler</span><span class="pun">()</span></pre>

<p>
	لاحظ كيف أخبرنا بايثون أن تعُد <code>s</code> اختصارًا لـ <code>SimpleXMLRPCServer</code>، ولن نحتاج بعد ذلك إلا إلى كتابة <code>s</code> كي نستخدم دوال الوحدة، مما قلل من الكتابة.
</p>

<h3>
	وحدات بايثون الأخرى
</h3>

<p>
	يمكن استيراد أي وحدة من وحدات بايثون واستخدامها بالطريقة السابقة، وهذا يشمل الوحدات التي ننشئها بأنفسنا، لنلق الآن نظرةً على بعض الوحدات القياسية في بايثون، وما توفره من وظائف:
</p>

<ul>
	<li>
		وحدة <code>sys</code>: تسمح بالتفاعل مع نظام بايثون:

		<ul>
			<li>
				<code>exit()‎</code>: للخروج.
			</li>
			<li>
				<code>argv</code>: للوصول إلى وسطاء سطر الأوامر.
			</li>
			<li>
				<code>path</code>: للوصول إلى مسار البحث الخاص بوحدة النظام.
			</li>
			<li>
				<code>ps1</code>: لتغيير محث بايثون <code>‎&gt;&gt;&gt;‎</code>.
			</li>
		</ul>
	</li>
	<li>
		وحدة <code>os</code>: تسمح بالتفاعل مع نظام التشغيل:
		<ul>
			<li>
				<code>name</code>: تعطينا اسم نظام التشغيل الحالي، وهي مفيدة في البرامج المحمولة التي لا تحتاج إلى تثبيت.
			</li>
			<li>
				<code>system()‎</code>: تنفذ أمرًا من أوامر نظام التشغيل.
			</li>
			<li>
				<code>mkdir()‎</code>: تنشئ مجلدًا.
			</li>
			<li>
				<code>getcwd()‎</code>: تعطينا مجلد العمل الحالي.
			</li>
		</ul>
	</li>
	<li>
		وحدة <code>re</code>: تسمح هذه الوحدة بتعديل السلاسل النصية باستخدام التعابير النمطية regular expressions لنظام يونكس:
		<ul>
			<li>
				<code>search()‎</code>: تبحث عن النمط في أي موضع في السلسلة النصية.
			</li>
			<li>
				<code>match()‎</code>: تبحث في البداية فقط.
			</li>
			<li>
				<code>findall()‎</code>: تبحث عن جميع مرات الورود في سلسلة نصية.
			</li>
			<li>
				<code>split()‎</code>: تقسيم السلسلة النصية إلى حقول مفصولة بالنمط.
			</li>
			<li>
				<code>()sub وsubn()‎</code>: استبدال السلاسل النصية.
			</li>
			<li>
				وحدة <code>math</code>: تسمح بالوصول إلى العديد من الدوال الرياضية.
			</li>
			<li>
				<code>()sin وcos()‎</code>: دوال حساب المثلثات.
			</li>
			<li>
				<code>log(), log10()‎</code>: اللوغاريتمات الطبيعية والعشرية.
			</li>
			<li>
				<code>()ceil وfloor()‎</code>: دالتا الجزء الصحيح floor والمتمم الصحيح الأعلى ceiling.
			</li>
			<li>
				<code>pi وe</code>: الثوابت الطبيعية.
			</li>
			<li>
				وحدة <code>time</code>: دوال التاريخ والوقت.
			</li>
			<li>
				<code>time()‎</code>: تحصل على الوقت الحالي بالثواني.
			</li>
			<li>
				<code>gmtime()‎</code>: تحول الوقت بالثواني إلى التوقيت العالمي UTC (أو GMT).
			</li>
			<li>
				<code>localtime()‎</code>: التحويل إلى التوقيت المحلي.
			</li>
			<li>
				<code>mktime()‎</code>: معكوس التوقيت المحلي.
			</li>
			<li>
				<code>strftime()‎</code>: تنسيق السلسلة النصية للوقت، مثل YYYYMMDD أو DDMMYYYY.
			</li>
			<li>
				<code>sleep()‎</code>: إيقاف البرنامج مؤقتًا لمدة n ثانية.
			</li>
			<li>
				وحدة <code>random</code>: تولد أرقامًا عشوائية، وهي مفيدة في برمجة الألعاب.
			</li>
			<li>
				<code>randint()‎</code>: تولد عددًا صحيحًا عشوائيًا بين نقطتين تضمَّنان في التوليد.
			</li>
			<li>
				<code>sample()‎</code>: تولد قائمةً فرعيةً عشوائيًا من قائمة أكبر.
			</li>
			<li>
				<code>seed()‎</code>: إعادة ضبط مفتاح توليد الأعداد.
			</li>
		</ul>
	</li>
</ul>

<p>
	هذه الوحدات على كثرتها ليست إلا شيئًا يسيرًا من الوحدات التي توفرها بايثون، والتي تزيد على مئة واحدة وأكثر يمكن تحميلها. تذكر أننا نستطيع استخدام <code>dir()‎</code> و<code>help()‎</code> للحصول على معلومات عن كيفية استخدام الدوال المختلفة، وأن المكتبة القياسية موثقة جيدًا في <a href="https://docs.python.org/3/py-modindex.html" rel="external nofollow">فهرس وحدات بايثون</a>، ومن المصادر الجيدة للوحدات الإضافية <a href="http://pypi.python.org/pypi" rel="external nofollow">فهرس حزم بايثون</a>، الذي ضم عند كتابتنا لهذا المقال أكثر من مئة ألف حزمة، وكذلك <a href="https://www.scipy.org/" rel="external nofollow">مشروع SciPy</a> الذي يستضيف مئات وحدات المعالجة العلمية والعددية، ولا غنى عنه لمن يعمل على مشاريع تحليل علمية، وأفضل وسيلة للوصول إلى تلك الحزم هو تثبيت إحدى إصدارات بايثون التي تحتوي على SciPy كإضافة قياسية فيها، مثل موقع <a href="https://anaconda.org/" rel="external nofollow">anaconda.org</a>، كما يحتوي sourceforge ومواقع التطوير مفتوح المصدر الأخرى على عدة مشاريع لبايثون فيها وحدات نافعة، ويمكنك الاستعانة بمحرك البحث نظرًا لتعدد المصادر، وتستطيع تصفحها وغيرها إذا أضفت كلمة python في بحثك، ولا تنس قراءة <a href="https://wiki.hsoub.com/Python" rel="external">توثيق بايثون</a> للمزيد من المعلومات عن البرمجة للإنترنت والرسوميات وبناء قواعد البيانات وغيرها.
</p>

<p>
	والمهم هنا إدراك أن أغلب <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a> تحوي هذه الدوال، والوظائف الأساسية إما مضمّنة فيها أو تكون جزءًا من مكتبتها القياسية، فابحث أولًا في توثيقك قبل كتابة دالة ما، فربما تكون موجودةً ولا تحتاج إلى كتابتها.
</p>

<h2>
	تعريف الدوال الخاصة بنا
</h2>

<p>
	يمكن إنشاء دوال خاصة بنا من خلال تعريفها، أي بكتابة تعليمة تخبر المفسر أننا نعرِّف كتلةً من الشيفرة، ويجب عليه تنفيذها عندما نطلبها في أي مكان في البرنامج.
</p>

<h3>
	VBScript
</h3>

<p>
	سننشئ الآن دالةً تطبع مثال جدول الضرب الخاص بنا لأي قيمة نعطيها إليها كوسيط، ;ستبدو هذه الدالة في VBScript كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_40" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Sub</span><span class="pln"> </span><span class="typ">Times</span><span class="pun">(</span><span class="pln">N</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> I
</span><span class="typ">For</span><span class="pln"> I </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="typ">To</span><span class="pln"> </span><span class="lit">12</span><span class="pln">
    </span><span class="typ">MsgBox</span><span class="pln"> I </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">" x "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> N </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">" = "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> I </span><span class="pun">*</span><span class="pln"> N
</span><span class="typ">Next</span><span class="pln"> 
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">Sub</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	sنبدأ هنا في هذا المثال بالكلمة المفتاحية <code>Sub</code> -وهي اختصار برنامج فرعي Subroutine-، التي تلي محدد VBScript لكتل الشيفرات مباشرةً في السطر الثاني، ثم نعطيها قائمةً من المعامِلات بين قوسين.
</p>

<p>
	أما الشيفرة التي داخل الكتلة المعرَّفة فهي شيفرة VBScript عادية مع استثناء أنها تعامل المعامِلات على أنها متغيرات محلية، لذا تسمى الدالة في المثال أعلاه <code>Times</code>، وتأخذ معامِلًا واحدًا هو <code>N</code>، كما تعرِّف المتغير المحلي <code>I</code>، ثم تنفذ حلقةً تكراريةً تعرض جدول الضرب الخاص بالعدد N باستخدام المتغيرين <code>N</code> و <code>I</code>، نستدعي هذه الدالة الجديدة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_42" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"Here is the 7 times table..."</span><span class="pln">
</span><span class="typ">Times</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لاحظ أننا عرّفنا معاملًا اسمه <code>N</code> ومررنا إليه الوسيط <code>7</code>، وقد أخذ المعامل أو المتغير المحلي <code>N</code> داخل الدالة القيمة <code>7</code> عندما استدعيناه، ويمكن تعريف أي عدد نريده من المعامِلات في تعريف الدالة، وعلى البرامج المستدعية أن توفر قيمةً لكل معامِل. تسمح بعض لغات البرمجة بتعريف قيم افتراضية للمعامل في حالة عدم توفير قيمة، لتستخدم الدالة تلك القيمة الافتراضية.
</p>

<p>
	كذلك فقد غلفنا المعامل <code>N</code> بقوسين أثناء تعريف الدالة، لكن هذا غير ضروري في VBScript عند استدعاء الدالة، كما قلنا من قبل.
</p>

<p>
	لا تعيد هذه الدالة أي قيمة، وهو ما نسميه بالإجراء في البرمجة، وما هو إلا دالة لا تعيد قيمةً، وتفرّق لغة VBScript بين الدوال والإجراءات باستخدام أسماء مختلفة لتعريفاتهما، فمثلًا: تعيد الدالة التالية في VBScript جدول الضرب الخاص بنا في سلسلة نصية طويلة واحدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_44" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Function</span><span class="pln"> </span><span class="typ">TimesTable</span><span class="pln"> </span><span class="pun">(</span><span class="pln">N</span><span class="pun">)</span><span class="pln">
  </span><span class="typ">Dim</span><span class="pln"> I</span><span class="pun">,</span><span class="pln"> S
  S </span><span class="pun">=</span><span class="pln"> N </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">" times table"</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> vbNewLine
  </span><span class="typ">For</span><span class="pln"> I </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to </span><span class="lit">12</span><span class="pln">
    S </span><span class="pun">=</span><span class="pln"> S </span><span class="pun">&amp;</span><span class="pln"> I </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">" x "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> N </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">" = "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> I</span><span class="pun">*</span><span class="pln">N </span><span class="pun">&amp;</span><span class="pln"> vbNewLine
  </span><span class="typ">Next</span><span class="pln">
  </span><span class="typ">TimesTable</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> S
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">Function</span><span class="pln">

</span><span class="typ">Dim</span><span class="pln"> </span><span class="typ">Multiplier</span><span class="pln">
</span><span class="typ">Multiplier</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Which table would you like?"</span><span class="pun">)</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="typ">TimesTable</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Multiplier</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	تكاد صيغة هذه الشيفرة أن تطابق صيغة <code>Sub</code>، مع استثناء أننا استخدمنا الكلمة <code>Function</code> بدلًا من <code>Sub</code> السابقة، ويجب أن نسند النتيجة إلى اسم الدالة داخل التعريف، لهذا ستعيد الدالة أي قيمة يحتويها اسمها عند خروجها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_46" style=""><span class="pln">  </span><span class="pun">...</span><span class="pln">
  </span><span class="typ">TimesTable</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> S
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">Function</span></pre>

<p>
	فإذا لم نسند قيمةً لاسم الدالة بشكل صريح، فستعيد الدالة القيمة الافتراضية، والتي تكون في الغالب صفرًا أو سلسلةً نصيةً فارغةً.
</p>

<p>
	لاحظ أننا وضعنا أقواسًا حول الوسيط في سطر <code>MsgBox</code>، لأن <code>MsgBox</code> لن يعرف -لولا هذه الأقواس- هل يجب أن يُطبع <code>Multiplier</code> أم يُمرّره إلى الوسيط الأول والذي هو <code>TimesTable</code>، فلما وضعناه داخل الأقواس فهم المفسر أن القيمة هي وسيط للدالة <code>TimesTable</code> بدلًا من <code>MsgBox</code>.
</p>

<h3>
	بايثون
</h3>

<p>
	ستكون دالة جدول الضرب في بايثون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_48" style=""><span class="pln">def times</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i in range</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">13</span><span class="pun">):</span><span class="pln">
        print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%d x %d = %d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">*</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	وتُستدعى كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_50" style=""><span class="pln">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Here is the 9 times table..."</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
times</span><span class="pun">(</span><span class="lit">9</span><span class="pun">)</span></pre>

<p>
	لاحظ أن الإجراءات في بايثون لا تميَّز عن الدوال، ويُستخدم <code>def</code> لتعريفهما، والفرق الوحيد هو أن الدالة التي تعيد قيمةً تستخدم تعليمة <code>return</code>، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_52" style=""><span class="pln">def timesTable</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln">
   s </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> i in range</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">13</span><span class="pun">):</span><span class="pln">
       s </span><span class="pun">=</span><span class="pln"> s </span><span class="pun">+</span><span class="pln"> </span><span class="str">"%d x %d = %d\n"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln">n</span><span class="pun">,</span><span class="pln">n</span><span class="pun">*</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> s</span></pre>

<p>
	الأمر بسيط، إذ تعيد الدالة النتيجة باستخدام تعليمة <code>return</code>، أما إذا لم يكن لدينا تعليمة <code>return</code> صريحة فستعيد بايثون تلقائيًا قيمةً افتراضيةً تسمى <code>None</code>، والتي نتجاهلها في العادة. نستطيع الآن طباعة نتيجة الدالة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_54" style=""><span class="pln">print</span><span class="pun">(</span><span class="pln"> timesTable</span><span class="pun">(</span><span class="lit">7</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	يفضل عدم وضع تعليمات <code>print</code> داخل الدوال، وإنما جعل الدالة تعيد النتيجة باستخدام <code>return</code>، ثم طباعتها من خارج الدالة، ورغم أننا لم نتبع هذا الأسلوب في أمثلتنا، إلا أن هذا يجعل الدوال قابلةً لإعادة الاستخدام في نطاق أوسع من الحالات.
</p>

<p>
	يبقى أمر مهم للغاية يجب أن نذكره حول تعليمة <code>return</code>، وهو أنها لا تعيد قيمةً من الدالة فحسب، بل تعيد التحكم إلى الشيفرة التي استدعت الدالة، وتكمن أهمية ذلك في أن الإعادة لا يجب أن تكون آخر سطر في الدالة، فقد تكون هناك تعليمات أكثر، وقد لا تنفَّذ أبدًا، كما يمكن أن يحتوي متن الدالة الواحدة على عدة تعليمات <code>return</code>. تُنهي التعليمة التي نصل إليها أولًا الدالة وتعيد القيمة إلى الشيفرة المستدعية، سنعرض مثالًا عن دالة لها عدة تعليمات <code>return</code>، وهي تعيد أول عدد زوجي تجده في القائمة المزودة بها أو <code>None</code> إذا لم تجد أي عدد زوجي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_56" style=""><span class="pln">def firstEven</span><span class="pun">(</span><span class="pln">aList</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> num in aList</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> num </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">تحقق</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">كونه</span><span class="pln"> </span><span class="pun">زوجيًا</span><span class="pln">
         </span><span class="kwd">return</span><span class="pln"> num  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">اخرج</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">الدالة</span><span class="pln"> </span><span class="pun">فورًا</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">None</span><span class="pln">   </span><span class="pun">#</span><span class="pln"> </span><span class="pun">لا</span><span class="pln"> </span><span class="pun">نصل</span><span class="pln"> </span><span class="pun">إليها</span><span class="pln"> </span><span class="pun">إلا</span><span class="pln"> </span><span class="pun">إذا</span><span class="pln"> </span><span class="pun">لم</span><span class="pln"> </span><span class="pun">نجد</span><span class="pln"> </span><span class="pun">عددًا</span><span class="pln"> </span><span class="pun">زوجيًا</span></pre>

<h3>
	ملاحظة بشأن المعاملات
</h3>

<p>
	قد يصعب على المبتدئين فهم دور المعامِلات في تعريف الدالة، فهل يجب تعريف الدالة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_58" style=""><span class="pln">def f</span><span class="pun">(</span><span class="pln">x</span><span class="pun">):</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">داخل</span><span class="pln"> </span><span class="pun">الدالة</span><span class="pln"> x </span><span class="pun">يمكن</span><span class="pln"> </span><span class="pun">استخدام...</span></pre>

<p>
	أم تعريفها بالشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_60" style=""><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pln">
def f</span><span class="pun">():</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">داخل</span><span class="pln"> </span><span class="pun">الدالة</span><span class="pln"> x </span><span class="pun">يمكن</span><span class="pln"> </span><span class="pun">استخدام...</span></pre>

<p>
	يعرِّف المثال الأول هنا المعامِل x ويستخدمه داخل الدالة، بينما يستخدم المثال الثاني متغيرًا معرَّفًا من خارج الدالة مباشرةً، وبما أن المثال الثاني صالح ويعمل دون مشاكل، فلم نتكبد عناء تعريف المعامل؟، والجواب هو أن المعامِلات تتصرف مثل متغيرات محلية، أي مثل المتغيرات التي لا تُستخدم إلا داخل الدالة، وقلنا إن مستخدم الدالة يستطيع أن يمرر وسطاءً إلى هذه المعامِلات، وعلى ذلك تتصرف قائمة المعامِلات مثل بوابة للبيانات التي تتحرك بين البرنامج الرئيسي والدالة.
</p>

<p>
	تستطيع الدالة أن ترى بعض البيانات خارجها، لكن إذا أردنا للدالة أن تكون قابلةً لإعادة الاستخدام في أكثر من برنامج، فيجب أن نقلل اعتمادها على البيانات الخارجية، بل يجب أن تُمرَّر البيانات المطلوبة لأداء وظيفة الدالة بكفاءة إليها من خلال معامِلاتها، فإذا عُرِّفت الدالة داخل ملف وحدة، فيجب أن تكون لها صلاحية قراءة البيانات المعرَّفة داخل نفس الوحدة، لكن هذه الخاصية ستقلل من مرونة الدالة التي نعرِّفها. نريد أن نقلل عدد المعامِلات المطلوبة لتشغيل الدالة إلى حد يمكن السيطرة عليه وإدارته، وهذا يراعى في حالة البيانات الكثيرة التي تحتاج إلى معامِلات أكثر، وذلك من خلال استخدام تجميعات البيانات مثل القوائم وصفوف tuples والقواميس وغيرها، كما نستطيع تقليل عدد قيم المعامِلات الفعلية التي يجب أن نوفرها، باستخدام ما يسمى بالوسيط الافتراضي.
</p>

<h3>
	الوسيط الافتراضي
</h3>

<p>
	يشير هذا المصطلح إلى طريقة لتعريف معامِلات الدالة التي تأخذ قيمًا افتراضيةً إذا لم تمرَّر كوسطاء صراحةً، وأحد استخدامات هذا الوسيط المنطقية في دالة تعيد يوم الأسبوع، فإذا استدعيناها بدون قيمة فيكون قصدنا اليوم الحالي، وإلا فإننا نوفر رقم اليوم كوسيط، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_62" style=""><span class="kwd">import</span><span class="pln"> time

</span><span class="pun">#</span><span class="pln"> </span><span class="typ">None</span><span class="pln"> </span><span class="pun">قيمة</span><span class="pln"> </span><span class="pun">اليوم</span><span class="pln"> </span><span class="pun">هي</span><span class="pln">  
def dayOfWeek</span><span class="pun">(</span><span class="typ">DayNum</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">None</span><span class="pun">):</span><span class="pln">
    </span><span class="pun">#</span><span class="pln"> </span><span class="pun">طابق</span><span class="pln"> </span><span class="pun">ترتيب</span><span class="pln"> </span><span class="pun">اليوم</span><span class="pln"> </span><span class="pun">مع</span><span class="pln"> </span><span class="pun">قيم</span><span class="pln"> </span><span class="pun">إعادة</span><span class="pln"> </span><span class="pun">بايثون</span><span class="pln">
    days </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Saturday'</span><span class="pun">,</span><span class="str">'Sunday'</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'Monday'</span><span class="pun">,</span><span class="str">'Tuesday'</span><span class="pun">,</span><span class="pln"> 
            </span><span class="str">'Wednesday'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Thursday'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Friday'</span><span class="pun">]</span><span class="pln">

    </span><span class="pun">#</span><span class="pln"> </span><span class="pun">تحقق</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">القيمة</span><span class="pln"> </span><span class="pun">الافتراضية</span><span class="pln">        
    </span><span class="kwd">if</span><span class="pln"> </span><span class="typ">DayNum</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="typ">None</span><span class="pun">:</span><span class="pln">
        theTime </span><span class="pun">=</span><span class="pln"> time</span><span class="pun">.</span><span class="pln">localtime</span><span class="pun">(</span><span class="pln">time</span><span class="pun">.</span><span class="pln">time</span><span class="pun">())</span><span class="pln">
        </span><span class="typ">DayNum</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> theTime</span><span class="pun">[</span><span class="lit">6</span><span class="pun">]</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">استخرج</span><span class="pln"> </span><span class="pun">قيمة</span><span class="pln"> </span><span class="pun">اليوم</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> days</span><span class="pun">[</span><span class="typ">DayNum</span><span class="pun">]</span></pre>

<p>
	لا نحتاج إلى استخدام وحدة الوقت إلا إذا كانت قيمة المعامِل الافتراضي مطلوبةً، وبناءً عليه نستطيع تأجيل عملية الاستيراد إلى أن نحتاج إليها، وسيحسن هذا من الأداء تحسينًا طفيفًا إذا لم نضطر إلى استخدام خاصية القيمة الافتراضية للدالة، لكن هذا التحسن يُعَد طفيفًا كما ذكرنا، ويلغي اصطلاح الاستيراد الذي ذكرناه أعلاه، لذا لا يستحق هذا التشوش.
</p>

<p>
	نستطيع الآن أن نستدعي ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_64" style=""><span class="pln">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Today is: %s"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> dayOfWeek</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="typ">Saturday</span><span class="pun">.</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"The third day is %s"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> dayOfWeek</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	تذكر أننا نبدأ العد من الصفر في عالم الحواسيب، وأننا افترضنا أن اليوم الأول في الأسبوع هو السبت.
</p>

<h3>
	عد الكلمات
</h3>

<p>
	أحد الأمثلة الأخرى على دالة تعيد قيمةً، هو الدالة التي تَعُد الكلمات في سلسلة نصية، ويمكن استخدامها لحساب الكلمات في ملف ما بجمع كلمات كل سطر، وتكون شيفرة هذه الدالة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_66" style=""><span class="pln">def numwords</span><span class="pun">(</span><span class="pln">s</span><span class="pun">):</span><span class="pln">
    s </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">()</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">أزل</span><span class="pln"> </span><span class="pun">المحارف</span><span class="pln"> </span><span class="pun">الزائدة</span><span class="pln">
    list </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">split</span><span class="pun">()</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">قائمة</span><span class="pln"> </span><span class="pun">كل</span><span class="pln"> </span><span class="pun">عنصر</span><span class="pln"> </span><span class="pun">فيها</span><span class="pln"> </span><span class="pun">يمثل</span><span class="pln"> </span><span class="pun">كلمة</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">list</span><span class="pun">)</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">كلمات</span><span class="pln"> </span><span class="pun">القائمة</span><span class="pln"> </span><span class="pun">هو</span><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">كلمات</span><span class="pln"> s</span></pre>

<p>
	لقد عرَّفنا الدالة في المثال أعلاه مستفيدين من بعض توابع السلاسل النصية المضمَّنة التي ذكرناها في مقال البيانات وأنواعها، ويمكن استخدام الدالة الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_68" style=""><span class="kwd">for</span><span class="pln"> line in file</span><span class="pun">:</span><span class="pln">
    total </span><span class="pun">=</span><span class="pln"> total </span><span class="pun">+</span><span class="pln"> numwords</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">راكم</span><span class="pln"> </span><span class="pun">مجموع</span><span class="pln"> </span><span class="pun">كل</span><span class="pln"> </span><span class="pun">سطر</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"File had %d words"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> total </span><span class="pun">)</span></pre>

<p>
	إذا حاولنا كتابة ذلك فلن تنجح الشيفرة، لأن مثل هذه الشيفرة تُعرف باسم الشيفرة الوهمية pseudocode، وهي تقنية تصميم شائعة للشيفرات لتوضيح الفكرة العامة لها، وليست مثالًا لشيفرة حقيقية صحيحة التركيب، وتُعرف أحيانًا باسم لغة وصف البرامج Program Description Language.
</p>

<p>
	يتضح لنا سبب أفضلية إعادة قيمة من دالة وطباعة النتيجة خارج الدالة بدلًا من داخلها، فإذا طبعت الدالة الطول بدلًا من إعادته فلم نكن لنستخدمها في عدّ إجمالي الكلمات في الملف، بل كنا سنحصل على قائمة طويلة فيها طول كل سطر، لكننا بإعادة القيمة نستطيع الاختيار بين استخدام القيمة كما هي، أو تخزينها في متغير بهدف المعالجة اللاحقة كما فعلنا هنا من أجل أخذ العدد الإجمالي، وهذه نقطة في غاية الأهمية من ناحية التصميم لفصل عرض البيانات من خلال الطباعة عن معالجها داخل الدالة.
</p>

<p>
	هناك ميزة أخرى وهي أننا إذا طبعنا الخرج فلن يكون مفيدًا إلا في بيئة سطر أوامر، أما بإعادة القيمة فنستطيع عرضها في صفحة ويب أو واجهة رسومية، فلفصل عرض البيانات عن معالجتها فائدة كبيرة، لذا اجتهد في إعادة القيم من الدوال بدلًا من طباعتها ما استطعت، وليس ثمة استثناء لهذه القاعدة إلا عند إنشاء دالة مخصصة لطباعة بعض البيانات، ففي تلك الحالة يجب توضيح هذا باستخدام كلمة print أو عرض اسم الدالة.
</p>

<h3>
	دوال جافاسكربت
</h3>

<p>
	يمكن إنشاء دوال داخل جافاسكربت باستخدام أمر <code>function</code>، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_71" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> values</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> times</span><span class="pun">(</span><span class="pln">m</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln"> results </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        results</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">*</span><span class="pln"> m</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> results</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// استخدم الدالة</span><span class="pln">
values </span><span class="pun">=</span><span class="pln"> times</span><span class="pun">(</span><span class="lit">8</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;=</span><span class="lit">12</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">values</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">"&lt;br /&gt;"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لن نستطيع الاستفادة كثيرًا من هذه الدالة بتلك الحالة، لكن هذا المثال يوضح كيف يشبه الهيكل الأساسي لإنشاء الدالة هنا تعريفات الدوال في بايثون وVBSCript، وسننظر في دوال أكثر تعقيدًا في جافاسكربت لاحقًا، لأنها تستخدم الدوال لتعريف الكائنات والدوال أيضًا، وهو الأمر الذي يبدو مربكًا للقارئ أو لمستخدم اللغة.
</p>

<h3>
	تنبيه
</h3>

<p>
	تنبع قوة الدوال من سماحها بتوسيع نطاق الوظائف والمهام التي تستطيع اللغة تنفيذها، كما أنها تتيح لنا إمكانية تغيير اللغة من خلال تعريف معنىً جديد لدالة موجودة مسبقًا -لا يُسمح بهذا في بعض اللغات-، ولكن هذا أمر غير محمود العاقبة، إلا إذا تحكمنا فيه بحذر شديد، لأن تغيير السلوك القياسي للغة يجعل قراءة الشيفرة وفهمها يُعَد صعبًا للغاية على غيرك، بل عليك أنت نفسك فيما بعد، وبما أن القارئ يتوقع من الدالة أن تنفذ سلوكًا معينًا لكنك غيرت هذا السلوك إلى شيء آخر، لذا يفضل عدم تغيير السلوك الافتراضي للدوال المضمّنة في اللغة. يمكن التغلب على هذا التقييد للإبقاء على السلوك المضمّن للغة مع الاستمرار في استخدام أسماء ذات معنىً لدوالنا، من خلال وضع الدوال داخل كائن أو وحدة توفر سياقها المحلي.
</p>

<h2>
	إنشاء الوحدات الخاصة
</h2>

<p>
	رأينا كيف ننشئ دوالًا خاصةً بنا وكيف نستدعيها من أجزاء أخرى من البرنامج، وهذا أمر جيد لأنه يوفر علينا كثيرًا من الكتابة المتكررة، ويجعل برامجنا سهلة الفهم، لأننا ننسى بعض التفاصيل بعد إنشاء دالة تخفيها، وهو مبدأ متبع في البرمجة عند الحاجة إلى إخفاء بعض التفاصيل، ويسمى إخفاء المعلومات، حيث تغلَّف المعلومات والتفاصيل في دالة ننشئها لها، لكن كيف نستخدم هذه الدوال في البرامج الأخرى؟ الإجابة على هذا هي إنشاء وحدة module لهذا الغرض.
</p>

<h3>
	وحدات بايثون
</h3>

<p>
	الوحدة في بايثون ما هي إلا ملف نصي بسيط فيه تعليمات برمجية مكتوبة بلغة بايثون، وتكون تلك التعليمات عادةً تعريفات دوال، فمثلًا عند كتابة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1066_78" style=""><span class="kwd">import</span><span class="pln"> sys</span></pre>

<p>
	فإننا نخبر مفسر بايثون أن يقرأ هذه الوحدة وينفذ الشيفرة الموجودة فيها، ويتيح لنا الأسماء التي تولدها في ملفنا، ويبدو هذا كأننا ننشئ نسخةً من محتويات <code>sys.py</code> في برنامجنا، على أن بعض الوحدات مثل <code>sys</code> في البرمجة العملية ليس لها ملف <code>sys.py</code> أصلًا، لكننا سنتجاهل هذا الآن، وتوجد لغات برمجة مثل <code>C</code> و<code>++C</code>، التي ينسخ فيها المترجم أو المصرِّف ملفات الوحدة إلى البرنامج الحالي حسب الطلب.
</p>

<p>
	ننشئ الوحدة بإنشاء ملف بايثون يحتوي الدوال التي نريد إعادة استخدامها في برامج أخرى، ثم نستورد الوحدة كما نستورد الوحدات القياسية، ولتنفيذ هذا عمليًا، انسخ الدالة التالية إلى ملف، واحفظه باسم <code>timestab.py</code>. يمكنك فعل هذا باستخدام IDLE أو Notepad، أو أي محرر آخر يحفظ الملفات النصية العادية، لكن لا تستخدم برامج معالجة نصوص مثل مايكروسوفت وورد، لأن تلك البرامج تدخل شيفرات تنسيق كثيرةً لن تفهمها بايثون.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1066_81" style=""><span class="kwd">def</span><span class="pln"> print_table</span><span class="pun">(</span><span class="pln">multiplier</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"--- Printing the %d times table ---"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> multiplier </span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> n </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">13</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%d x %d = %d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n</span><span class="pun">,</span><span class="pln"> multiplier</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">*</span><span class="pln">multiplier</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	ثم اكتب في محث بايثون:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1066_83" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> timestab
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> timestab</span><span class="pun">.</span><span class="pln">print_table</span><span class="pun">(</span><span class="lit">12</span><span class="pun">)</span></pre>

<p>
	وهكذا تكون قد أنشأت وحدةً واستوردتها واستخدمت الدالة المعرَّفة فيها.
</p>

<p>
	لاحظ أنك إن لم تبدأ بايثون من نفس المجلد الذي خزنت فيه ملف <code>timestab.py</code>، فلن تستطيع بايثون أن تجد الملف وستعطيك خطأً، وعندها يمكن إنشاء متغير بيئة اسمه PYTHONPATH يحمل قائمةً من المجلدات الصالحة للبحث فيها عن وحدات، إضافةً إلى الوحدات القياسية التي تأتي مع بايثون، ويفضل تعريف مجلد داخل PYTHONPATH وتخزين جميع ملفات الوحدات القابلة لإعادة الاستخدام داخله، ولا تنسى اختبار الوحدات جيدًا قبل نقلها إليه.
</p>

<p>
	يجب التأكد من عدم استخدام اسم تحمله وحدة قياسية في بايثون، لئلا تجعل بايثون تستورد ملفك أنت بدلًا من القياسي، مما سينتج عنه سلوك غريب جدًا كما ذكرنا من قبل في شأن التلاعب في لغة البرمجة. ولا تستخدم اسم إحدى الوحدات التي تحاول استيرادها إلى نفس الملف، فهذا سيؤدي أيضًا إلى حدوث مشاكل.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		تختلف عملية إنشاء متغيرات البيئة من منصة لأخرى، وهذا أمر يُفترض أن يعلمه القارئ أو على الأقل يعرف كيف يبحث عن كيفية تنفيذه، حيث يستطيع مستخدمو ويندوز مثلًا أن يبحثوا عن متغيرات البيئة Environment Variables في قائمة ابدأ، ثم المساعدة والدعم، ويتعلموا بأنفسهم كيفية إنشائها.
	</p>
</blockquote>

<h3>
	الوحدات في جافاسكربت وVBScript
</h3>

<p>
	يُعَد إنشاء الوحدات في VBScript أكثر تعقيدًا من بايثون، فلم يكن مفهوم الوحدات موجودًا في هذه اللغة ولا في اللغات التي بنفس عمرها، بل كانت تعتمد على إنشاء الكائنات لإعادة استخدام الشيفرة بين المشاريع، وسننظر الآن في كيفية النسخ من المشاريع السابقة واللصق في مشروعنا الحالي باستخدام المحرر النصي.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		لاحظ أن لغة Visual Basic -وهي الأخت الكبرى للغة VBScript-، فيها ذلك المفهوم الخاص بالوحدات، ويمكن تحميل وحدة من خلال بيئة تطوير متكاملة IDE من قائمة File، ثم خيار Open Module، وهناك بعض القيود لما يمكن فعله داخل وحدة Visual Basic، لكننا لن نتعرض لها بما أنها خارج نطاق حديثنا. توفر مايكروسوفت نسخةً مجانيةً من أحدث إصدار للغة VB Express، لكن يجب أن تسجل لديهم قبل أن تستخدمها. انظر في <a href="http://www.microsoft.com/express/download/" rel="external nofollow">صفحتها</a> إذا أردت التجربة بنفسك.
	</p>
</blockquote>

<p>
	أما جافاسكربت فتوفر آليةً لإنشاء وحدات من ملفات الشيفرة القابلة لإعادة الاستخدام، لكنها آلية معقدة وتستخدم صيغةً غامضةً تخرج عن نطاق عملنا في هذه المرحلة، غير أن لدينا حلًا أسهل، وهو استخدام وحدات كتبها أشخاص آخرون، باستخدام الصيغة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_85" style=""><span class="pln">  </span><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="pln">text</span><span class="pun">/</span><span class="typ">JavaScript</span><span class="pln"> src</span><span class="pun">=</span><span class="str">"mymodule.js"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	نستطيع الوصول إلى جميع تعريفات الدوال الموجودة في ملف <code>mymodule.js</code> بمجرد إدراج السطر السابق داخل قسم <code>&lt;head&gt;</code> في صفحة الويب الخاصة بنا، وتوجد وحدات عديدة من الطرف الثالث متاحة لمبرمجي الويب ويمكن استيرادها بهذه الطريقة، ولعل أشهرها هي وحدة <a href="http://www.jquery.org/" rel="external nofollow">JQuery</a>؛ أما في المواضع التي تُستخدم فيها جافاسكربت خارج المتصفحات -انظر قسم Windows Script Host اللاحق- فهناك آليات أخرى متاحة، ويُرجع في ذلك إلى التوثيق.
</p>

<h3>
	تقنية Windows Script Host
</h3>

<p>
	نظرنا حتى الآن إلى جافاسكربت وVBScript على أنهما لغات للبرمجة داخل الويب، ولكن توجد طريقة أخرى لاستخدامهما داخل بيئة ويندوز، وهو تقنية مضيف سكربت ويندوز Windows Script Host أو WSH اختصارًا، وهي تقنية أتاحتها مايكروسوفت لتمكين المستخدمين من برمجة حواسيبهم بنفس الطريقة التي استخدم بها مستخدمو نظام DOS قديمًا ملفات باتش Batch Files، فهي توفر آليات لقراءة الملفات والسجل والوصول إلى الحواسيب والطابعات التي في الشبكة وغيرها.
</p>

<p>
	في الإصدار الثاني من WSH إمكانية تضمين ملف WSH آخر، ومن ثم توفير وحدات قابلة لإعادة الاستخدام، وذلك بإنشاء ملف وحدة أولًا اسمه <code>SomeModule.vbs</code> يحتوي على ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_87" style=""><span class="typ">Function</span><span class="pln"> </span><span class="typ">SubtractTwo</span><span class="pun">(</span><span class="pln">N</span><span class="pun">)</span><span class="pln">
   </span><span class="typ">SubtractTwo</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> N </span><span class="pun">-</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="kwd">function</span></pre>

<p>
	ننشئ الآن ملف سكربت WSH اسمه <code>testModule.wsf</code> مثلًا، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_89" style=""><span class="pun">&lt;?</span><span class="pln">xml version</span><span class="pun">=</span><span class="str">"1.0"</span><span class="pln"> encoding</span><span class="pun">=</span><span class="str">"UTF-8"</span><span class="pun">?&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">job</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pln"> src</span><span class="pun">=</span><span class="str">"SomeModule.vbs"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="typ">Dim</span><span class="pln"> value</span><span class="pun">,</span><span class="pln"> result
      </span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">Echo</span><span class="pln"> </span><span class="str">"Type a number"</span><span class="pln">
      value </span><span class="pun">=</span><span class="pln"> </span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">StdIn</span><span class="pun">.</span><span class="typ">ReadLine</span><span class="pln">
      result </span><span class="pun">=</span><span class="pln"> </span><span class="typ">SubtractTwo</span><span class="pun">(</span><span class="typ">CInt</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span><span class="pln">

      </span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">Echo</span><span class="pln"> </span><span class="str">"The result was "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">CStr</span><span class="pun">(</span><span class="pln">result</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">job</span><span class="pun">&gt;</span></pre>

<p>
	يمكن تشغيل هذا في ويندوز ببدء جلسة DOS وكتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_91" style=""><span class="pln">C</span><span class="pun">:</span><span class="pln">\&gt; cscript testModule</span><span class="pun">.</span><span class="pln">wsf</span></pre>

<p>
	تسمى الطريقة التي تمت هيكلة ملف (wsf.) بها باسم XML، ويتواجد البرنامج داخل زوج من وسوم <code>&lt;job&gt;&lt;/job&gt;</code> بدلًا من وسم <code>&lt;html&gt;&lt;/html&gt;</code> الذي رأيناه في لغة HTML من قبل.
</p>

<p>
	يشير أول وسم سكربت في الداخل إلى ملف وحدة اسمه <code>SomeModule.vbs</code>، أما وسم السكربت الثاني فيحتوي على برنامجنا الذي يصل إلى <code>SubtractTwo</code> داخل ملف <code>SomeModule.vbs</code>؛ بينما ملف <code>‎.vbs</code> فيحتوي على شيفرة VBScript عادية ليس فيها وسوم XML أو HTML.
</p>

<p>
	لاحظ أن علينا تهريب محرف <code>&amp;</code> من أجل ضم السلاسل النصية لتعليمة <code>WScript.Echo</code>، لأن التعليمة جزء من ملف XML، وهذا المحرف مستخدم في لغة XML كرمز محدِّد.
</p>

<p>
	نستخدم <code>WScript.Stdin</code> لقراءة مدخلات المستخدم، وهو تطبيق لما تحدثنا عنه في مقال <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-r1311/" rel="">قراءة البيانات من المستخدم</a>.
</p>

<p>
	تصلح هذه التقنية مع جافاسكربت أيضًا، أو لنكون أدق، مع نسخة مايكروسوفت من جافاسكربت التي تسمى JScript، وذلك بتغيير سمة <code>type=‎</code>، بل يمكن دمج اللغات في WSH بأن نستورد وحدةً مكتوبةً بجافاسكربت ونستخدمها في شيفرة VBScript أو العكس.
</p>

<p>
	فيما يلي سكربت WSH مكافئ لما سبق، حيث تُستخدم جافاسكربت للوصول إلى وحدة من VBScript:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1066_93" style=""><span class="pun">&lt;?</span><span class="pln">xml version</span><span class="pun">=</span><span class="str">"1.0"</span><span class="pln"> encoding</span><span class="pun">=</span><span class="str">"UTF-8"</span><span class="pun">?&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">job</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pln"> src</span><span class="pun">=</span><span class="str">"SomeModule.vbs"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="kwd">var</span><span class="pln"> value</span><span class="pun">,</span><span class="pln"> result</span><span class="pun">;</span><span class="pln">
      </span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">Echo</span><span class="pun">(</span><span class="str">"Type a number"</span><span class="pun">);</span><span class="pln">
      value </span><span class="pun">=</span><span class="pln"> </span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">StdIn</span><span class="pun">.</span><span class="typ">ReadLine</span><span class="pun">();</span><span class="pln">
      result </span><span class="pun">=</span><span class="pln"> </span><span class="typ">SubtractTwo</span><span class="pun">(</span><span class="pln">parseInt</span><span class="pun">(</span><span class="pln">value</span><span class="pun">));</span><span class="pln">

      </span><span class="typ">WScript</span><span class="pun">.</span><span class="typ">Echo</span><span class="pun">(</span><span class="str">"The result was "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> result</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">job</span><span class="pun">&gt;</span></pre>

<p>
	نستطيع رؤية مدى تقارب هاتين النسختين، فإذا استثنينا بعض الأقواس الزائدة فسيمكننا القول أنهما متشابهتان للغاية؛ أما أغلب الأمور الفنية فتجري من خلال كائنات WScript.
</p>

<p>
	لن نستخدم WSH كثيرًا، لكن قد ننظر فيها بين الحين والآخر إذا رأينا أنها توفر لنا مزايا لا يمكن شرحها باستخدام بيئة المتصفح الأكثر تقييدًا، فعلى سبيل المثال، سنستخدم WSH في المقال التالي لبيان كيف يمكن تعديل الملفات باستخدام جافاسكربت وVBScript، وتوجد بعض الكتب التي تتحدث عن WSH إذا كنت مهتمًا بتعلم المزيد عنها، ويحتوي موقع مايكروسوفت على <a href="https://msdn.microsoft.com/en-us/library/ec0wcxh3(v=vs.84).aspx" rel="external nofollow">قسم خاص بها</a> مع أمثلة لبرامج وأدوات تطوير وغير ذلك.
</p>

<h2>
	خاتمة
</h2>

<p>
	نأمل أن تخرج من هذا المقال وقد تعلمت:
</p>

<ul>
	<li>
		الدوال التي هي شكل من أشكال الوحدات.
	</li>
	<li>
		تعيد الدوال قيمًا، أما الإجراءات فلا تعيد شيئًا.
	</li>
	<li>
		تتكون الوحدات في بايثون في العادة من تعريفات للدوال داخل ملف.
	</li>
	<li>
		يمكن إنشاء دوال جديدة في بايثون باستخدام الكلمة المفتاحية <code>def</code>.
	</li>
	<li>
		استخدام <code>Sub</code> أو<code>Function</code> في VBScript، و<code>function</code> في جافاسكربت.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutfunc.htm/" rel="external nofollow">للفصل الحادي عشر: Programming with Modules من كتاب Learning To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1334/" rel="">التعامل مع الملفات في البرمجة</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/" rel="">مقدمة في البرمجة الشرطية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">المدخل الشامل لتعلم علوم الحاسوب</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1333</guid><pubDate>Fri, 01 Oct 2021 15:08:00 +0000</pubDate></item><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x641;&#x64A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x627;&#x644;&#x634;&#x631;&#x637;&#x64A;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_09/6155d83a34690_---.png.a66717473595233e0b90a742e0e34111.png" /></p>
<p>
	تصف التعليمات الشرطية في البرمجة قدرتنا على تنفيذ تسلسل واحد من بين عدة تسلسلات محتملة من الشيفرات -التي تمثل الفروع- وفقًا لوقوع حدث ما، وقد كانت أبسط صورة لتلك التعليمات الشرطية في الأيام الأولى لاستخدام لغة التجميع Assembly هي تعليمة <code>JUMP</code> التي تجعل البرنامج يقفز إلى عنوان ما في الذاكرة، غالبًا عندما يكون ناتج التعليمة السابقة صفرًا، وقد استُخدمت هذه التعليمة في برامج بالغة التعقيد، دون استخدام أي صورة شرطية أخرى وقتها، ليؤكد هذا قول ديكسترا Dijkstra عن الحد الأدنى المطلوب للبرمجة، ثم ظهرت نسخة جديدة من تعليمة <code>JUMP</code> مع تطور <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a> عالية المستوى، وهي <code>GOTO</code>، التي لا تزال متاحةً حتى الآن في لغة QBASIC، والتي يمكن تحميلها واستخدامها من www.qbasic.net، لننظر إلى الشيفرة التالية مثلًا -بعد تثبيت QBASIC-:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_7" style=""><span class="lit">10</span><span class="pln"> PRINT </span><span class="str">"Starting at line 10"</span><span class="pln">
</span><span class="lit">20</span><span class="pln"> J </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="lit">30</span><span class="pln"> IF J </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> GOTO </span><span class="lit">50</span><span class="pln">
</span><span class="lit">40</span><span class="pln"> PRINT </span><span class="str">"This line is not printed"</span><span class="pln">
</span><span class="lit">50</span><span class="pln"> STOP</span></pre>

<p>
	لاحظ كيف تحتاج إلى بضع ثوان لتعرف الخطوة التالية رغم صغر البرنامج، إذ لا يوجد هيكل للشيفرة، بل عليك أن تكتشف ما يفعله البرنامج بينما تقرؤه بنفسك، وهذا الأمر مستحيل في البرامج كبيرة الحجم، لهذا لا تحتوي أغلب لغات البرمجة الحديثة بما فيها لغة بايثون وجافاسكربت وVBScript، على تعليمة JUMP أو GOTO بحيث يمكن استخدام أي منهما مباشرةً، وإن وجدت فستحثك اللغة على عدم استخدامها، فما العمل إذًا في حالة البرمجة الشرطية؟.
</p>

<h2>
	تعليمة if الشرطية
</h2>

<p>
	إن أول ما يرد إلى الذهن عند التفكير في حالات شرطية هي البنية <code>if.. then.. else</code>، والتي تعني "إذا حدث س، فسيكون ص، وإلا سيكون ع"، فهي تتبع منطقًا لغويًا بحيث إذا تحقق شرط بولياني ما -أي كان true-، فستُنفَّذ كتلة من التعليمات، وإلا ستنفَّذ كتلة أخرى.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير التطبيقات باستخدام لغة Python
		</p>

		<p class="banner-subtitle">
			احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/python-application-development" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<img alt="دورة تطوير التطبيقات باستخدام لغة Python" src="https://academy.hsoub.com/learn/assets/images/courses/python-application-development.png">
	</div>
</div>

<h3>
	بايثون
</h3>

<p>
	إذا أردنا كتابة مثال GOTO السابق بلغة بايثون، فسيبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_16" style=""><span class="kwd">import</span><span class="pln"> sys  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">فقط</span><span class="pln"> exit </span><span class="pun">لنستطيع</span><span class="pln"> </span><span class="pun">استخدام</span><span class="pln"> 
print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Starting here"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> j </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">:</span><span class="pln">
    print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"This is never printed"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
    sys</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">()</span></pre>

<p>
	هذه الصورة أسهل من سابقتها في القراءة وفهم المراد منها، ونستطيع وضع أي شرط اختباري نريده بعد تعليمة <code>if</code>، طالما أنه يقيَّم إلى <code>True</code> أو <code>False</code>، جرب تغيير علامتي <code>‎&gt;‎</code> و <code>‎&lt;‎</code> وانظر ما سيحدث.
</p>

<p>
	لاحظ النقطتين الرأسيتين <code>:</code> في نهاية سطري التعليمتين <code>if</code> و<code>else</code>، إذ تخبرنا هاتان النقطتان أن ما يليهما كتلة مستقلة من الشيفرة، بينما تخبرنا إزاحة تلك الكتلة ببدايتها ونهايتها.
</p>

<h3>
	VBScript
</h3>

<p>
	سيبدو المثال السابق في VBScript كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_19" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"Starting Here"</span><span class="pln">
DIM J
J </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="typ">If</span><span class="pln"> J </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="typ">Then</span><span class="pln">
    </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"This is never printed"</span><span class="pln">
</span><span class="typ">Else</span><span class="pln">
    </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"End of Program"</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">If</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	يكاد يكون هذا المثال مطابقًا لمثال بايثون، مع فرق أن كلمة <code>Then</code> مطلوبة للكتلة الأولى، وأننا نستخدم <code>End If</code> لنعلن نهاية بنية if/then، ولعلك تذكر أننا استخدمنا كلمة <code>Loop</code> لإنهاء حلقة <code>Do While</code> في مثال VBScript من مقال سابق، ذلك أن VBScript تستخدم في اصطلاحها محددًا لنهاية التعليمة.
</p>

<h3>
	جافاسكربت
</h3>

<p>
	يبدو مثال <code>if</code> في جافاسكربت كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_21" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> j</span><span class="pun">;</span><span class="pln">
j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> j </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">){</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"This is never printed"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"End of program"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لاحظ أن جافاسكربت تستخدم أقواسًا معقوصةً لتحديد كتل الشيفرات الموجودة داخل الجزء الخاص بتعليمة <code>if</code> والجزء الخاص بتعليمة <code>else</code>، وأن الاختبار البولياني يوجد بين قوسين، وليس هناك استخدام صريح لكلمة <code>then</code>.
</p>

<p>
	من المنظور الجمالي للتنسيق، يمكن وضع الأقواس المعقوصة في أي مكان، لكننا اخترنا صفها كما في المثال لإبراز بنية الكتلة البرمجية، ويمكن إهمال الأقواس المعقوصة كليًا إذا كان لدينا سطر واحد فقط داخل الكتلة كما في حالتنا هذه، لكن يفضل بعض المبرمجين وضعها للحفاظ على اتساق الكتابة، ولاحتمال إضافة سطر آخر مستقبلًا، فوضعها الآن أفضل من نسيانها لاحقًا.
</p>

<h2>
	التعابير البوليانية
</h2>

<p>
	لعلك تذكر أننا ذكرنا في مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A7%D9%84%D8%AA%D8%AC%D9%85%D9%8A%D8%B9%D8%A7%D8%AA-collections-r1288/" rel="">البيانات وأنواعها</a>، نوعًا من البيانات اسمه النوع البولياني، وقلنا إن هذا النوع لا يحوي إلا قيمتين فقط، هما <code>True</code> و<code>False</code>، ورغم أننا لا ننشئ متغيرًا بوليانيًا إلا نادرًا، إلا أننا نحتاج إلى إنشاء قيم بوليانية مؤقتة باستخدام التعابير، والتعبير هو تجميعة من المتغيرات و/أو القيم، تجمعها معًا عوامل لإخراج قيمة ناتجة، لننظر إلى المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2535_23" style=""><span class="pln">if x &lt; 5:
  print( x )</span></pre>

<p>
	التعبير هنا هو <code>x &lt; 5</code>، والنتيجة ستكون <code>True</code> إذا كانت x أقل من 5، و<code>False</code> إذا كانت x أكبر من (أو تساوي) 5.
</p>

<p>
	قد تكون التعابير معقدةً بما أنها تقيَّم إلى قيمة نهائية وحيدة، إذ يجب أن تكون تلك القيمة <code>True</code> أو <code>False</code> في حالة الفرع، لكن يختلف تعريف هاتين القيمتين من لغة لأخرى، فأغلب اللغات تساوي بين القيمة <code>False</code> وبين الصفر أو القيمة غير الموجودة أو غير المعرفة والتي تدعى <code>NULL</code> أو <code>Nil</code> أو <code>None</code>، وبناءً على ذلك تقيَّم القائمة الفارغة أو السلسلة النصية الفارغة إلى false في السياق البولياني وتعتمد بايثون هذا السلوك، مما يعني أننا نستطيع استخدام حلقة <code>while</code> لمعالجة القائمة إلى أن تصبح فارغةً، بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_25" style=""><span class="kwd">while</span><span class="pln"> aList</span><span class="pun">:</span><span class="pln">
   </span><span class="pun">#</span><span class="pln"> </span><span class="pun">افعل</span><span class="pln"> </span><span class="pun">شيئًا</span><span class="pln"> </span><span class="pun">هنا</span></pre>

<p>
	أو يمكن استخدام تعليمة <code>if</code> لننظر هل القائمة فارغة أم لا، دون اللجوء إلى دالة <code>len()‎</code> كما يلي:
</p>

<pre class="ipsCode">if aList:
   # افعل شيئًا هنا
</pre>

<p>
	يمكن جمع عدة تعابير بوليانية باستخدام عوامل بوليانية كذلك، والتي تقلل من عدد تعليمات <code>if</code> التي علينا كتابتها، كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_27" style=""><span class="kwd">if</span><span class="pln"> value </span><span class="pun">&gt;</span><span class="pln"> maximum</span><span class="pun">:</span><span class="pln">
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Value is out of range!"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> value </span><span class="pun">&lt;</span><span class="pln"> minimum</span><span class="pun">:</span><span class="pln">
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Value is out of range!"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ أن كتلة الشيفرة التي يجب تنفيذها متطابقة في شرطي المثال أعلاه، ويمكن أن نوفر على أنفسنا بعض الكتابة وعلى الحاسوب بعض العمل، بأن نجمع الاختبارين في اختبار واحد كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_29" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value </span><span class="pun">&lt;</span><span class="pln"> minimum</span><span class="pun">)</span><span class="pln"> or </span><span class="pun">(</span><span class="pln">value </span><span class="pun">&gt;</span><span class="pln"> maximum</span><span class="pun">):</span><span class="pln">
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Value is out of range!"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ كيف جمعنا الاختبارين باستخدام عامل <code>or</code> البولياني، وبما أن بايثون تقيِّم مجموعة الاختبارات المجمعة تلك إلى نتيجة واحدة؛ فنستطيع القول أن هذين التعبيرين إنما هما تعبير واحد، ونستطيع استيعاب هذا الأسلوب إذا عرفنا أننا نقيّم المجموعة الأولى من الأقواس أولًا، ثم نقيّم المجموعة الثانية، ثم نجمع القيمتين الناتجتين لنشكل قيمةً نهائيةً وحيدةً تكون إما True أو False. تستخدم بايثون أسلوبًا أكثر كفاءةً من هذا يُعرف بالتقييم المقصور أو تقييم الدارة المقصورة short-circuit evaluation، وإذا تأملنا في هذه الاختبارات، فسنجد أننا نفكر فيها بالمنطق اللغوي البشري الذي يستخدم حروف العطف مثل ("و" "and") و("أو" "or") و("النفي" "not")، مما يتيح لنا كتابة اختبار واحد مجمَّع بدلًا من عدة اختبارات منفصلة، كما سنرى فيما يلي.
</p>

<h2>
	تعليمات if المتسلسلة
</h2>

<p>
	يمكن سَلسَلة تعليمات "if..then..else" معًا بجعلها متشعبةً، بحيث تتداخل كل واحدة مع الأخرى، لننظر مثالًا على ذلك في بايثون:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_31" style=""><span class="pun">#</span><span class="pln"> </span><span class="pun">افترض</span><span class="pln"> </span><span class="pun">أن</span><span class="pln"> </span><span class="pun">السعر</span><span class="pln"> </span><span class="pun">قد</span><span class="pln"> </span><span class="pun">حُدد</span><span class="pln"> </span><span class="pun">مسبقًا...</span><span class="pln">
price </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"What price? "</span><span class="pun">))</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> price </span><span class="pun">==</span><span class="pln"> </span><span class="lit">100</span><span class="pun">:</span><span class="pln">
    print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"I'll take it!"</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> 
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> price </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">500</span><span class="pun">:</span><span class="pln">
        print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"No way!"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> price </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">200</span><span class="pun">:</span><span class="pln">
            print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"How about throwing in a free mouse mat?"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
            print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"price is an unexpected value!"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ أننا استخدمنا <code>==</code> المزدوجة لاختبار التساوي في تعليمة <code>if</code> الأولى، بينما استخدمنا علامة <code>=</code> مفردةً لإسناد القيم إلى المتغيرات، وهذا الخطأ شائع جدًا في الكتابة بلغة بايثون، لأنه يعارض المنطق الرياضي الذي تعودنا عليه، وبايثون تحذرك من أن هذا خطأ لغوي syntax error، وعليك النظر والبحث لإيجاده.
</p>

<p>
	ننفذ اختبار "أكبر من" بدءًا من القيمة العظمى إلى الصغرى، فإذا عكسنا هذا المنطق، أي بدأنا من <code>price &gt; 200</code> فستتحقق التعليمة دومًا ولن ننتقل إلى اختبار <code>‎&gt; 500</code>، وبالمثل يجب أن يبدأ استخدام تسلسل اختبارات "أقل من" من القيمة الصغرى ثم ننتقل إلى العظمى، وهذا أيضًا أحد الأخطاء الشائعة في البرمجة ببايثون.
</p>

<h3>
	جافاسكربت وVBScript
</h3>

<p>
	يمكن أن نسلسل تعليمات <code>if</code> في جافاسكربت وVBScript أيضًا، لكننا لن نشرح إلا VBScript لأن المثال واضح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_33" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
DIM </span><span class="typ">Price</span><span class="pln">
price </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"What's the price?"</span><span class="pun">)</span><span class="pln">
price </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CInt</span><span class="pun">(</span><span class="pln">price</span><span class="pun">)</span><span class="pln">
</span><span class="typ">If</span><span class="pln"> price </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="typ">Then</span><span class="pln">
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"I'll take it!"</span><span class="pln"> 
</span><span class="typ">Else</span><span class="pln">
    </span><span class="typ">If</span><span class="pln"> price </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">500</span><span class="pln"> </span><span class="typ">Then</span><span class="pln">
        </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"No way Jose!"</span><span class="pln">
    </span><span class="typ">Else</span><span class="pln">
        </span><span class="typ">If</span><span class="pln"> price </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">200</span><span class="pln"> </span><span class="typ">Then</span><span class="pln">
            </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"How about throwing in a free mouse mat too?"</span><span class="pln">
        </span><span class="typ">Else</span><span class="pln">
            </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"price is an unexpected value!"</span><span class="pln">
        </span><span class="typ">End</span><span class="pln"> </span><span class="typ">If</span><span class="pln">
    </span><span class="typ">End</span><span class="pln"> </span><span class="typ">If</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">If</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	يجب ملاحظة وجود تعليمة <code>End If</code> مطابقة لكل تعليمة <code>If</code>، واستخدامنا لدالة التحويل <code>CInt</code> الخاصة بلغة VBScript لتحويل الدخل من سلسلة نصية إلى عدد صحيح.
</p>

<h2>
	تعليمات الحالة Switch/Case
</h2>

<p>
	تتسبب إزاحة الشيفرات بملء الصفحة بسرعة، وهو أحد مساوئ سلسلة تعليمات <code>if/else</code> أو تشعبها، لكن شيوع هذا التسلسل المتشعب في البرمجة جعل كثيرًا من اللغات توفر نوعًا آخر من التفريع خاصًا بها، ويشار إليه عادةً باسم تعليمة <code>Case</code> أو <code>Switch</code>، التي تبدو في جافاسكربت كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_35" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> doArea</span><span class="pun">(){</span><span class="pln">
   </span><span class="kwd">var</span><span class="pln"> shape</span><span class="pun">,</span><span class="pln"> breadth</span><span class="pun">,</span><span class="pln"> length</span><span class="pun">,</span><span class="pln"> area</span><span class="pun">;</span><span class="pln">
   shape   </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">forms</span><span class="pun">[</span><span class="str">"area"</span><span class="pun">].</span><span class="pln">shape</span><span class="pun">.</span><span class="pln">value</span><span class="pun">;</span><span class="pln">
   breadth </span><span class="pun">=</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">forms</span><span class="pun">[</span><span class="str">"area"</span><span class="pun">].</span><span class="pln">breadth</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
   len     </span><span class="pun">=</span><span class="pln"> parseInt</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">forms</span><span class="pun">[</span><span class="str">"area"</span><span class="pun">].</span><span class="pln">len</span><span class="pun">.</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">shape</span><span class="pun">){</span><span class="pln">
       </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'Square'</span><span class="pun">:</span><span class="pln"> 
           area </span><span class="pun">=</span><span class="pln"> len </span><span class="pun">*</span><span class="pln"> len</span><span class="pun">;</span><span class="pln">
           alert</span><span class="pun">(</span><span class="str">"Area of "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> shape </span><span class="pun">+</span><span class="pln"> </span><span class="str">" = "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> area</span><span class="pun">);</span><span class="pln">
           </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'Rectangle'</span><span class="pun">:</span><span class="pln"> 
           area </span><span class="pun">=</span><span class="pln"> len </span><span class="pun">*</span><span class="pln"> breadth</span><span class="pun">;</span><span class="pln">
           alert</span><span class="pun">(</span><span class="str">"Area of "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> shape </span><span class="pun">+</span><span class="pln"> </span><span class="str">" = "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> area</span><span class="pun">);</span><span class="pln">
           </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'Triangle'</span><span class="pun">:</span><span class="pln">
           area </span><span class="pun">=</span><span class="pln"> len </span><span class="pun">*</span><span class="pln"> breadth </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
           alert</span><span class="pun">(</span><span class="str">"Area of "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> shape </span><span class="pun">+</span><span class="pln"> </span><span class="str">" = "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> area</span><span class="pun">);</span><span class="pln">
           </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">default</span><span class="pun">:</span><span class="pln"> alert</span><span class="pun">(</span><span class="str">"No shape matching: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> shape</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">form name</span><span class="pun">=</span><span class="str">"area"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;</span><span class="typ">Length</span><span class="pun">:</span><span class="pln">  </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"len"</span><span class="pun">&gt;&lt;/</span><span class="pln">label</span><span class="pun">&amp;</span><span class="pln">lgt</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;</span><span class="typ">Breadth</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"breadth"</span><span class="pun">&gt;&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;</span><span class="typ">Shape</span><span class="pun">:</span><span class="pln">   </span><span class="pun">&lt;</span><span class="pln">select name</span><span class="pun">=</span><span class="str">"shape"</span><span class="pln"> size</span><span class="pun">=</span><span class="lit">1</span><span class="pln"> onChange</span><span class="pun">=</span><span class="str">"doArea()"</span><span class="pun">&gt;</span><span class="pln">
           </span><span class="pun">&lt;</span><span class="pln">option value</span><span class="pun">=</span><span class="str">"Square"</span><span class="pun">&gt;</span><span class="typ">Square</span><span class="pln">
           </span><span class="pun">&lt;</span><span class="pln">option value</span><span class="pun">=</span><span class="str">"Rectangle"</span><span class="pun">&gt;</span><span class="typ">Rectangle</span><span class="pln">
           </span><span class="pun">&lt;</span><span class="pln">option value</span><span class="pun">=</span><span class="str">"Triangle"</span><span class="pun">&gt;</span><span class="typ">Triangle</span><span class="pln">
         </span><span class="pun">&lt;/</span><span class="pln">select</span><span class="pun">&gt;</span><span class="pln">
         </span><span class="pun">&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span></pre>

<p>
	لا تقلق من حجم الشيفرة أعلاه، فما هي إلا امتداد لما شرحناه في المقالات السابقة وإن زاد حجمه قليلًا.
</p>

<p>
	تحتوي استمارة HTML التي في آخر الشيفرة على حقلين نصيين لإدخال الطول length و العرض breadth، أما حقل الإدخال الثالث فهو قائمة منسدلة من القيم التي ألحقناها بسمة <code>onChange</code> التي تستدعي دالةً ما، وكل تلك الحقول لديها عناوين <code>labels</code> مرتبطة.
</p>

<p>
	تسمح شيفرة الاستمارة في HTML بالتقاط التفاصيل والبيانات، ثم تستدعي دالة جافاسكربت حين يختار المستخدم أحد الأشكال، وبما أننا لم نشرح الدوال بعد، فيكفي أن تعلم الآن أن الدالة هي برنامج صغير تستدعيه البرامج الأخرى، وفي حالتنا هذه عرَّفنا تلك الدالة في أول الشيفرة.
</p>

<p>
	تنشئ الأسطر الأولى بعض المتغيرات المحلية، وتحوِّل سلاسل الإدخال النصية إلى أعداد صحيحة عند الحاجة، وما نريده هو تعليمة <code>switch</code>، التي تختار الإجراء المناسب وفقًا لقيمة الشكل.
</p>

<p>
	لاحظ أن الأقواس التي حول <code>shape</code> ضرورية، ولا تُحدَّد كتل الشيفرة التي داخل بنية <code>case</code> باستخدام الأقواس المعقوصة كما هو متوقع، فإذا أردنا إنهاءها، فسنستخدم تعليمة <code>break</code>؛ أما مجموعة تعليمات <code>case</code> الخاصة بـ <code>switch</code> فهي مرتبطة معًا مثل كتلة واحدة بين قوسين معقوصين.
</p>

<p>
	يلتقط الشرط الأخير <code>default</code> أي شيء لم تلتقطه تعليمات <code>case</code> السابقة.
</p>

<p>
	جرب توسيع المثال السابق ليشمل الدوائر، وتذكر أن تضيف خيارًا جديدًا إلى القائمة المنسدلة في استمارة HTML وتعليمة <code>case</code> جديدة إلى <code>switch</code>.
</p>

<h3>
	بنية Case الاختيارية في VBScript
</h3>

<p>
	تحتوي لغة VBscript على بنية case كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_37" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> shape</span><span class="pun">,</span><span class="pln"> length</span><span class="pun">,</span><span class="pln"> breadth</span><span class="pun">,</span><span class="pln"> SQUARE</span><span class="pun">,</span><span class="pln"> RECTANGLE</span><span class="pun">,</span><span class="pln"> TRIANGLE
SQUARE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
RECTANGLE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
TRIANGLE </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
shape  </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CInt</span><span class="pun">(</span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Square(0),Rectangle(1) or Triangle(2)?"</span><span class="pun">))</span><span class="pln">
length </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CDbl</span><span class="pun">(</span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Length?"</span><span class="pun">))</span><span class="pln">
breadth  </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CDbl</span><span class="pun">(</span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Breadth?"</span><span class="pun">))</span><span class="pln">
</span><span class="typ">Select</span><span class="pln"> </span><span class="typ">Case</span><span class="pln"> shape 
 </span><span class="typ">Case</span><span class="pln"> SQUARE
   area </span><span class="pun">=</span><span class="pln"> length </span><span class="pun">*</span><span class="pln"> length
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"Area = "</span><span class="pln">  </span><span class="pun">&amp;</span><span class="pln"> area 
 </span><span class="typ">Case</span><span class="pln"> RECTANGLE
   area </span><span class="pun">=</span><span class="pln"> length </span><span class="pun">*</span><span class="pln"> breadth
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"Area = "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> area
 </span><span class="typ">Case</span><span class="pln"> TRIANGLE
   area </span><span class="pun">=</span><span class="pln"> length </span><span class="pun">*</span><span class="pln"> breadth </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"Area = "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> area
 </span><span class="typ">Case</span><span class="pln"> </span><span class="typ">Else</span><span class="pln"> 
   </span><span class="typ">MsgBox</span><span class="pln"> </span><span class="str">"Shape not recognized"</span><span class="pln">
</span><span class="typ">End</span><span class="pln"> </span><span class="typ">Select</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	تجمع الأسطر الأولى البيانات من المستخدم وتحولها إلى النوع المناسب، تمامًا مثلما يحدث في جافاسكربت، وتظهر تعليمة <code>select</code> بنية <code>case</code> الخاصة بلغة VBScript، حيث تنهي كل تعليمة <code>Case</code> الكتلة التي سبقتها، كذلك لدينا فقرة <code>Case Else</code> التي تلتقط أي شيء لم تلتقطه تعليمات <code>Case</code> التي سبقتها، كما في حالة <code>default</code> في جافاسكربت.
</p>

<p>
	وكما تعودنا في أسلوب VBScript في التنسيق، فإن الشيفرة تغلَق بتعليمة <code>End select</code>.
</p>

<p>
	ربما تجب الإشارة إلى استخدام الثوابت الرمزية بدلًا من الأعداد، أي استخدام المتغيرات <code>SQUARE</code> و<code>RECTANGLE</code> و<code>TRIANGLE</code>، لأنها تجعل الشيفرة أسهل في القراءة، كما أن استخدام الأحرف الكبيرة هو اصطلاح لبيان كونها قيمًا ثابتةً وليست متغيرات، مع أن VBScript تسمح بأي أسماء نريدها للمتغيرات.
</p>

<h3>
	الاختيار المتعدد في بايثون
</h3>

<p>
	لا توفر بايثون بنية <code>case</code> صراحةً، وإنما تعوضنا عن ذلك بتوفير صيغة مضغوطة من <code>if/else-if/else</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_39" style=""><span class="pln">menu </span><span class="pun">=</span><span class="pln"> </span><span class="str">"""</span><span class="pln">
</span><span class="typ">Pick</span><span class="pln"> a shape</span><span class="pun">(</span><span class="lit">1</span><span class="pun">-</span><span class="lit">3</span><span class="pun">):</span><span class="pln">
   </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Square</span><span class="pln">
   </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln">
   </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Triangle</span><span class="pln">
</span><span class="str">"""</span><span class="pln">
shape </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="pln">menu</span><span class="pun">))</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
   length </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Length: "</span><span class="pun">))</span><span class="pln">
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Area of square = "</span><span class="pun">,</span><span class="pln"> length </span><span class="pun">**</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
elif shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
   length </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Length: "</span><span class="pun">))</span><span class="pln">
   width </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Width: "</span><span class="pun">))</span><span class="pln">
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Area of rectangle = "</span><span class="pun">,</span><span class="pln"> length </span><span class="pun">*</span><span class="pln"> width </span><span class="pun">)</span><span class="pln">   
elif shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
   length </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Length: "</span><span class="pun">))</span><span class="pln">
   width </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Width: "</span><span class="pun">))</span><span class="pln">
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Area of triangle = "</span><span class="pun">,</span><span class="pln"> length </span><span class="pun">*</span><span class="pln"> width</span><span class="pun">/</span><span class="lit">2</span><span class="pln"> </span><span class="pun">)</span><span class="pln">   
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> 
   print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Not a valid shape, try again"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ استخدام <code>elif</code>، وعدم تغير الإزاحة على عكس مثال تعليمة <code>if</code> المتشعبة، وتجدر الإشارة إلى أنه لا فرق بين استخدام <code>if</code> المتشعبة أو <code>elif</code>، فكلاهما صالح، كما أنهما تؤديان نفس الغرض، غير أن <code>elif</code> أيسر في القراءة إذا كان لدينا عدة اختبارات.
</p>

<p>
	أما الشرط الأخير فهو <code>else</code> التي تلتقط أي شيء لم تلتقطه الاختبارات السابقة، كما في <code>default</code> في جافاسكربت و<code>Case Else</code> في VBScript.
</p>

<p>
	توفر VBScript نسخةً معقدةً من هذه التقنية هي <code>ElseIf...Then</code> التي تُستخدم بنفس طريقة <code>elif</code> في بايثون، لكنها غير شائعة بما أن <code>Select Case</code> أسهل استخدامًا.
</p>

<h2>
	إيقاف الحلقة التكرارية
</h2>

<p>
	يغطي هذا الجزء استخدامًا خاصًا للتفريع كنا نريد شرحه في مقال <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1306/" rel="">الحلقات التكرارية</a>، لكن اضطررنا إلى الانتظار حتى شرح تعليمات if، لذا نعود الآن إلى موضوع الحلقات التكرارية لنرى كيف يمكن أن يحل التفريع مشكلةً شائعةً فيها، فقد نريد الخروج من حلقة تكرارية قبل أن تنتهي. توفر أغلب اللغات آليةً لإيقاف تنفيذ الحلقة، وفي بايثون تكون تلك الآلية هي كلمة <code>break</code>، ويمكن استخدامها في حلقتي <code>for</code> و<code>while</code>. تُستخدم هذه الكلمة غالبًا عند البحث في قائمة عن قيمة ما وإيجادها، عندها لا نريد متابعة البحث إلى نهاية الحلقة، كما تُستخدم إذا اكتشفنا خللًا في البيانات، أو إذا قابلنا شرط خطأ error condition؛ أما أكثر الاستخدامات شيوعًا خاصةً في بايثون التي اعتُمد فيها هذا السلوك لكثرة استخدامه، فهو عند قراءة الدخل باستخدام حلقة <code>while</code>.
</p>

<p>
	في مثالنا التالي سنستخدم كلمة <code>break</code> للخروج من الحلقة عندما نقابل أول قيمة صفرية في قائمة من الأعداد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_41" style=""><span class="pln">  nums </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="lit">4</span><span class="pun">,</span><span class="lit">7</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">]</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> num in nums</span><span class="pun">:</span><span class="pln">
     print</span><span class="pun">(</span><span class="pln"> num </span><span class="pun">)</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> num </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">break</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">اخرج</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">الحلقة</span><span class="pln"> </span><span class="pun">فورًا</span><span class="pln">
  print</span><span class="pun">(</span><span class="str">"We finished the loop"</span><span class="pun">)</span></pre>

<p>
	في المثال السابق نستطيع رؤية كيفية اختبار شرط الخروج في تعليمة <code>if</code>، ثم استخدام <code>break</code> للقفز خارج الحلقة. تحتوي جافاسكربت على الكلمة المفتاحية <code>break</code> لإيقاف الحلقات التكرارية، وتُستخدم بنفس الطريقة المستخدمة في بايثون؛ أما VBScript، فتستخدم الكلمات <code>Exit For</code> أو <code>Exit Do</code> للخروج من حلقاتها التكرارية.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		توجد كلمة قريبة في سلوكها من <code>break</code>، وهي <code>continue</code> غير أنها أقل استخدامًا منها، ووظيفتها الخروج من متن الحلقة فقط، بدلًا من إنهاء الحلقة بالكلية، حيث تقفز إلى بداية الحلقة التكرارية وتبدأ التكرار التالي، قد يكون هذا مفيدًا إذا أردنا معالجة أنواع بعينها من البيانات مثلًا، لكن يمكن الحصول على نفس النتيجة بشرط <code>if</code> داخل الكتلة البرمجية، تحتوي بايثون وجافاسكربت على كلمة <code>continue</code>، على عكس VBScript.
	</p>
</blockquote>

<h2>
	الجمع بين الشروط والحلقات التكرارية
</h2>

<p>
	بما أن الأمثلة التي أوردناها سابقًا كانت نظريةً وتجريديةً، فسننظر الآن في مثال يستخدم كل ما تعلمناه سابقًا لنشرح تقنيةً شائعةً في البرمجة، وهي عرض القوائم للتحكم في مدخلات المستخدم، لنرى الشيفرة أولًا ثم نشرحها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_43" style=""><span class="pln">menu </span><span class="pun">=</span><span class="pln"> </span><span class="str">"""</span><span class="pln">
</span><span class="typ">Pick</span><span class="pln"> a shape</span><span class="pun">(</span><span class="lit">1</span><span class="pun">-</span><span class="lit">3</span><span class="pun">):</span><span class="pln">
   </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Square</span><span class="pln">
   </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln">
   </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Triangle</span><span class="pln">

   </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Quit</span><span class="pln">
</span><span class="str">"""</span><span class="pln">
shape </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="pln">menu</span><span class="pun">))</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> shape </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">4</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
      length </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Length: "</span><span class="pun">))</span><span class="pln">
      print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Area of square = "</span><span class="pun">,</span><span class="pln"> length </span><span class="pun">**</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
   elif shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
      length </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Length: "</span><span class="pun">))</span><span class="pln">
      width </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Width: "</span><span class="pun">))</span><span class="pln">
      print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Area of rectangle = "</span><span class="pun">,</span><span class="pln"> length </span><span class="pun">*</span><span class="pln"> width </span><span class="pun">)</span><span class="pln">   
   elif shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
      length </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Length: "</span><span class="pun">))</span><span class="pln">
      width </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Width: "</span><span class="pun">))</span><span class="pln">
      print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Area of triangle = "</span><span class="pun">,</span><span class="pln"> length </span><span class="pun">*</span><span class="pln"> width </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">)</span><span class="pln">   
   </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> 
      print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Not a valid shape, try again"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
   shape </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="pln">menu</span><span class="pun">))</span></pre>

<p>
	لقد زدنا ثلاثة أسطر على مثال بايثون السابق، وهي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_45" style=""><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Quit</span><span class="pln">

</span><span class="kwd">while</span><span class="pln"> shape </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">4</span><span class="pun">:</span><span class="pln">

shape </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="pln">menu</span><span class="pun">))</span><span class="pln">   </span></pre>

<p>
	لكن هذه الأسطر الثلاثة جعلت البرنامج أكثر سهولةً، فقد مكنّا المستخدم من استمرار حساب أحجام الأشكال المختلفة إلى أن يجمع كل المعلومات التي يريدها، وذلك بإضافة الخيار <code>Quit</code> إلى القائمة وحلقة <code>while</code>، كما لا نحتاج الآن إلى إعادة تشغيل البرنامج يدويًا في كل مرة.
</p>

<p>
	أما السطر الثالث الذي أضفناه فقد كان لتكرار عملية اختيار الشكل <code>input(menu)‎</code> ليتمكن المستخدم من تغيير الشكل والخروج من البرنامج إذا أراد.
</p>

<p>
	يوهم هذا البرنامج المستخدم بأنه يعرف ما يرغب به وينفذه له، ويختلف سلوك البرنامج في كل مرة باختلاف مدخلات المستخدم، مما يجعل المستخدم يبدو وكأنه هو المتحكم بينما يكون المتحكم الحقيقي هو المبرمج، لأنه توقع جميع المدخلات الصالحة وجعل البرنامج يتفاعل معها، فتكون العبقرية الحقيقية هنا للمبرمج وليس للبرنامج أو الحاسوب، فالحواسيب غبية كما ذكرنا من قبل.
</p>

<p>
	تتضح الآن سهولة توسعة وظائف برنامجنا بمجرد إضافة بعض الأسطر ودمج تسلسلات -الكتل البرمجية التي تحسب مساحات الأشكال-، والحلقات التكرارية -حلقة <code>while</code>-، والتعليمات الشرطية -بنية <code>if</code> / <code>elif</code>-، وبهذا نكون قد أنهينا الوحدات الثلاث الأساسية التي تتكون منها البرمجة وفقًا لديكسترا، ونستطيع الآن برمجة أي شيء، من الناحية النظرية، بما أننا تعلمنا هذه الوحدات، غير أننا لا زلنا بحاجة إلى تقنيات أخرى لنتعرف على كيفية تسهيل كتابة البرامج على أنفسنا.
</p>

<h3>
	مبدأ DRY: لا تكرر نفسك
</h3>

<p>
	إحدى المزايا التي نريد الإشارة إليها في هذا البرنامج هو أننا اضطررنا إلى تكرار سطر <code>input()‎</code> مرةً قبل الحلقة ومرةً داخلها؟ ولا يفضَّل تكرار الشيفرة البرمجية نفسها أكثر من مرة، لأننا سنضطر إلى تذكر تغيير كلا السطرين إذا احتجنا إلى تعديلها أو تغييرها، مما يفسح مجالًا للخطأ والنسيان، وهنا يمكن استخدام حيلة مبنية على خاصية <code>break</code> التي تحدثنا عنها في مقال الحلقات التكرارية في البرمجة، حيث نجعل في هذه الحيلة حلقة <code>while</code> حلقةً لا نهائية، ثم نختبر شرط الخروج، ونستخدم <code>break</code> للخروج منها، انظر إلى المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_47" style=""><span class="pln">menu </span><span class="pun">=</span><span class="pln"> </span><span class="str">"""</span><span class="pln">
</span><span class="typ">Pick</span><span class="pln"> a shape</span><span class="pun">(</span><span class="lit">1</span><span class="pun">-</span><span class="lit">3</span><span class="pun">):</span><span class="pln">
   </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Square</span><span class="pln">
   </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Rectangle</span><span class="pln">
   </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Triangle</span><span class="pln">

   </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Quit</span><span class="pln">
</span><span class="str">"""</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="typ">True</span><span class="pun">:</span><span class="pln">
   shape </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="pln">menu</span><span class="pun">))</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">4</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">break</span><span class="pln">

   </span><span class="kwd">if</span><span class="pln"> shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
      length </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Length: "</span><span class="pun">))</span><span class="pln">
      print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Area of square = "</span><span class="pun">,</span><span class="pln"> length </span><span class="pun">**</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
   elif shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
      length </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Length: "</span><span class="pun">))</span><span class="pln">
      width </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Width: "</span><span class="pun">))</span><span class="pln">
      print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Area of rectangle = "</span><span class="pun">,</span><span class="pln"> length </span><span class="pun">*</span><span class="pln"> width </span><span class="pun">)</span><span class="pln">   
   elif shape </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln">
      length </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Length: "</span><span class="pun">))</span><span class="pln">
      width </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">"Width: "</span><span class="pun">))</span><span class="pln">
      print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Area of triangle = "</span><span class="pun">,</span><span class="pln"> length </span><span class="pun">*</span><span class="pln"> width </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">)</span><span class="pln">   
   </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> 
      print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Not a valid shape, try again"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	يسمى تقليل التكرار هذا، والذي يبدو بدهيًا في أوساط المبرمجين، باسم مبدأ DRY، وهو اختصار لـ: "لا تكرر نفسك Dont Repeat Yourself".
</p>

<h2>
	التعابير الشرطية
</h2>

<p>
	توجد صورة أخرى من التفريع شائعة جدًا في البرمجة، عندما نريد إسناد قيمة مختلفة إلى متغير وفقًا لشرط ما، ويمكن فعل هذا بسهولة باستخدام شرط <code>if/else</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_49" style=""><span class="kwd">if</span><span class="pln"> someCondition</span><span class="pun">:</span><span class="pln">
   value </span><span class="pun">=</span><span class="pln"> </span><span class="str">'foo'</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
   value </span><span class="pun">=</span><span class="pln"> </span><span class="str">'bar'</span></pre>

<p>
	إلا أن لغات البرمجة توفر اختصارًا لذلك، وهو ما يسمى ببنية التعبير الشرطي، ويبدو في بايثون كما يلي، وهو مطابق تمامًا في وظيفته للشيفرة أعلاه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_53" style=""><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">'foo'</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">شرط</span><span class="pln"> </span><span class="pun">ما</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="str">'bar'</span></pre>

<p>
	لا تحتوي VBScript على مثل هذه البنية، وتوفر جافاسكربت شيئًا شبيهًا بها، لكن البنية اللغوية له مبهمة قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_51" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> someCondition </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> s</span><span class="pun">;</span><span class="pln">

s </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">someCondition </span><span class="pun">?</span><span class="pln"> </span><span class="str">"foo"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"bar"</span><span class="pun">);</span><span class="pln">
document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">s</span><span class="pun">);</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لاحظ البنية الغريبة للشرط بين القوسين <code>()</code>، الذي له نفس وظيفة الأمثلة السابقة في بايثون، إلا أنه يستخدم مجموعةً مختصرةً من الرموز، وهو يقول: "إن تحقق التعبير الذي يسبق علامة الاستفهام وكان true، فأعد القيمة التي بعد علامة الاستفهام، وإلا فأعد القيمة التي بعد النقطتين الرأسيتين". لا يُعَد القوسان ضروريين في هذا المثال رغم استخدامنا لهما، لأنهما يوضحان للقارئ ما يحدث في الشيفرة، ويُنصح باستخدامهما حتى في التعبيرات الشرطية في بايثون.
</p>

<p>
	إن مثل هذه الاختصارات تبدو جماليةً مريحةً في استخدامها، لكن كثيرًا من المبرمجين ينأون عنها ويرونها غير عملية، لذا يجب استخدمها متى كان وجودها ضروريًا ومتى دعت الحاجة إليها، ويُفضل تجنبها إذا جعلت الشيفرة تبدو معقدةً أكثر من اللازم.
</p>

<h2>
	تعديل التجميعات من داخل الحلقات التكرارية
</h2>

<p>
	لقد ذكرنا في مقال الحلقات التكرارية في البرمجة أن تعديل التجميعة collection من داخل حلقة تكرارية أمر صعب، لكن لم نشرح كيفية تعديلها وقتها، إذ أردنا الانتظار حتى نشرح التفريع أولًا، وقد أتى وقت بيان ذلك، يمكن استخدام حلقة <code>while</code> لتنفيذ التعديلات أثناء التكرار على التجميعة نفسها، وهذا ممكن لأننا نستطيع التحكم الصريح في الفهرس داخل بنية <code>while</code> على عكس حلقة <code>for</code> التي يحدَّث الفهرس فيها تلقائيًا. لننظر الآن كيف نحذف جميع الأصفار من قائمة ما:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2535_55" style=""><span class="pln">myList </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">4</span><span class="pun">,</span><span class="lit">5</span><span class="pun">,</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
index </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> index </span><span class="pun">&lt;</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">myList</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> myList</span><span class="pun">[</span><span class="pln">index</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
      del</span><span class="pun">(</span><span class="pln">myList</span><span class="pun">[</span><span class="pln">index</span><span class="pun">])</span><span class="pln">
   </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> 
      index </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> myList </span><span class="pun">)</span></pre>

<p>
	تجدر الإشارة هنا إلى أننا لا نزيد الفهرس عند حذف عنصر، بل تحرك عملية الحذف باقي العناصر للأعلى كي يشير الفهرس القديم إلى العنصر التالي في التجميعة.
</p>

<p>
	سنستخدم فرع <code>if/else</code> لنتحكم في وقت زيادة الفهرس، ويسهل هنا ارتكاب خطأ في تنفيذ مثل هذا التعديل، لذا احرص على اختبار شيفرتك جيدًا، هناك مجموعة أخرى من دوال بايثون مصممة خصيصًا لتعديل محتويات القائمة، وسننظر فيها في مقال لاحق.
</p>

<h2>
	خاتمة
</h2>

<p>
	في نهاية هذا المقال نريد التذكير بما يلي:
</p>

<ul>
	<li>
		استخدم <code>if/else</code> لتفريع مسار البرنامج.
	</li>
	<li>
		استخدام <code>else</code> أمر اختياري يعود إليك.
	</li>
	<li>
		يمكن تمثيل القرارات المتعددة باستخدام بنية <code>Case</code> أو <code>if/elif</code>.
	</li>
	<li>
		تعيد التعابير البوليانية القيمة <code>True</code> أو <code>False</code>، ويمكن دمجها باستخدام <code>and</code> أو <code>or</code>.
	</li>
	<li>
		دمج القوائم باستخدام البنية <code>Case</code> يسمح لنا ببناء تطبيقات يتحكم فيها المستخدم.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutbranch.htm" rel="external nofollow">للفصل العاشر: Decisions, Decisions من كتاب Learning To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-r1333/" rel="">البرمجة باستخدام الوحدات</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-r1311/" rel="">كيفية قراءة البرامج لمدخلات المستخدم</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">المدخل الشامل لتعلم علوم الحاسوب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/apps/productivity/office/microsoft-excel/%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D9%85%D8%A7%D9%8A%D9%83%D8%B1%D9%88%D8%B3%D9%88%D9%81%D8%AA-%D8%A5%D9%83%D8%B3%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vba-r452/" rel="">العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D9%87%D9%84-%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">أسهل لغات البرمجة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1329</guid><pubDate>Sun, 26 Sep 2021 15:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x62F;&#x62E;&#x644; &#x627;&#x644;&#x634;&#x627;&#x645;&#x644; &#x644;&#x62A;&#x639;&#x644;&#x645; &#x639;&#x644;&#x648;&#x645; &#x627;&#x644;&#x62D;&#x627;&#x633;&#x648;&#x628;</title><link>https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_09/61446837e4f57_----.png.fff00f9fbe6c8d6bd46eb4a39c9b3bbd.png" /></p>
<p>
	علوم الحاسوب computer science (أو يطلق عليه علوم الكمبيوتر أو علوم الحاسبات بالعامية) هو روح العصر الحديث ويمثل مجال التقنية التي دخلت في كل مفاصل حياتنا، فهو يدخل في كل صغيرة وكبيرة من حولنا بدءًا من الهواتف المحمولة والحواسيب والآلات والمصانع وكل شيء بما لا يمكن حصره من المنتجات والخدمات حيث أسهم في نقلنا إلى مرحلة أعلى من الفعالية والجودة والفائدة.
</p>

<p>
	هذا المقال هو دليل شامل للتعرف على اختصاص علوم الحاسب وفوائده وتطبيقاته والمواد التي تدرس فيه والمجالات المتفرعة منه ثم سنناقش بعض الأسئلة المهمة المتعلقة بجدوى اختيار تخصص علوم الحاسوب ودراسته وما هي فرص العمل المتوفرة في مجال علوم الحاسوب وسنعرف أيضًا الفرق بين علم الحاسوب وهندسة الحاسوب وأخيرًا سنرشدك إلى كيفية البدء في دراسة اختصاص علوم الحاسب ذاتيًا وندلك على بداية الطريق لتنطلق إن أحببت المجال.
</p>

<p>
	هل أنت جاهز؟ لننطلق!
</p>

<h2>
	فهرس المحتويات
</h2>

<p>
	حرصًا على تنظيم المقالة ولتسهيل الوصول إلى القسم الذي تريده بسهولة، سنذكر هنا جدول المحتويات باختصار:
</p>

<ul>
	<li>
		<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="#%D9%85%D8%A7-%D9%87%D9%8A-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8" rel="">ما هي علوم الحاسب؟</a>
	</li>
	<li>
		<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="#%D9%81%D9%88%D8%A7%D8%A6%D8%AF-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8" rel="">فوائد وتطبيقات علوم الحاسوب</a>
	</li>
	<li>
		<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="#%D9%87%D9%84-%D8%AA%D8%B9%D9%84%D9%85-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8-%D9%85%D9%81%D9%8A%D8%AF" rel="">هل تعلم علوم الحاسوب مفيد؟</a>
	</li>
	<li>
		<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="#%D9%85%D9%88%D8%A7%D8%AF-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8" rel="">مواد علوم الحاسوب</a>
	</li>
	<li>
		<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="#%D8%AA%D8%AE%D8%B5%D8%B5%D8%A7%D8%AA-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8" rel="">تخصصات علوم الحاسب</a>
	</li>
	<li>
		<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="#%D9%83%D9%8A%D9%81-%D8%A3%D8%AE%D8%AA%D8%A7%D8%B1-%D8%A7%D9%84%D8%AA%D8%AE%D8%B5%D8%B5-%D8%A7%D9%84%D9%85%D9%86%D8%A7%D8%B3%D8%A8-%D9%84%D9%8A-%D9%85%D9%86-%D8%AA%D8%AE%D8%B5%D8%B5%D8%A7%D8%AA-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8" rel="">كيف أختار التخصص المناسب لي من تخصصات علوم الحاسب؟</a>
	</li>
	<li>
		<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="#%D8%A7%D9%84%D8%AA%D9%88%D8%B8%D9%8A%D9%81-%D9%88%D9%81%D8%B1%D8%B5-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D9%85%D8%AC%D8%A7%D9%84-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8" rel="">التوظيف وفرص العمل في مجال علوم الحاسوب</a>
	</li>
	<li>
		<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="#%D8%A7%D9%84%D9%81%D8%B1%D9%82-%D8%A8%D9%8A%D9%86-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D8%A8-%D9%88%D9%87%D9%86%D8%AF%D8%B3%D8%A9-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D8%A8" rel="">ما الفرق بين علوم الحاسب وهندسة الحاسب؟</a>
	</li>
	<li>
		<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="#%D9%85%D9%86-%D8%A3%D9%8A%D9%86-%D8%A3%D8%A8%D8%AF%D8%A3-%D8%A8%D8%AA%D8%B9%D9%84%D9%85-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8" rel="">من أين أبدأ بتعلم علوم الحاسب؟</a>
	</li>
</ul>

<h2 id="ما-هي-علوم-الحاسوب">
	ما هي علوم الحاسب؟
</h2>

<p>
	تُعرَف علوم الحاسوب بأنها كل العلوم المتعلقة بالآلات الحسابية والمنطقية، حيث تعمل بدارات إلكترونية، وقد تكون علومًا نظريةً مثل نظرية المعلومات Information Theory أو تطبيقية مثل البرمجيات Software أو العتاد Hardware.
</p>

<p>
	والبرمجيات software هي الأنظمة غير الملموسة التي تُشغّل عتاد الحواسيب hardware وتقوم بمهام المستخدمين المطلوبة، بينما العتاد هو القطع الفيزيائية الملموسة التي تُكوّن النظام الحاسوبي مثل المعالِج والذاكرة العشوائية RAM والقرص الصلب …إلخ.
</p>

<p>
	وتتشعّب علوم الحاسوب وتترابط مع بعضها بعضًا، إذ لا يمكنك دراسة البرمجة دون دراسة الخوارزميات وهياكل البيانات، كما لا يمكنك دراسة علوم <a href="https://academy.hsoub.com/programming/artificial-intelligence/%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A/" rel="">الذكاء الاصطناعي</a> دون دراسة الجبر الخطّي والاحتمالات وعدد آخر من علوم الرياضيات.
</p>

<h2 id="فوائد-وتطبيقات-علوم-الحاسوب">
	فوائد وتطبيقات علوم الحاسوب
</h2>

<p>
	نَذكُر من فوائد وتطبيقات علم الحاسوب ما يلي:
</p>

<ul>
	<li>
		تعد شبكة الإنترنت واحدة من أفضل الاختراعات في التاريخ الإنساني، فهي شبكة حاسوبية تصل مناطق العالم ببعضها البعض.
	</li>
	<li>
		حواسيب سطح المكتب والحواسيب المحمولة التي نعمل عليها أو نرفّه خلالها عن أنفسنا …إلخ، جميعها قائمة على علوم الحاسوب وتخصصات الحاسب.
	</li>
	<li>
		الهواتف المحمولة وتطبيقات الهواتف الذكية التي نستعملها للتسوق أو طلب سيارة أجرةٍ أو طلب الطعام والدواء وغير ذلك فكلها تطبيقات حاسوبية.
	</li>
	<li>
		أجهزة إدارة المصانع والعمليات التصنيعية التي تُستعمل لتخطيط تصنيع المنتجات الغذائية وغير الغذائية، فهي مبنيّة بالأساس على برامج وخوارزميات ورياضيات حاسوبية، فلولاها لما تطورت أنظمة التصنيع التي لدينا إلى مرحلة تكفي احتياجات الجنس البشري.
	</li>
	<li>
		الأجهزة الطبية التي تُنقَذ بها حياة الناس في المستشفيات، وأجهزة الاستشعار والإدارة العسكرية، والأجهزة التي تساعد على إدارة الأسواق الاقتصاد والمال وغيرها، فكلها موجودة بفضل علوم الحاسوب.
	</li>
</ul>

<p>
	ولعلك تشاهد بعضًا من فوائد هذه العلوم بنفسك، فلا تحتاج من يخبرك عنها.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة علوم الحاسوب
		</p>

		<p class="banner-subtitle">
			دورة تدريبية متكاملة تضعك على بوابة الاحتراف في تعلم أساسيات البرمجة وعلوم الحاسوب
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/computer-science/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<img alt="دورة علوم الحاسوب" src="https://academy.hsoub.com/learn/assets/images/courses/computer-science.png">
	</div>
</div>

<h2 id="هل-تعلم-علوم-الحاسوب-مفيد">
	هل تعلم علوم الحاسب مفيد؟
</h2>

<p>
	قد تفكر في نفسك الآن وتقول هل من المجدي لي أن أتخصص في مجال علم الحاسوب وأتعلمها سواء للدراسة والبحث الأكاديمي أو للعمل والوظيفة مستقبلًا؟ والجواب هو نعم، فالأمر مُجدٍ وأنصح به بشدة، إذ يحصل متخصصو علوم الحاسوب على <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://www.payscale.com/research/US/Industry=Software/Salary" rel="external nofollow">رواتب أعلى</a> من العديد من نظرائهم المهندسين غير العاملين في المجال، كما تزداد الرواتب بازدياد الخبرة ونُدرة المجال الذي يتخصص فيه المرء؛ فمثلًا لا يتساوى مُطوّر واجهات الاستخدام بمهندس يجيد الذكاء الاصطناعي وتعلم الآلة، وكذلك لا يتساوى مع مهندسي البرمجيات ومهندسي العتاد.
</p>

<p>
	وبغض النظر عن عامل الوظيفة والراتب والمال، يساعدك تعلم علوم الحاسوب على بناء مشاريع حقيقيةٍ يمكنك أن تستفيد منها أو تغيّر بها العالم، مثلًا انظر كيف غير مارك زوكيبربيرغ طريقة تواصل المليارات من البشر وكامل التاريخ الإنساني بسبب تطويره لموقع إنترنتٍ، وانظر كذلك كيف تتحكم العملات الرقمية وتغير الاقتصاد العالمي في وقتنا الحالي.
</p>

<p>
	ويؤهلك تعلم علوم الحاسب لإنشاء خدمات ومواقع وبرمجيات وأنظمة حسبما تحتاج، ومن ثَم تستفيد منها سواءٌ لنفسك أو تبيعها للآخرين إما على شكل وظيفةٍ، أو خبرةٍ كما في مجال العمل الحُرّ.
</p>

<p>
	ولا يعني هذا بالطبع أنك ستكون مالك شركة مايكروسوفت المستقبلي، وكذلك لن تكون مارك الذي سيغيّر العالم، إلا أنك ستمتلك نفس الخبرات والأدوات التي امتلكوها عندما فعلوا ذلك، أما الباقي فيعتمد عليك وعلى اجتهادك ومثابرتك.
</p>

<h2 id="مواد-علوم-الحاسوب">
	مواد علوم الحاسب
</h2>

<p style="text-align: center;">
	<img alt="تعلم-علوم-الحاسوب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="77485" data-unique="4fpa7zlel" style="" src="https://academy.hsoub.com/uploads/monthly_2021_09/614b243eef1c6_--.jpg.d1faf91818405304576818baf740f083.jpg">
</p>

<p>
	سنتحدث في هذا القِسم عن مواد تخصص علوم الحاسب وتفريعاتها المختلفة، وأبرز المواد التي تُدرّسها معظم الجامعات حول العالم لطلابها الراغبين بتَعلّم هذا التخصص، ومعظم هذه المواد مُستوحاةٌ من <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://cs.stanford.edu/degrees/undergrad/Requirements.shtml" rel="external nofollow">الفهرس الأكاديمي لجامعة ستانفورد</a> لعلوم الحاسبات، هذا بالإضافة لعددٍ من الجامعات الأخرى.
</p>

<h3>
	1. أساسيات الهندسة وهندسة البرمجيات
</h3>

<p>
	تعد من أول المواد التي يدرسها الطلاب وتهدف للإجابة على أسئلة متنوعة مثل ما هو تعريف الهندسة وما هي عمليات الإدخال والإخراج وكيف تصمم منتجًا أو برنامجًا أو مشروعًا وما هي الخطوات العملية لتصميم وهندسة نظام ما وغيرها.
</p>

<p>
	والهدف الرئيسي من هذه المادة هو نقل وتوصيل معنى الهندسة للطلاب، وذلك بإدراكهم أن عملية إنشاء الأنظمة هي خليطٌ مُتقنٌ من التخطيط والترتيب، فهي ليست عمليةً عشوائيةً بسيطةً، وعادةً لا تحتوي هذه المادة على مشاريع برمجية حقيقية، وقد تشتمل على مشاريع بسيطة في بعض الجامعات.
</p>

<p>
	ويَتعلّم الطالب في هذه المادة عددًا من التقنيات والأدوات الشائعة لتوصيف الأنظمة وتصميماتها، مثل لغة النمذجة الموحدة Unified Modeling Language واختصارًا UML وآلات الحالة State Machines وغيرها من التقنيات.
</p>

<h3>
	2. الرياضيات الأساسية
</h3>

<p>
	مادة الرياضيات مادةٌ أساسيةٌ لدى جميع طلاب الهندسة عمومًا؛ لذلك من الضروري أن يُدرك الطالب أساسيات الرياضيات مثل العمليات الحسابية والتفاضل والتكامل والجبر وحسابات الأشكال الهندسية وغير ذلك من العمليات الرياضية البسيطة.
</p>

<p>
	ولا تُعلّم هذه المادة في الجامعات بهدف الرياضيات ذاتها؛ فبمجرد انتهائك من المادة ستنسى غالبًا تلك المعادلات الرياضية، ولكن الهدف هو تعويد الطالب على استخدام العقل لحساب ما لم يقدِر على حسابه من قبل، فمواجهة القليل من الصعوبة في التَعلّم تُفتّح الذهن وتُعوّده على تحمّل الأكثر صعوبةً من هذه الرياضيات البسيطة مستقبلًا.
</p>

<h3>
	3. الرياضيات الخطية
</h3>

<p>
	ستتعلم في الرياضيات الخطية أو الجبر الخطي أساس حلّ المعادلات الرياضية، مثل معادلات الدرجة الأولى والثانية والثالثة، وبعض الأساليب والقوانين الرياضية لحلها بسهولة.
</p>

<p>
	كما ستتعلم بعض الأمور عن المصفوفات وطريقة التعامل معها وإجراء بعض الحسابات لها وطريقة الاستفادة منها مثل المصفوفات أولية وثنائية وثلاثية الأبعاد.
</p>

<h3>
	4. التفاضل والتكامل
</h3>

<p>
	هنا ستتعمق في التفاضل والتكامل بعد اطلاعك عليها بصورة مبسطة بالفعل في إحدى المواد الرياضية السابقة، وستتعرف عليهما بالتفصيل، وكيف تستخدمها لحل بعض المشكلات الحقيقية في العالم، كما ستعرف بعض قواعد التفاضل والتكامل.
</p>

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

<h3>
	5. تصميم المنطق الرقمي
</h3>

<p>
	ستتعلم في مادة تصميم المنطق الرقمي Digital Logic Design أهم أركان التفكير المنطقي، وكيفية تمثيل الحجج والنقاشات والمعضلات في العالم الحقيقي على شكل معادلات رياضية ومنطقية وكذلك قد تتعلّم بعض الأمور عن المجموعات Sets في الرياضيات وطريقة استخدامها لتمثيل معلومة أو بيانات معينة.
</p>

<p>
	كما ستتعلم تصميم البوابات المنطقية Logic Gates مثل and و or و nor و xor و not وغيرها، وكذلك ستفهم الطريقة العامة لعمل المعالجات داخل الحواسيب والأجهزة الإلكترونية.
</p>

<p>
	وهذه المادة واحدةٌ من بين أكثر المواد إفادةً ضمن علم الحاسوب لأن طريقة التفكير المنطقية هذه ستنقلك من إنسان عشوائي التفكير قد لا يفكر بمنطقية في معظم أمور حياته إلى إنسان يفهم الحياة بصورة منطقية كما تفهمها الآلات ويَسهُل عليه تحديد ما هو منطقي وما هو غير منطقيٍ من الحجج والمعلومات التي حوله، كما ستفهم كيفية تحويل الأفكار إلى أنظمة فيزيائية وبرمجية داخل الحواسيب بحيث تُستعمَل لإكمال تصميم الحواسيب وتُجري العمليات الحسابية المطلوبة. أي الغرض من هذه المادة أن ترى كيف يعمل الحاسوب وكيف يفهم الأوامر وينفذها حتى تعرف كيف ستتعامل معه وتبرمجه وتتخاطب معه بسهولة.
</p>

<p>
	وفقًا لما سبق، من الأفضل التركيز عليها كونها واحدةٌ من أهم المواد في المجال، وقد تُدرّس هذه المادة على عدة مواد منفصلة، لذلك قد تجد موادًا شبيهةً مثل التفكير المنطقي Critical Thinking والرياضيات المتقطعة Discrete Mathematics، فكلّ على حسب الجامعة والتخصص.
</p>

<h3>
	6. الاحتمالات
</h3>

<p>
	مادة الرياضيات الأخيرة التي ستتعلّمها هي مادة الاحتمالات Probabilties أو نظرية الاحتمالات Probability Theory، وهي مادةٌ تهدف إلى تعليمك أهم مبادئ هذا العلم بالإضافة لأنواع الاحتمالات المُمكنة حسب الأحداث Events وطريقة ارتباطها ببعضها البعض ليُستفاد منها في الحياة الواقعية إما في اتخاذ قرارات المؤسسات أو إجراءات أصغر من ذلك سواءٌ على مستوى الأفراد أو الأجهزة الرقمية.
</p>

<p>
	والاحتمالات علم عميق تقوم عليه الكثير من الرياضيات الحديثة، كما يقوم عليه علم التعمية Cryptography المُستخدم في تأمين وتشفير الاتصالات والشبكات، وستستفيد من هذه المادة كثيرًا في المستقبل متى أتقنتها.
</p>

<h3>
	7. البرمجة
</h3>

<p>
	من البداهة أن توجد مادة مختصة <a href="https://academy.hsoub.com/learn-programming/" rel="">بتعلم البرمجة</a> في تخصص علوم الحاسب أو التخصصات المرتبطة به، وذلك لأن البرمجة هي لبّ علوم الحاسب في النهاية، فجميع الأجهزة والأنظمة التي حولنا ما هي إلا برمجيات وخوارزميات مختلفة صنعت لتعمل بطريقة معيّنة.
</p>

<p>
	كانت لغة <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/tags/%D9%85%D8%AF%D8%AE%D9%84%20%D8%A5%D9%84%D9%89%20%D8%AC%D8%A7%D9%81%D8%A7/" rel="">جافا Java</a> أبرز لغة برمجةٍ تُعلّم في الجامعات قبل عقد من الزمن، بينما تميل الكفة الآن إلى <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون Python</a> أو <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/courses/javascript-application-development/" rel="">جافاسكربت</a> في بعض الأحيان، ولكن بايثون هي الأكثر استعمالًا واعتمادًا في الجامعات لما لها من تطبيقات لاحقة في جميع المجالات الأكاديمية الأخرى.
</p>

<p>
	وفي كل الأحوال ستتعلّم في هذه المادة المتغيرات والخوارزميات وحلقات التكرار والجمل الشرطية والبرمجة كائنية التوجه وغيرها من المبادئ البرمجية، وذلك بِغَض النظر عن لغة البرمجة التي ستتعلّمها.
</p>

<p>
	كما قد تُعلّم القليل من استخدام بيئة ماتلاب Matlab وهي بيئة برمجية ولغة برمجة تُستخدَم لإنشاء الحسابات الرياضية وبرمجة برمجيات معينة، لذلك فهي منصة ولغة برمجة في آنٍ واحدٍ، ويستعمل ماتلاب طلاب أقسام الهندسة الأخرى لمحاكاة وحساب المعادلات والنماذج الرياضية.
</p>

<h3>
	8. الخوارزميات وهياكل البيانات
</h3>

<p>
	<strong><a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://wiki.hsoub.com/Algorithms" rel="external">الخوارزميات Algorithms</a></strong> وهي الإجراءات المنطقية المتسلسلة لحلّ مشكلة ما، وسنتعلّم الخوارزميات وأفضل الطرق لتصميمها من أجل حل مختلف المشكلات التي قد تظهر لنا في المستقبل، حيث سنحتاج إلى معرفة متى نستعمل خوارزمية بعينها من أجل <a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/general/%D8%AD%D9%84-%D8%A7%D9%84%D9%85%D8%B4%D9%83%D9%84%D8%A7%D8%AA-%D9%88%D8%A3%D9%87%D9%85%D9%8A%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r760/" rel="">حل مشكلة</a> ما، ومتى سنلجأ لخوارزمية أخرى نعرف أنها ستعطينا أداءً أفضل، بمعنى أننا سنغوص في <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/advance/%D8%AF%D9%84%D9%8A%D9%84-%D8%B4%D8%A7%D9%85%D9%84-%D8%B9%D9%86-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-r1247/" rel="">الموازنة بين مختلف الخوارزميات وأدائها</a> مثل السرعة والوقت ومساحة التخزين، ومتى يجب استعمال كلّ واحدةٍ منها كما سنطّلع على مختلف تشعيبات الخوارزميات المتوفرة.
</p>

<p>
	<strong>هياكل البيانات Data Structures</strong> وهي طريقة تخزين البيانات واستعمالها بغرض تحقيق أهدافٍ مختلفةٍ حسبما يريد المُطوّر؛ فهناك هياكل بياناتٍ أسهل وأوضح للفهم العام، وهناك هياكل بيانات أسرع في الأداء، وهناك هياكل بيانات غير سريعة في الأداء لكنها تستهلك حجمًا أقل في تخزين البيانات وبالتالي قد تفضل على غيرها في بعض الأحيان.
</p>

<p>
	وستتعلم كل هذه الأمور في هذه المادة، وربما تقسم هذه المادة إلى مادتين على حسب الجامعة والاختصاص الذي تدرسه، كما ستطلع على <strong><a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://wiki.hsoub.com/Design_Patterns" rel="external">أنماط التصميم Design Patterns</a></strong> إذا كنت ستدرس <a href="https://academy.hsoub.com/programming/general/%D9%87%D9%86%D8%AF%D8%B3%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7%D8%AA/" rel="">هندسة البرمجيات</a>؛ وهي الأنماط الشهيرة لتصميم البرمجيات بحيث لا تحتاج لإعادة اختراع العجلة مرة أخرى من أجل كل مشكلة تواجهها.
</p>

<h3>
	9. مبادئ أنظمة التشغيل
</h3>

<p>
	أنظمة التشغيل هي البرمجيات الأساسية التي تُدير الأجهزة الحاسوبية والهواتف والأنظمة المدمجة وغيرها، حيث توزع الموارد على البرمجيات وتدير تشغيلها وعملها ومراقبتها للمستخدم، وأبرز أنظمة التشغيل على سطح المكتب هي ويندوز Windows وماك Mac ولينكس Linux، أم فيما يتعلق بأنظمة تشغيل الهواتف الذكية، فلدينا نظام أندرويد Android الذي يعمل على مختلف الأجهزة ونظام iOS الذي يعمل على أجهزة آبل Apple فقط.
</p>

<p>
	وستتعلم في هذه المادة أساسيات عمل أنظمة التشغيل المختلفة، بالإضافة لأبرز المبادئ التي تعمل بها أنظمة التشغيل الحالية مثل العمليات وأجهزة الإدخال والإخراج Input/Output وإدارة الذاكرة والوصول للمعالِج ونظام الوصول والصلاحيات وإدارة المستخدمين وغير ذلك.
</p>

<p>
	وستضع عليك معظم الجامعات واجبات منزلية بلغة <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/c/" rel="">سي C</a> في هذه المادة، لذلك سيكون عليك تَعلّمها إن أردت اجتياز هذه المادة بنجاح.
</p>

<h3>
	10. مبادئ الشبكات
</h3>

<p>
	<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/devops/networking/" rel="">الشبكات</a> هي كذلك من أبرز سمات العصر الحديث فشبكات الاتصال الخلوية وشبكة الإنترنت والشبكات المنزلية كلها غيّرت شكل العالم الحديث وساهمت في فوائد جمة لا تعد ولا تحصى فبدون علم الشبكات، لن تتمكن من قراءة هذا المقال الآن.
</p>

<p>
	وستتعلم في هذه المادة <a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/certificates/comptia/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D9%88%D8%A7%D8%B3%D9%8A%D8%A8-%D9%85%D8%B5%D8%B7%D9%84%D8%AD%D8%A7%D8%AA-%D9%88%D9%81%D9%87%D9%85-%D8%B7%D8%A8%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A9-r65/" rel="">أساسيات الشبكات وطريقة عملها</a>، وستطّلع على بروتوكولات التواصل أشهرها <a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/devops/servers/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-tcpip-%D9%88%D8%A8%D8%B9%D8%B6-%D9%85%D9%86-%D8%AE%D8%AF%D9%85%D8%A7%D8%AA%D9%87-r169/" rel="">بروتوكول TCP وبروتوكول UDP</a>، كما ستطّلع على بعض المفاهيم والأجهزة الأخرى مثل الموجه Router والخوادم Servers وأجهزة العملاء Clients والنظير للنظير Peer to Peer وغير ذلك من مبادئ الشبكات البسيطة.
</p>

<p>
	وسيطلب منك غالبًا برمجة برنامج محادثة بسيط بأي لغة برمجةٍ تريدها وذلك باستخدام أحد بروتوكولات التواصل، وهو ما سيوضح مدى فهمك وتعلمك لهذا المساق.
</p>

<h3>
	11. معمارية الحاسوب
</h3>

<p style="text-align: center;">
	<img alt="هيكلة-الحواسيب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="77486" data-unique="8rv90arv7" style="" src="https://academy.hsoub.com/uploads/monthly_2021_09/614b243f5b549_-.jpg.42db9484058ca84332abfc61d7666590.jpg">
</p>

<p>
	إلى هنا سيكون طالب علم الحاسوب قد فهم بالفعل معظم الأساسيات التي سيحتاج إليها، ولكن مادة معمارية الحاسوب أو بنية الحاسوب Computer Architecture ستتعمق في تفاصيل دقيقة حول <a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/certificates/comptia/%D8%A7%D9%84%D9%84%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D8%A3%D9%85-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r55/" rel="">مكونات الحاسوب الفيزيائية</a> وكيفية تواصلها مع بعضها بعضًا مثل طريقة تواصل الذاكرة العشوائية مع المعالِج وقرص التخزين وطريقة إرسال أو جلب المعلومات منهما.
</p>

<p>
	كما سيطّلع على مفهوم المسجلات Registers، وهي وحدات الذاكرة الصغيرة للمعالجات الحديثة، وكيف يستعملها لتسريع عمليات المعالجة بدلًا من جلب البيانات من الذاكرة، وسيفهم كيف ستتحول الخوارزميات والبرمجيات التي يكتبها إلى عمليات مجزأة يمكن للمعالجات حسابها في أقل من لحظة من الزمن بفضل البوابات المنطقية التي تعرّف عليها مسبقًا.
</p>

<p>
	أي أن هذه المادة ستغوص في تفاصيل عمل أجهزة الحواسيب وبنيتها الداخلية وطريقة تواصل مكوناتها مع بعضها بعضًا.
</p>

<p>
	زيادةً على المواد الأساسية التي ذكرناها آنفًا، هناك مواد ومجالات وتخصصات اختيارية يختار الطالب غالبًا ما يحلو له منها ليمارس المجال الذي يحبه، ولا يتخرج مهندسو الحاسوب وهم يتقنون كل هذه التخصصات، فعادةً ما يختارون واحدًا أو اثنين منها على الأكثر، ثم يدرسونه بصورةٍ أعمق من السابق، لذا سننتقل تاليًا إلى شرح تخصصات الحاسب التي يمكن لمهندس الحاسوب أو دارس تخصص علم الحاسوب أن يعمل ويتخصص فيها.
</p>

<h2 id="تخصصات-علوم-الحاسوب">
	تخصصات علوم الحاسب
</h2>

<p>
	لا يكون هناك تخصصات واضحة في الجامعة أحيانًا، بل يمكن للطالب ببساطة أن يختار مجال أحد المواد التي درسها وأحبها ويتخصص فيها إلى حين إتمام السنوات الدراسية.
</p>

<p>
	سنعرض أهم تخصصات الحاسب والمجالات التي يمكن العمل فيها بعد التخرج:
</p>

<h3>
	1. البرمجة وهندسة البرمجيات
</h3>

<p style="text-align: center;">
	<img alt="البرمجة-وهندسة-البرمجيات-في-علوم-الحاسب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="77482" data-unique="q371gdfdw" style="" src="https://academy.hsoub.com/uploads/monthly_2021_09/614b243cc41df_-----.jpg.a81e3909ee8995c1770f4308450a5f90.jpg">
</p>

<p>
	هندسة البرمجيات وهي العلم المَعني بصناعة البرمجيات بطريقة احترافية، فهي لا تختص بالبرمجة فقط وإنما تشمل فروعًا وعمليات أكثر من ذلك بكثير.
</p>

<p>
	صحيحٌ أن <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B3%D8%B7%D8%AD-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8/" rel="">تطوير تطبيقات سطح المكتب</a> وتطوير تطبيقات الهواتف المحمولة هي المجالات البرمجية الأكثر شيوعًا، لكن هناك مجالات برمجية أخرى أكثر تعقيدًا مثل:
</p>

<ul>
	<li>
		برمجة أنظمة إدارة الخوادم Servers مثل Kubernetes و<a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/devops/cloud-computing/docker/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-docker-r3/" rel="">دوكر Docker</a> وأشباهها من أدوات <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/devops/" rel="">إدارة العمليات DevOps</a>.
	</li>
	<li>
		برمجة أدوات الأنظمة المالية والاقتصادية التي تدير اقتصادات الدول والبنوك حول العالم.
	</li>
	<li>
		برمجة أنظمة الشركات العملاقة مثل شركات الطيران وشركات النفط وشركات الكهرباء …إلخ، فهذه أنظمةٌ حساسةٌ لا تحتمل الفشل وإن احتملته فهي بحاجة للاسترجاع والإدارة الفورية.
	</li>
	<li>
		الكثير من الشركات العملاقة كانت تعمل قبل عِدّة عقودٍ من الزمن على أنظمة مبرمجة بلغات برمجية قديمة عفا عليها الزمن الآن ولم يعد يُبرمَج بها، ولكن ما زالت هذه الشركات تعمل بتلك الأنظمة لعِدّة أسبابٍ لوجستيةٍ وهنا يعد نقل البرمجيات من لغة برمجة معينة إلى لغة برمجة أخرى هو مجال تخصصي كبير في علوم الحاسبات وقسم هندسة البرمجيات، فمثلًا <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://www.ziprecruiter.com/Jobs/IBM-Cobol" rel="external nofollow">تدفع شركة IBM رواتب عملاقة</a> لمن يجيد نقل برمجياتٍ مكتوبةٍ بلغة COBOL إلى لغة C.
	</li>
</ul>

<p>
	ويقوم مهندسو البرمجيات بالتخطيط لعملية بناء البرمجيات اللازمة لهذه المجالات، كما يخططون للموارد التي ستلزمهم والمميزات التي سيسلمونها بالإضافة إلى نمط التصميم الذي سيستعملونه في مختلف مراحل تطوير البرنامج، ولذلك هي عملية معقدة واحترافية تحتاج إلى فريق متكامل من المبرمجين وليست مُجرّد برمجة بسيطة ينجزها فرد واحد.
</p>

<h3>
	2. هندسة الشبكات
</h3>

<p>
	الشبكات ليست برامج التواصل بين المستخدمين فقط، فهناك شبكات أعقد من ذلك بكثير.
</p>

<p>
	ويمكنك التخصص في مجال الشبكات لتفهم <a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/devops/networking/%D9%85%D8%B9%D9%85%D8%A7%D8%B1%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8%D9%8A%D8%A9-%D9%88%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-network-architecture-r484/" rel="">طريقة عمل الشبكات البسيطة</a> وحتى العملاقة مثل شبكة الإنترنت، والبنية التحتية لها وطريقة ربط الدول لتلك البنية التحتية، كما يمكنك التعرف على بعض أنماط الشبكات البديلة مثل النظير للنظير Peer to Peer وكيفية عمل تطبيقات مفيدة بها في الحياة الواقعية.
</p>

<p>
	وكذلك قد تتطرق إلى الشبكات المركبية Vehicular Networks وهي الشبكات المرتبطة بالسيارات والمركبات، أو شبكات الاتصال الخلوي وطريقة صنعها وعملها، وطريقة التعامل مع مختلف أجهزة المودم Modems.
</p>

<p>
	وبشكلٍ أبسط من ذلك، فيمكن أن تعمل مدير شبكات في المؤسسات والشركات الصغيرة والكبيرة وحتى مراكز إدارة الخوادم Data Centers، فلا تخلو الآن مؤسسة أو شركة من شبكة داخلية تربط أقسامها مع بعضها وهي آنذاك بحاجة إلى مدير شبكة بالتأكيد هذا أقل القليل.
</p>

<h3>
	3. الذكاء الاصطناعي وتعلم الآلة
</h3>

<p style="text-align: center;">
	<img alt="الذكاء-الاصطناعي-وتعلم-الآلة.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="77483" data-unique="kogeyh0d2" style="" src="https://academy.hsoub.com/uploads/monthly_2021_09/614b243d5e187_---.jpg.08ab7f3ad03279bba9ac08f7f0548313.jpg">
</p>

<p>
	<a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/artificial-intelligence/%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A-%D8%A3%D9%87%D9%85-%D8%A7%D9%84%D8%A5%D9%86%D8%AC%D8%A7%D8%B2%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%B1%D8%A7%D8%B9%D8%A7%D8%AA-%D9%88%D9%83%D9%8A%D9%81-%D8%A3%D8%AB%D8%B1%D8%AA-%D9%81%D9%8A-%D8%AD%D9%8A%D8%A7%D8%AA%D9%86%D8%A7-%D8%A7%D9%84%D9%8A%D9%88%D9%85%D9%8A%D8%A9-r975/" rel="">زاد الاهتمام بالذكاء الاصطناعي زيادة كبيرة في العقد الأخير</a>، وهذا أمرٌ طبيعيٌ بسبب زيادة الحاجة إليه، بالإضافة إلى تَوفُّر الموارد الحاسوبية الكافية لتشغيل خوارزمياته المختلفة على أجهزة المستخدمين الشخصية، فدخل الذكاء الاصطناعي في كل شيء حولنا من <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://ieeexplore.ieee.org/document/9358334" rel="external nofollow">إدارة إشارات المرور</a> وتنظيم السير وتصنيف الصور في هواتفنا والتعرف على الأشخاص والوجوه والترجمة الآلية وإدارة المركبات والآلات وكشف الجرائم وعمليات التتبع وتحليل البيانات والكثير الكثير غيرها حتى بات تقريبًا عصب التقدم والتطور الذي نشهده حاليًا، وهو الأمر الذي يفسر سبب الطلب الكبير على المتخصصين في هذا المجال كما أشرنا.
</p>

<p>
	وهناك فرق بين <strong>الذكاء الاصطناعي Artificial Intelligence</strong> و<strong>تعلم الآلة Machine Learning</strong>؛ فالأول هو اسم المجال العام المَعني بكل ما يتعلق بإنشاء ذكاء يشابه ذكاء الإنسان باستعمال الآلات بينما الثاني مجال فرعي يتعلق بتدريب الآلات على مجموعة بيانات معينة بهدف الخروج منها بتصنيفات يمكن أن تساعد الآلة على اتخاذ قرار مطلوب منها.
</p>

<p>
	وستتعلم في هذا التخصص فروع تعلم الآلة الثلاثة الأشهر وهم، التعلم الموجه Supervised Learning والتعلم غير الموجه Unsupervised Learning بالإضافة إلى التعلم المعزز Reinforcement Learning، وللمزيد من المعلومات عن المجال، يمكنك الاطّلاع على كتاب <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/files/17-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A-%D9%88%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A2%D9%84%D8%A9/" rel="">مدخل إلى الذكاء الاصطناعي وتعلم الآلة</a>.
</p>

<h3>
	4. الحوسبة البيولوجية الطبية
</h3>

<p>
	لا تأتي الأجهزة الطبية الموجودة بالمستشفيات من العدم، بل يصنعها المهندسون ويساهم فيها المبرمجون، وهناك مجموعة من المواد الجامعية في تخصصات الحاسب التي تعلم الحوسبة البيولوجية الطبية الحيوية Biomedical Computing، وقد تكون تخصصًا كاملًا منفصلًا في بعض الجامعات باسم هندسة طبية حيوية biomedical engineering أو هندسة الأجهزة الطبية أو الهندسة الطبية.
</p>

<p>
	ويمكن أن تتخصص في هذا المجال لتتعلم أهم المتطلبات البرمجية في المجال الطبي أو البيولوجي، وكيفية تطوير برمجيات أو قطع عتاد تحل مشاكل أو تقدم استخدامات حقيقية تفيد مجال الطب والعلاج أي تقريبًا هو تخصص في مجال تصنيع الأجهزة المتعلقة في المجال الطبي من تصميم وبرمجة واختبار وتنفيذ …إلخ.
</p>

<p>
	ولا تستفيد المستشفيات فقط من هذا التخصص بل تستفيد كذلك مختبرات التحليل والمختبرات الحيوية والمستوصفات والعيادات الطبية وغيرها، فتحتاج جميعها إلى برمجيات صادرة عن المتخصصين في هذا المجال.
</p>

<h3>
	5. الرسوميات
</h3>

<p>
	لا تُعَد الرسوميات Graphics مجالًا واحدًا فقط، فهو مجال تطوير عريض جدًا، حيث تنضوي تحته مجموعة من المجالات المتفرعة، نذكر من بينها:
</p>

<ul>
	<li>
		أنظمة التشغيل، فلها مكتبات برمجية معينة تساعدها على عَرْض الخطوط والصور والواجهات الرسومية وغير ذلك للمستخدمين، وهذا مجال ضخم، فهو ضروري لتمكين المبرمجين الآخرين من تطوير التطبيقات والألعاب لأنظمة التشغيل هذه، أي أن الرسوميات هنا هي جزء من <a href="https://academy.hsoub.com/apps/operating-systems/%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84/" rel="">نظام التشغيل</a>.
	</li>
	<li>
		محركات الرسوميات Graphics Engines، وهي أنظمة برمجية عملاقة تهدف لتمكين المبرمجين من برمجة مختلف الرسوميات التي يريدونها لمختلف أنظمة التشغيل، فمثلًا يستخدم محرك <a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/game-development/unity3d/%D9%86%D8%A8%D8%B0%D8%A9-%D8%B9%D9%86-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D9%88%D9%85%D8%AD%D8%B1%D9%83-unity3d-r126/" rel="">Unity 3D</a> أو Source2 أو غيرهما لبرمجة الألعاب التي تعمل على مختلف أنظمة التشغيل مثل ويندوز وماك ولينكس وأندرويد.
	</li>
	<li>
		البرامج المتخصصة في الرسم ثنائي وثلاثي الأبعاد، فتعد برمجة هذه البرمجيات مجال منفصل ويتطلب بعض الخبرات والمهارات، بينما تعلم استخدامها سيحولك إلى مصمم، وتدخل فيها برامج النمذجة modeling مثل برامج الرسم والتصميم الهندسي CAD المفيدة في الكثير من التخصصات الهندسية.
	</li>
	<li>
		برامج تحرير ومونتاج الفيديوهات مجال فرعي آخر مشهور.
	</li>
</ul>

<p>
	وتدخل الكثير من التخصصات تحت تخصص الرسوميات كما ترى، إلا أنها قد تختلف جذريًا فيما بينها، فتطوير برامج الرسم ثنائية الأبعاد لا يشبه تطوير المحركات الرسومية فعملية تطوير المحركات الرسومية واحدة من أصعب العمليات البرمجية وأكثرها تعقيدًا، لأنها تحاكي فيزياء الكون وتتطلّب فهمًا عميقًا للرياضيات.
</p>

<h3>
	6. تحليل البيانات وإدارة قواعد البيانات
</h3>

<p>
	مجال تحليل البيانات (أو يرقى حتى إلى قسم منفصل باسم هندسة تحليل البيانات data analysis engineering) واحد من أكثر المجالات طلبًا حاليًا، لما له من استخدامات مفيدة وجلية في تحليل البيانات والمعطيات واستعمالها في اتخاذ القرارات المُهمَّة لدى المؤسسات والشركات، حتى إن بعض الفرق الرياضية لكرة القدم مثل <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://www.liverpool.com/liverpool-fc-news/features/liverpool-transfer-news-jurgen-klopp-17569689" rel="external nofollow">ليفربول</a> تعتمد على تحليل البيانات لوضع خططها الرياضية في كل مباراة، فتطبيقات هذا المجال واسعةٌ جدًا.
</p>

<p>
	كما ستتعلم في هذا المجال طريقة معالجة مجموعات ضخمة من البيانات، وطريقة تنظيفها من الأخطاء والمشاكل، وتحويلها إلى بياناتٍ يمكن معالجتها من الأنظمة الحاسوبية، وستتعلم طريقة استخراج أهم المعلومات والأسرار المخفية في البيانات الخام التي لديك بمختلف المكتبات واللغات البرمجية.
</p>

<p>
	حتى تتقن فن التعامل مع البيانات، فيجب أن تتقن التعامل مع أنظمة قواعد البيانات التي تخزَّن فيها البيانات، لذا يتخصص هذا المجال في مفهوم <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">قواعد البيانات Databases</a> و<a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%84%D8%A7%D9%82%D9%8A%D8%A9-sqlite-%D9%85%D8%B9-mysql-%D9%85%D8%B9-postgresql-r72/" rel="">أنظمة إدارة قواعد البيانات</a> database management systems تختصر إلى DBMS بتعمق كبير فهي مدخل إلى التعامل مع البيانات والتلاعب بها وتطويها والغوص فيها لاستخراج المعلومات. قد يتفرد هذا المجال في تخصص بمفرده في الدراسات العليا أو حتى في سوق العمل، فقد تطلب بعض الشركات متخصص لإدارة قواعد بياناتها وله المسمى الوظيفي "مدير قواعد بيانات" Database Administrator.
</p>

<p>
	وتشمل مشاريع تحليل البيانات عادة:
</p>

<ol>
	<li>
		جمْع البيانات من مصادرها.
	</li>
	<li>
		تنظيف وتهيئة البيانات للمعالجة وإزالة القيم الشاذة.
	</li>
	<li>
		إدخال البيانات في الأنظمة الحاسوبية المطلوبة لاستخراج النتائج والمعلومات الأولية منها، ومن أين يُبدَأ في البحث عن روابط مفيدة بين أجزائها.
	</li>
	<li>
		تحليل أعمق للبيانات إما عبر أنظمة أكثر تقدمًا أو عبر تَعلّم الآلة، وقد تُستعمل أنظمة التعرف على الأنماط Pattern Recognition كذلك.
	</li>
	<li>
		تهيئة النتائج السابقة للعرض والمشاركة عبر بعض الأدوات الشهيرة.
	</li>
	<li>
		عرض النتائج والتقارير مع المخططات والتوصيات.
	</li>
</ol>

<p>
	وتعد بايثون أكثر لغات <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">البرمجة</a> طلبًا في هذا المجال، بالإضافة لمكتباتها الشهيرة مثل Pandas وNumpy وJupyter Notebook وMatplotlib وغيرها، وكذلك تستعمل لغة R في هذا المجال، ولكنها ليست بنفس شيوع بايثون، أما بالنسبة لقواعد البيانات، فيجب أن تقن <a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/sql/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-sql-r844/" rel="">لغة SQL</a> وتتقن بعدها أنظمة التعامل مع قواعد البيانات.
</p>

<p>
	ولتَتعلّم أساسيات بايثون بسهولة، بإمكانك الاطّلاع على كتاب <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">البرمجة بلغة بايثون</a> كما يمكنك الاطلاع على كتاب <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/files/16-%D9%85%D9%84%D8%A7%D8%AD%D8%B8%D8%A7%D8%AA-%D9%84%D9%84%D8%B9%D8%A7%D9%85%D9%84%D9%8A%D9%86-%D8%A8%D9%84%D8%BA%D8%A9-sql/" rel="">ملاحظات للعاملين بلغة SQL</a> وكتاب <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/files/18-%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D8%A5%D9%84%D9%89-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql/" rel="">الدليل العملي إلى قواعد بيانات PostgreSQL</a>.
</p>

<h3>
	7. أنظمة التشغيل والأنظمة المدمجة
</h3>

<p>
	تحتاج جميع الحواسيب والهواتف الذكية والأجهزة الإلكترونية عمومًا إلى نظام تشغيل Operating System لتعمل وفق رغبات المستخدم، وهذه الأنظمة هي الأخرى لا تأتي من العدم بل هناك متخصصون لبرمجتها وجعلها أفضل من غيرها والحفاظ عليها مع الزمن.
</p>

<p>
	تطوير أنظمة تشغيل سطح المكتب مثل ويندوز وماك ولينكس، أو أنظمة الهواتف الذكية مثل نظام أندرويد ونظام iOS وغيرهما، هي مجالات برمجية متقدمة تعتمد على خبرات ومهارات متعددة، كما يعتمد هذا على العتاد Hardware الذي ترغب ببناء نظام تشغيل له، وقد تُستخدَم أكثر من لغة برمجية في الوقت نفسه لتطوير نظام تشغيل بسيط، فتطوير أنظمة التشغيل عملية عملاقة ومكلفة وتحتاج الكثير من المهندسين، كما ينفق عليها ملايين الدولارات من الاستثمار المستمر على امتداد عدة سنوات للخروج بنتائج مرضية، ولهذا ربما تجد أن هناك ملايين البرمجيات الصغيرة حول العالم، بينما يوجد ثلاث أنظمة شهيرة لسطح المكتب ونظامان للهواتف الذكية فقط، ورغم أنه هناك بالفعل العشرات غيرها إلا أنها محدودة وضعيفة المزايا موازنة بتلك الأكثر استخدامًا والأكبر دعمًا حاليًا؛ وذلك لأن مطوريها لا يمتلكون نفس موارد وإمكانات مطوري الأنظمة الشائعة ذات الدعم الكبير.
</p>

<p>
	أما الأنظمة المدمجة Embedded Systems فهي الأنظمة التي تعمل مع موارد عتاد Hardware Resources محدودة للغاية، فهي تُنفّذ مهامًا محدودةً وصغيرةً مثل أنظمة الإشارات والاستشعار والأقفال الإلكترونية وألعاب الأطفال وحتى أنظمة إدارة السدود المائية وأنظمة الأجهزة العسكرية …إلخ، كما أن برمجتها مجالٌ منفصلٌ لوحده، ويوجد به الكثير من التفرعات كذلك وهو علم ضخم ذاع صيته هذه الأيام وأهم مجال تفرع عنه هو مجال إنترنت الأشياء Internet of Things تختصر إلى IoT وهي برمجة العتاد مع ربطه بالإنترنت مثل أنظمة مراقبة المباني وأقفالها وأنظمة البيوت الذكية وغيرها. أصبحت هنالك برامج واختصاصات دراسات عليا وحتى درجات جامعية تُدرِّس هذا المجال.
</p>

<h3>
	8. الأمان الرقمي
</h3>

<p style="text-align: center;">
	<img alt="تخصص-الأمان-الرقمي-في-علوم-الحاسوب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="77484" data-unique="tb58i97lw" style="" src="https://academy.hsoub.com/uploads/monthly_2021_09/614b243e0b440_-----.jpg.396d2eaca1b8d86f00ec856703bb0f59.jpg">
</p>

<p>
	الأمان الرقمي مجال كبير تنضوي تحته عدة أمور، مثل أنظمة التشغيل والبرمجيات العادية والشبكات والتعمية وغيرها، فكلها أمور مترابطة تحتاج لتأمين واستخدام أفضل للتقنيات وذلك للتأكد من عدم وصول الأشخاص غير المخوّلين لها.
</p>

<p>
	وبينما هناك مجالاتٌ متعلقةٌ بالأمان الرقمي الشخصي للمستخدمين، هناك مجالاتٌ متعلقةٌ بالأمان الرقمي الجنائي أو العسكري بين المجرمين وأجهزة الشرطة وبين الدول وبعضها البعض، كما أن هناك مجالاتٌ متعلقةٌ بالشبكات وإدارة الخوادم وغير ذلك الكثير، وكلها أمورٌ يمكن أن تتخصص بها إذا رغبت بذلك.
</p>

<p>
	ولمعلومات مفيدة حول الأمان الرقمي الشخصي والخصوصية، اطلع على كتاب <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/files/20-%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%86-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A/" rel="">دليل الأمان الرقمي</a>.
</p>

<h3>
	9. الحوسبة العلمية
</h3>

<p>
	تعتمد العديد من الصناعات التي تراها حولك اعتمادًا أساسيًا على علم الحاسوب لإتمام مهامها بنجاحٍ، فأغلب ما تراه حولك قد عولج في الحاسوب بدءًا من البناء الذي تقطنه والذي قد صمم واختُبر باستعمال برامج حاسوبية صممت البناء ونمذجته واختبرته على الزلازل ومختلف العوامل للتأكد منه ومن تصميمه وحتى قطع وقطع البلاستيك وأجزاءها قد صممت أيضًا باستعمال برامج حاسوبية عملاقة وهكذا، وكل هذه البرامج تعمل بخوارزميات ضخمة تحتاج للكثير من العمليات الرياضية التي تحل معادلات مختلفة، وهي بدورها تعتمد على خوارزميات محددة لتبسيطها وحسابها وهذا ما يدخل ضمن مجال <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://ar.wikipedia.org/wiki/%D8%AD%D9%88%D8%B3%D8%A8%D8%A9_%D8%B9%D9%84%D9%85%D9%8A%D8%A9" rel="external nofollow">الحوسبة العلمية</a> Scientific computing.
</p>

<p>
	كما توجد مجالات كثيرة أخرى مثل هذه لا مجال لحصرها الآن ولكن نذكر منها مجال الحوسبة التطورية Evolutionary Computation وهي العلم الذي يأخذ نظرية التطور والحالات المعقدة المتطورة ويحولها إلى نظام قابل لحل الكثير من المشاكل في الحياة الواقعية، فيمكن استخدام هيكلة ومبادئ نظرية التطور لتطوير خوارزمية تساعدنا على معرفة عدد المطارات والمدارج التي علينا وضعها في كل مدينة.
</p>

<h3>
	10. الحوسبة السحابية
</h3>

<p>
	توفر الآن الكثير من الشركات خدمات سحابية Cloud Services للمستخدمين وفكرة الحوسبة السحابية Cloud computing ببساطة إلغاء العمل على نظام تشغيل سطح المكتب لتخزين وتشغيل وإدارة الخدمات والبرامج التي تريدها والاعتماد كليًا على خدمات بعيدة موجودة على حواسيب وخوادم مركزية عملاقة تستفيد من الإنترنت للوصول إليها لفعل نفس الأمور السابقة.
</p>

<p>
	فمثلًا بدلًا من تشغيل خادم قاعدة البيانات الخاص بك يمكنك الاعتماد على أحد الحلول الجاهزة من أمازون Amazon أو ديجيتال أوشين Digital ocean، كما يمكنك استعمال فيجوال ستوديو من مايكروسوفت عبر الإنترنت لأداء مهامك البرمجية بدلًا من استخدام مُحرر النصوص البرمجي الخاص بك على نظامك.
</p>

<p>
	ويمكنك كذلك أن تستأجر خوادم فيزيائية Dedicated Servers ثم تُقسّمها إلى خوادم افتراضيةٍ Virtual Servers وتُوزّعها على مستخدمين آخرين حسب الموارد، ثم تُوّفر لهم خدمات جاهزة Software-as-a-Service واختصارًا SaaS، وهذا هو مبدأ شركات الاستضافة الحديثة والمجال السائد فكل ما تراه أصبح مخزنًا وموجودًا على سحابة وتصل إليه أو تستعمله عبر الإنترنت لذلك زاد الطلب على متخصصين في هذا المجال وتكون المسميات الوظيفية باسمه عادة مهندس حوسبة سحابية Cloud Computing Engineer.
</p>

<h3>
	11. تخصصات أخرى
</h3>

<p>
	هناك مجالات ضمن علم الحاسوب تبتعد عن العلوم التطبيقية البرمجية، وتبحث في المبادئ النظرية لما تقدمه علوم الحاسب للتخصصات والمجالات الأخرى في الحياة.
</p>

<ul>
	<li>
		نظرية المعلومات Information Theory وتتحدث عن المبادئ النظرية لنقل المعلومات الرقمية ومحتواها، وإلى أي مدى يمكن ضغطها وبأي سرعاتٍ يمكن الوصول إليها.
	</li>
	<li>
		نظرية الإشارات Signal Theory وتتحدث عن الإشارات التي تُصدِرها الكائنات الحية وكيف يمكن تحديد العلاقات بينها وكيفية نمذجتها في الأنظمة الرقمية بهدف دراستها وتحليلها.
	</li>
	<li>
		نظرية الفوضى Chaos Theory ورغم أنها نظريةٌ رياضيةٌ لا تنضوي تحت علوم الحاسوب بصورةٍ مباشرةٍ، إلا أن لها تطبيقاتٌ واضحةٌ في عِدّة مجالاتٍ مثل حالة الطقس والمناخ والأنظمة المصممة لتوقّعها والتبليغ عنها، فهي تعتمد على علوم حاسوبية مثل التعمية والروبوتات وغيرها.
	</li>
	<li>
		<a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/devops/linux/%D8%AA%D9%82%D9%86%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B9%D9%8A%D9%85%D8%A9-cryptography-%D9%88%D8%A7%D9%84%D8%AA%D8%B4%D9%81%D9%8A%D8%B1-encryption-%D9%88%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D8%A7%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D9%84%D9%8A%D9%86%D9%83%D8%B3-r236/" rel="">علم التعمية Cryptography</a> وهو واحدٌ من أكثر العلوم أهمية في علوم الحاسب لأن تطبيقاته هي التي تسمح بتشفير البيانات، ويعتمد على المبادئ الرياضية بشدةٍ، كما أنه شديد التعقيد، حيث تقوم عليه أنظمة الأمان الرقمية حول العالم بما في ذلك الأنظمة الاقتصادية.
	</li>
</ul>

<p>
	والكثير من هذه العلوم هي علوم نظرية تعتمد على مجالات متداخلة Interdisciplinary مع علوم الحاسبات، إلا أن علوم الحاسبات مركزية وأساسية فيها.
</p>

<h2 id="كيف-أختار-التخصص-المناسب-لي-من-تخصصات-علوم-الحاسوب">
	كيف أختار التخصص المناسب لي من تخصصات علوم الحاسب؟
</h2>

<p style="text-align: center;">
	<img alt="اختيار-تخصص-علوم-الحاسب-المناسب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="77481" data-unique="1l5ker4j6" style="" src="https://academy.hsoub.com/uploads/monthly_2021_09/614b243c49922_----.jpg.9e975a079af171d1b24b7bc685b93a94.jpg">
</p>

<p>
	ليست كل التخصصات السابقة الذكر متوفرة في مجالات علوم الحاسب بالطبع، فهناك غيرها ولكن ذكرنا الأشيع والأشهر منها، ويبرز هنا سؤال وهو كيف يمكن لداخل جديد إلى هذه العلوم أن يختار التخصص المناسب له والذي يحبه؟
</p>

<p>
	وتكمن الإجابة في معرفة المرء بنفسه وأين يحب أن يعمل فإذا كنت تحب الرياضيات فربما تناسبك العلوم النظرية، وإذا كنت تحب العمل مع الخوارزميات وتطوير الجديد منها لتسريع حل مشكلات الجنس البشري وابتكار حلول أفضل فربما قد يكون هذا اختصاصك، أو ربما ببساطة تحب <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7%D8%AA/" rel="">تطوير البرمجيات</a> والتطبيقات وحينها لن تحتاج شيئًا أكثر من المعارف الأساسية في علوم الحاسب ثم التخصص في <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/general/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>.
</p>

<p>
	لذا عليك أن تنظر في هذه المجالات المختلفة، ثم تسأل نفسك في أي منها يمكن أن تعمل دون أن تشعر بالملل بعد فترة؟ وستجد بضع مجالات قد تعجبك وستستبعد بعض المجالات الأخرى، فمثلًا أنا أستبعد أن أعمل في المجالات الرياضية أو مجالات التشفير، ببساطة لأنني لا أحب تعقيدها، وبعدها حاول أن تصرف بعض الساعات من وقتك في هذه المجالات التي تبقّت معك لتتعرّف عليها وترى أبرز المشاريع الموجودة فيها، وهل أحسست براحة وانشراح للنفس أثناء دراستها والعمل فيها، أم أنك تريد غيرها؟
</p>

<p>
	الخلاصة، جرب التخصص والقراءة الدراسة في كل تخصص فترة من الزمن وبعدها إما أن تكمل أن تنتقل إلى تخصص آخر وهكذا تعرف الاختصاص الصحيح المناسب لك، وبعد فترة ستجد مجالات واضحة معينة لن تحب العمل في غيرها، وتلك هي المجالات التي يمكنك البدء بدراستها والتخصص بها بعد أن تنتهي من دراسة علوم الحاسوب الأساسية.
</p>

<h2 id="التوظيف-وفرص-العمل-في-مجال-علوم-الحاسوب">
	التوظيف وفرص العمل في مجال علوم الحاسب
</h2>

<p>
	تقل أهمية الشهادة الجامعية تدريجيًا في التوظيف عندما يتعلق الأمر بعلوم الحاسوب فشركات مثل جوجل بدأت تهتم بالخبرة وتعمل على نشر شهاداتها الخاصة والتي تبلغ مدتها 6 أشهر في حال عدم وجود الشهادة الجامعية، كما أن كثيرًا من الشركات الأخرى تشترط وجود الخبرة ومعرض الأعمال بدلًا من الشهادة الجامعية للمتقدِّم.
</p>

<p>
	وتبلغ مدة أغلب الشهادات الجامعية في معظم البلدان 4 سنوات، وهي مدةٌ طويلةُ جدًا يذهب معظمها بالانتظار والفراغ بين الحصص الدراسية الأسبوعية وتعلم علوم ومواد قد لا يكون لها أهمية كبيرة وقد تنساها بعد التخرج هذا لم نتحدث عن قلة المقاعد الدراسية الحكومية المجانية والمنافسة الشديدة عليها أو غلاء الجامعات الخاصة مما يزيد من العوامل التي تعيق أصلًا دخول الجامعة أو اختيار التخصص الذي ترغب دراسته في الجامعة فقد تضطر من أجل الدخول للجامعة والحصول على درجة جامعية أن تدرس تخصصًا لا تحبه ولا يناسبك أصلًا وهنا الحديث يطول، على أي حال، وبما أن علوم الحاسوب مجال مرتبط بالحواسيب التي بين أيدينا فقد لجأت نسبة لا بأس بها ممن يرغبون التخصص في المجال بتعلم المعلومات المطلوبة من مصادر خارجية لا علاقة لها بالجامعات الأكاديمية، دون الحاجة للدراسة الجامعية التقليدية ودخلوا سوق العمل فعليًا.
</p>

<p>
	ولا نريد محو أهمية الشهادات الجامعية، وذلك لأنها ما تزال تطلبها الحكومات والدول رسميًا للعمل في الوظائف الحكومية، كما لا تزال لها سمعة في الأوساط الاجتماعية على عكس من يتعلم تلك العلوم بمفرده، ولكن إذا كانت المعرفة والعمل ما يهمك فقط فحينها لا مشكلة من الخوض في المجال بعيدًا عن الدراسة الجامعية، وبذلك تكسب سنوات من عمرك بالإضافة إلى توفير الكثير من المال الذي كنت ستصرفه على الشهادة الجامعية. فمثلًا، يمكنك خلال فترة تترواح من ستة أشهر إلى سنة أن تتعلم أساسيات علوم الحاسوب وأن تبدأ العمل فيها مثلًا أن تتخصص في البرمجة وتطوير المواقع وتدخل سوق العمل وأغلب الدورات الحرة التي تعلم الاختصاص تكون مدتها ستة أشهر وحتى السنة وهي كافية لوضع قدمك على الطريق ودخول وكسب فرصة عمل.
</p>

<p>
	فمؤسسي أكبر الشركات التقنية في العصر الحديث، مثل مارك زوكيربيرغ مؤسس فيسبوك، وجاك دورسي مؤسس تويتر، وستيف جوبز مؤسس آبل <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://www.businessinsider.com/mark-zuckerberg-steve-jobs-tech-executives-never-graduated-college-dropouts-2019-5" rel="external nofollow">لم يتخرجوا من الجامعات</a>، وكذلك فهناك غيرهم الكثير من مدراء ورؤساء الشركات التقنية، ولهذا لن تكون الشهادة الجامعية عائقًا أمامك في حال أردت سلوك نفس المسار العصامي. وهنالك الكثير من المبرمجين الماهرين اليوم الذين لم يدخلوا إلى الجامعة أو درسوا اختصاصًا مختلفًا وهم يعملون في شركات كبيرة منها شركة IBM وهو لا يملك درجة في أي تخصص من تخصصات الحاسب وحتى أنه يساهم في كتابة بحث مع من درس في أروقة الجامعات.
</p>

<p>
	أضف إلى ذلك أنه يمكنك العمل كعامل مستقل على حسب الاختصاص الذي تجيده من اختصاصات علوم الحاسوب؛ فلو كنت مطور ويب محترف فيمكنك تطوير المواقع الإلكترونية للعملاء عبر مواقع العمل الحر مثل <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://mostaql.com" rel="external">مستقل</a>، ففي العمل الحر لن يسألك أحد بتاتًا عن شهادتك الجامعية وكل ما سيسألونك عنه هو خبراتك ونماذج لأعمالك السابقة نفذتها لا أكثر.
</p>

<p>
	أما عن فرص العمل المتوفرة في الشركات فهي تختلف باختلاف البلدان والشركات التي تريد العمل فيها، ولكنها تنضوي جميعًا تحت قسم التخصصات الذي تحدثنا فيه بصورة موسعة عن تخصصات علوم الحاسوب التي يمكن للمرء الاختصاص فيها، فمثلًا يمكنك العمل بتخصص مهندس برمجيات أو يتخصص في مجال الذكاء الاصطناعي أو مطور أنظمة تشغيل …إلخ على حسب المسميات الوظيفية المتوفرة في الشركات.
</p>

<p>
	انظر مثلًا إلى <a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://baaeed.com/categories/remote-programming-jobs" rel="external nofollow">موقع بعيد</a>، حيث تجد فيه طلبات توظيف من شركات مختلفة حول العالم العربي، وستجد أن معظم الوظائف لا تشترط أي نوع من أنواع الشهادات، بل تشترط معرض أعمال وخبرة سابقة فقط.
</p>

<p>
	وتكون رواتب المتخصصين في علوم الحاسوب متعلقة بعدة عوامل منها التخصص والخبرة والأعمال المنجزة وكذلك باختلاف الشركات والأماكن والدول، لكن يمكننا القول بصورة عامة أن رواتبهم أعلى من المهندسين الآخرين، ويمكنك البحث عن المواقع التي تَعرِض لك متوسط الرواتب التي يتلقاها الموظفون حسب المهنة في بلدك ثم البحث فيها عن التخصصات السابقة لرؤية مُعدّل الرواتب في بلدك.
</p>

<h2 id="الفرق-بين-علوم-الحاسب-وهندسة-الحاسب">
	ما الفرق بين علوم الحاسب وهندسة الحاسب؟
</h2>

<p>
	على عكس الشائع فلا يوجد فرق جوهري بين علوم الحاسب computer science وهندسة الحاسب computer engineering وذلك لأن الجامعات الموجودة في دول مختلفة حول العالم تتعامل مع المصطلحين بطريقة مختلفة، فتجد في بعض الجامعات وفي بعض البلدان أن التخصصين مجرد اسمين مختلفين لنفس المواد الجامعية، فمثلًا الجامعة التي تخرجت منها كان تخصصي فيها هو هندسة وعلوم الحاسوب، أي أنني درست الاثنين معًا، ولم يكن هناك فرق في المواد التي درسناها مع الجامعات الأخرى.
</p>

<p>
	أما في بعض البلدان الأخرى مثل الولايات المتحدة هناك فرق حيث تكون علوم الحاسب علومًا أقرب للأقسام النظرية والفهم العام لمختلف المجالات والتخصصات، بينما تركز هندسة الحاسوب بالتحديد على علوم البرمجيات Software وعلوم العتاد Hardware والعلاقات والمشاريع التي يمكن تنفيذها بالدمج بينهما، أي أن هندسة الحاسوب تخصص هندسي تقليدي أقرب للعلوم العملية من تخصص علوم الحاسوب الأقرب للعلوم النظرية المفاهيمية.
</p>

<p>
	ويُعَد مصطلح علوم الحاسوب مصطلحًا جديدًا نسبيًا إذ كان التركيز قديمًا على <span ipsnoautolink="true">هندسة البرمجيات</span> Software Engineering وهندسة الحاسوب Computer Engineering وشاع المصطلح بعد 2010م وصار يشمل كل هذه العلوم وأكثر.
</p>

<h2 id="من-أين-أبدأ-بتعلم-علوم-الحاسوب">
	من أين أبدأ بتعلم علوم الحاسوب؟
</h2>

<p>
	إن كنت تفكر بالدراسة الجامعية الأكاديمية، فهي من سيرشدك للبدء ويوفر لك المواد المتسلسلة في سنوات الدراسة ويؤمن لك كل شيء خلال رحلتك في دراسة علوم الحاسب وتخصصاته أما إن كنت ممن يريد دراسة مجال علوم الحاسوب ذاتيًا والتخصص فيه دون اللجوء إلى الجامعة، فأنت في المكان الصحيح الذي سيرشدك إلى بداية الطريق.
</p>

<p>
	من الأفضل لك أن تبحث عن بعض الدورات المتكاملة للبدء في تعلم علوم الحاسب بدلًا من الدروس المتفرقة، فمن الصعب على طالب جديد لا يعرف شيئًا في المجال أن يدخل فيه مباشرةً ويتعلم ما يحتاج إليه من دروس في كل مادة وتخصص من تلك المواد والتخصصات، بينما الدورات المتكاملة تكون مجهزة وكاملة وفق خطة معينة من متخصصين.
</p>

<p>
	عملت أكاديمية حسوب على توفير دورة متكاملة عن أساسيات علوم الحاسب هي <a href="https://academy.hsoub.com/store/7-%D8%AF%D9%88%D8%B1%D8%A9-%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">دورة علوم الحاسوب</a> وهي دورة شاملة مدتها عشرات الساعات حول علوم الحاسوب بدءًا من أبسط الأساسيات وصولًا إلى الخوارزميات وهياكل البيانات والبرمجة وقواعد البيانات وتطوير الويب وإدارة الخوادم، كما أنها تحت التوسيع والتحديث المستمر، ومن أبرز ميزاتها أن هناك من يتابع سَيْرَك ويجيب على أسئلتك على امتداد الدورة وليست فقط مجرد فيديوهات.
</p>

<p style="text-align: center;">
	<iframe allowfullscreen="" data-ss1625151558="1" data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1632300990="1" data-ss1632301679="1" data-ss1632314633="1" data-ss1633010598="1" data-ss1635004318="1" frameborder="0" height="450" src="https://player.vimeo.com/video/409436178" width="800"></iframe>
</p>

<p>
	ستكون مؤهلًا بعد الدورة من التخصص والغوص في إحدى مجالات علوم الحاسب التي تحبها وتريد تعلمها وقد وفرت الأكاديمية بعد دورة علوم الحاسب دورات أخرى إن أحببت الاختصاص في مجال البرمجة وتطوير البرمجيات لإكمال طريقك وستكون جاهزًا لدخول سوق العمل وبدء الكسب مما تعلمت خلال فترة قصيرة لا تتجاوز السنة بناءً على همتك وعزيمتك.
</p>

<p>
	وإذا وصلت إلى مرحلة أنت جاهزٌ فيها لتَعلّم البرمجة، فيمكنك قراءة <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://hausaba.com/learn-programming-arabic/" rel="external nofollow">الدليل الشامل لتعلم البرمجة باستخدام المصادر العربية</a> ففيه أبرز المصادر العربية المتوفرة في الشبكة لتعلم البرمجة.
</p>

<p>
	كما يمكنك البحث في الشبكة عن سلاسل فيديوهات أو كتب لتُعلّمك تخصص علوم الحاسب بأي لغةٍ تجيدها، وجوجل مليءٌ بالنتائج عن ذلك كما أن أكاديمية حسوب تعمل جاهدًا على توفير مراجع عالية الجودة لتساعدك في ذلك، فتابع دومًا قسم <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/" rel="">المقالات البرمجية</a> وقسم <a data-ss1631871812="1" data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/files/c5-programming/" rel="">الكتب البرمجية</a>.
</p>

<h2>
	خاتمة
</h2>

<p>
	وصلنا إلى نهاية هذا المقال بعد أن اطلعنا على أبرز علوم الحاسب وماهية التخصصات الموجودة فيه، ولا تنسَ أن هذا المقال مجرد مقدمة وسيكون عليك صَرْف العديد من الساعات لتتعلّم هذا المجال وتغوص فيه بصورة أعمق.
</p>

<p>
	وصحيح أن تعلم علوم الحاسوب قد يكون صعبًا في البداية للوافدين الجدد عليه، ولكن النتيجة مثمرةٌ جدًا حيث يمكنك استخدام أحد أبرز العلوم في العصر الحديث وأهمها لأي غرض أو هدف تريده، سواء كان ذاك الهدف شخصيًا أو ماديًا بهدف الكسب والرزق.
</p>

<p>
	إن كان لديك أي سؤال أو استفسار، فلا تتردد بطرحه في التعليقات ونسعد بمشاركتنا تجربتك، أرجو لك التوفيق والسداد!
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/general/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">دليلك الشامل لتعلم البرمجة</a>
	</li>
	<li>
		<a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/advance/%D8%AF%D9%84%D9%8A%D9%84-%D8%B4%D8%A7%D9%85%D9%84-%D8%B9%D9%86-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-r1247/" rel="">دليل شامل عن تحليل تعقيد الخوارزمية</a>
	</li>
	<li>
		<a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">المرجع الشامل إلى تعلم لغة بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%81%D9%88%D8%A7%D8%A6%D8%AF-%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">ما هي فوائد تعلم البرمجة؟</a>
	</li>
	<li>
		<a data-ss1631878306="1" data-ss1631956191="1" data-ss1631956247="1" data-ss1635004318="1" href="https://academy.hsoub.com/files/17-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A-%D9%88%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A2%D9%84%D8%A9/" rel="">مدخل إلى الذكاء الاصطناعي وتعلم الآلة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1321</guid><pubDate>Wed, 22 Sep 2021 13:09:00 +0000</pubDate></item><item><title>&#x623;&#x645;&#x62B;&#x644;&#x629; &#x639;&#x645;&#x644;&#x64A;&#x629; &#x644;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x648;&#x627;&#x62C;&#x647;&#x629; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x645;&#x62A;&#x627;&#x62C;&#x631; &#x632;&#x62F; Zid API</title><link>https://academy.hsoub.com/programming/general/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D9%84%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AA%D8%A7%D8%AC%D8%B1-%D8%B2%D8%AF-zid-api-r1319/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_09/614427aca2836_.png.736615fcda55b755ca15199b4f02e535.png" /></p>

<p>
	تعرفنا في المقال اﻷول على <a data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">الواجهة البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> </a> وكيفية استعمالها في تطوير المواقع وتطبيقات الويب على ماهية الواجهات البرمجية وأسس عملها ولماذا نحتاج إليها، وتعلمنا في المقال الثاني، المعنون بـ <a data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api-%D9%88%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-%D9%88%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D8%AD-r1318/" rel="">الاتصال بواجهة برمجة التطبيقات <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> وفهم عملية الاستيثاق والتصريح</a> كيفية الاتصال بالواجهة البرمجية بصورة صحيحة، وأخذنا مثاﻻ عن ذلك باستخدام الواجهة البرمجية لمنصة زد، وإن كنت تتبعت جميع الخطوات التي ذُكرت في المقالين السابقين، فسنفترض اﻵن أن لديك حساب مطور على منصة زد وأيضا متجر للتجربة عليه أو عد إليهما ثم أكمل بعدهما قراءة هذا المقال.
</p>

<p>
	هذا المقال هو جزء من سلسلة مقالات حول الواجهة البرمجية <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> وكيفية الاستفادة منها في بناء تطبيق ويب:
</p>

<ol>
<li>
		<a data-ss1631885755="1" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">مدخل إلى الواجهات البرمجية <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a>
	</li>
	<li>
		<a data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api-%D9%88%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-%D9%88%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D8%AD-r1318/" rel="">الاتصال بواجهة زد البرمجية وفهم عملية الاستيثاق والتصريح</a>
	</li>
	<li>
		أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>
	</li>
	<li>
		<a data-ss1631885755="1" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/javascript/nodejs/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%8A%D8%B2%D9%8A%D8%AF-%D9%85%D9%86-%D8%A7%D8%AD%D8%AA%D9%81%D8%A7%D8%B8-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D8%A7%D8%A1-%D8%B9%D8%A8%D8%B1-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%B2%D8%AF-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1320/" rel="">تطوير تطبيق عملي يزيد من احتفاظ العملاء عبر واجهة زد البرمجية</a>
	</li>
</ol>
<h2>
	متطلبات مسبقة
</h2>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		ملحوظة: جميع نقاط الوصول Endpoints التي ستُستخدم في هذا المقال موجودة بكل تفاصيلها في <a data-ss1631886114="1" data-ss1631887115="1" href="https://portal.zid.dev/devportal/apis/69291bae-dfbc-4475-bb6b-b67ea53f0d76/test" rel="external nofollow">التوثيق الرسمي الخاص بمنصة زد</a> وشرحنا في المقال السابق من هذه السلسلة كيفية بدء استعمال وتوليد مفاتيح الوصول المساعدة الخاصة بك. كل التجارب التي سننفذها ستكون باستخدام برنامج Insomnia الذي شرحنا طريقة تنزيله واستعماله أيضًا في المقال السابق.
	</p>
</blockquote>

<p>
	حتى تستطيع العمل بجميع التجارب، يجب عليك الحصول على كل من مفتاح الوصول Access Token وهو المفتاح المساعد الخاص بحسابك كمطور، وأيضا مفتاح المتجر X-Manager-Token وهو المفتاح المساعد الخاص بالمتجر المنشود الذي ستطبق عليه العملية.
</p>

<p>
	يمكنك جلب مفتاح الوصول بعد تفعيل <a data-ss1631886114="1" data-ss1631887115="1" href="https://portal.zid.dev/devportal/applications" rel="external nofollow">تطبيقك</a> في منصة تطور زد للمطورين أما بخصوص مفتاح المتجر المساعد، فيمكنك جلب واحد من متجر حقيقي منشور أو تجريبي تنشئه بغرض التجربة ولكن يفضل استخدام متجر تجريبي حتى ﻻ يتأثر متجرك الفعلي بأية عمليات تجريبية سنطبقها في هذا المقال (انظر مقال <a data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/apps/web/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%AA%D8%AC%D8%B1-%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-%D9%85%D8%AA%D9%83%D8%A7%D9%85%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%85%D9%86%D8%B5%D8%A9-%D8%B2%D8%AF-r440/" rel="">كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد</a>).
</p>

<p>
	لن أذكر أنك تحتاج لكل من مفتاح الوصول Access Token ومفتاح المتجر X-Manager-Token واللغة في جميع التجارب التي سنجريها على نقاط وصول الواجهة البرمجية ﻷنها مطلوبة في ترويسات الطلبيات كلها دون استثناء.
</p>

<h2>
	استعراض العملاء
</h2>

<p>
	توفر واجهة زد البرمجية إمكانية استعراض العملاء عبر إرسال طلب HTTP من النوع GET إلى نقطة الوصول التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_959_9" style="">
<span class="str">/managers/</span><span class="pln">store</span><span class="pun">/</span><span class="pln">customers</span></pre>

<p>
	تستعمل نقطة الوصول هذه لاستعراض بيانات عملاء المتجر الذي حددناه بالمفتاح X-Manager-Token المرسل مع الطلبية وتذكر دومًا أننا سنرسل مع الطلبية متفاح المتجر ومفتاح الوصول مع الطلبية حتى لو لم نذكر ذلك صراحةً.
</p>

<p>
	المعلومات المطلوبة:
</p>

<ul>
<li>
		page: ويعني كم من صفحة تريد استعراضها
	</li>
	<li>
		per_page: عدد العملاء المراد استعراضهم في الصفحة الواحدة
	</li>
</ul>
<p>
	هذه المعلومات نحتاجها في جميع طلباتنا القادمة، وهي تخص ترقيم الصفحات Pagination لترتيب البيانات في واجهة المستخدم بتنسيق مقبول التي نحصل عليها والتي قد تكون بيانات آلاف العملاء.
</p>

<p>
	حسب التوثيق، فإنها ترسل مثل استعلام Query، وبالتالي الطلب سيكون كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77178" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/List_Customers_Request.png.236a28780a9266ea7d184f4df3d54a68.png" rel=""><img alt="List_Customers_Request.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77178" data-unique="79pq1kqm8" src="https://academy.hsoub.com/uploads/monthly_2021_09/List_Customers_Request.png.236a28780a9266ea7d184f4df3d54a68.png"></a>
</p>

<p>
	سنرسل الطلب بهذا الشكل للواجهة البرمجية لمنصة زد، وننتظر إجابة الخادم Response والتي ستكون كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77179" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/List_Customers_Response.png.743d7e7c8209cc44d45b868bcb11e70e.png" rel=""><img alt="List_Customers_Response.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77179" data-unique="tmf0ucsms" src="https://academy.hsoub.com/uploads/monthly_2021_09/List_Customers_Response.thumb.png.e7c4850e6f731dea50e2842ebe633d41.png"></a>
</p>

<p>
	نلاحظ أن الرد يحوي على مفتاح Key تحت اسم customers ونوعه مصفوفة، وفي حالتنا هذه، مصفوفة فارغة ﻷن متجرنا التجريبي ﻻ يحوي عملاء مسجلين فيه.
</p>

<h2>
	إضافة منتج جديد
</h2>

<p>
	توفر واجهة زد البرمجة إمكانية إضافة منتج جديد إلى المتجر المحدد بالمفتاح المرسل عبر إرسال طلبية إلى نقطة الوصول التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_959_11" style="">
<span class="pun">/</span><span class="pln">products</span></pre>

<p>
	المعلومات المطلوبة في الترويسة:
</p>

<ul>
<li>
		STORE_ID: وهو الرقم التعريفي الخاص بالمتجر خاصتك، ستحصل على الرقم التعريفي الخاص بالمتجر من نفس الصفحة التي حصلت منها على مفتاح المتجر X-MANGER-TOKEN
	</li>
	<li>
		ROLE: وهو السماحية الخاصة بك، ويمكن أن تأخذ القيمة Manager أي المدير، أو Customer أي عميل، في حالتنا سنحتاج إلى استخدام السماحية Manager.
	</li>
</ul>
<p>
	أما جسم الطلب Request Body فيجب أن يحوي المعلومات التالية:
</p>

<ul>
<li>
		cost: وتعني التكلفة ويجب أن تكون سلسلة نصية string
	</li>
	<li>
		quantity: الكمية ويجب أن تكون سلسلة نصية string
	</li>
	<li>
		keywords: الكلمات المفتاحية ويجب أن تكون مصفوفة من السلاسل النصية
	</li>
	<li>
		name: الاسم، ويكون كائن Object يحوي مفتاحين ar و en
	</li>
	<li>
		description: التوصيف ويجب أن يكون كائنًا يحوي مفتاحين ar و en
	</li>
	<li>
		price: السعر ويكون سلسلة نصية
	</li>
	<li>
		sale_price: سعر البيع ويكون سلسلة نصية
	</li>
	<li>
		weight: الوزن، ويكون كائنا يحوي على مفتاحين unit ويعني وحدة القياس، و value وهي القيمة
	</li>
	<li>
		Is_published: و يجب أن يكون بولياني Boolean، وبالتالي إما True أو False، وتعني هل المنتج معروض للشراء أم ﻻ.
	</li>
</ul>
<p>
	سنضيف منتجًا جديدًا عن طريق إرسال طلب باستخدام برنامج Insomnia، وسيكون من نوع Post كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77173" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Create_Product_Request_Headers.png.832b14cfae6daf780cf51931d23046aa.png" rel=""><img alt="Create_Product_Request_Headers.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77173" data-unique="7ulz0rish" src="https://academy.hsoub.com/uploads/monthly_2021_09/Create_Product_Request_Headers.png.832b14cfae6daf780cf51931d23046aa.png"></a>
</p>

<p>
	توضح الصورة التالية نموذج عن جسم الطلبية المرسل بصيغة json:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77172" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Create_Product_Request_Body.png.6f2c5a1e462962cae0682a81000b1e24.png" rel=""><img alt="Create_Product_Request_Body.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77172" data-unique="kmfec8j2c" src="https://academy.hsoub.com/uploads/monthly_2021_09/Create_Product_Request_Body.thumb.png.442c0667c7ec966d7a92268fed062ba2.png"></a>
</p>

<p>
	إن كانت كل المعلومات المطلوبة صحيحة، فسيُنشأ المنتج الجديد وإرسال معلومات المنتج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_959_13" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"37c99a36-4a43-4c96-8566-6158b0263c74"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"sku"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Z.111684.16216931837021275"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"parent_id"</span><span class="pun">:</span><span class="pln"> null</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"ar"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"منتج تجريبي"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"en"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Testing Product"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"slug"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"منتج-تجريبي"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"price"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">150.0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"sale_price"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">130.0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"formatted_price"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"150.00 ر.س "</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"formatted_sale_price"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"130.00 ر.س "</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"currency"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"SAR"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"currency_symbol"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ر.س "</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"attributes"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  </span><span class="str">"categories"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  </span><span class="str">"display_order"</span><span class="pun">:</span><span class="pln"> null</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"has_options"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"has_fields"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"images"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  </span><span class="str">"is_draft"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"quantity"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"is_infinite"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"html_url"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://zid.store/madjid/products/منتج-تجريبي"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"weight"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"value"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"unit"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"kg"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"keywords"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">"أكاديمية حسوب"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"حسوب"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"منتج تجريبي"</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="str">"requires_shipping"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"is_taxable"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"structure"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"standalone"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"seo"</span><span class="pun">:</span><span class="pln"> null</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"sold_products_count"</span><span class="pun">:</span><span class="pln"> null</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"cost"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"is_published"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"created_at"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2021-05-22T14:19:43.702509Z"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"updated_at"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2021-05-22T14:19:43.702542Z"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"description"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"ar"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"[\"&lt;h1&gt;من الممكن وضع تنسيقات هنا&lt;/h1&gt;\"]"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"en"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"[\"&lt;h1&gt;You can add HMTL here&lt;/h1&gt;\"]"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"variants"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  </span><span class="str">"custom_user_input_fields"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  </span><span class="str">"custom_option_fields"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  </span><span class="str">"options"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  </span><span class="str">"related_products"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
  </span><span class="str">"next_product"</span><span class="pun">:</span><span class="pln"> null</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"previous_product"</span><span class="pun">:</span><span class="pln"> null
</span><span class="pun">}</span></pre>

<h2>
	استعراض المنتجات
</h2>

<p>
	تتيح الواجهة البرمجية لمنصة زد استعراض جميع المنتجات المعروضة على المتجر، يكفي فقط أن نرسل طلبا من نوع GET إلى نفس نقطة الوصول السابقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_959_15" style="">
<span class="pun">/</span><span class="pln">products</span></pre>

<p>
	وبنفس ترويسة الطلب Headers السابقة، بحيث تُرسل كل من الترويسة STOREID والترويسة ROLE مع إضافة المفتاحين pagesize وpage كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77176" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/List_All_Product_Request.png.ca6b29866252971560bfd8f092ac02ee.png" rel=""><img alt="List_All_Product_Request.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77176" data-unique="iprnsalki" src="https://academy.hsoub.com/uploads/monthly_2021_09/List_All_Product_Request.thumb.png.11f5e78e3b824b999e7aeae54c67eac0.png"></a>
</p>

<p>
	سترسل الواجهة البرمجية لمنصة زد ردًا Response يحوي جميع المنتجات الموجودة في المتجر في الوقت الحالي سواء كانت معروضة أو مخفية، الرد سيكون مشابهًا للرد التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_959_19" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"count"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"next"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"previous"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"results"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"37c99a36-4a43-4c96-8566-6158b0263c74"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"sku"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Z.111684.16216931837021275"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"parent_id"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"ar"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"منتج تجريبي"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"en"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Testing Product"</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="str">"slug"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"منتج-تجريبي"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"price"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">150.0</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"sale_price"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">130.0</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"formatted_price"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"150.00 ر.س "</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"formatted_sale_price"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"130.00 ر.س "</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"currency"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"SAR"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"currency_symbol"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ر.س "</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"attributes"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
      </span><span class="str">"categories"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
      </span><span class="str">"display_order"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"has_options"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"has_fields"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"images"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
      </span><span class="str">"is_draft"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"quantity"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"is_infinite"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"html_url"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://zid.store/madjid/products/منتج-تجريبي"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"weight"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"value"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"unit"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"kg"</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="str">"keywords"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="str">"أكاديمية حسوب"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"حسوب"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"منتج تجريبي"</span><span class="pln">
      </span><span class="pun">],</span><span class="pln">
      </span><span class="str">"requires_shipping"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"is_taxable"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"structure"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"standalone"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"seo"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"sold_products_count"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"cost"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100.0</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"is_published"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"created_at"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2021-05-22T14:19:43.702509Z"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"updated_at"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2021-05-22T14:19:43.702542Z"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كل المنتجات موجودة داخل المفتاح results وهي مصفوفة كائنات Array Of Objects.
</p>

<h2>
	استعراض قائمة البلدان المدعومة
</h2>

<p>
	ﻻستعراض قائمة جميع البلدان التي تدعمها منصة زد، يكفي أن نرسل طلبا من نوع GET إلى نقطة الوصول التالية:
</p>

<pre class="ipsCode" id="ips_uid_7719_11">
/settings/countries</pre>

<p>
	كالعادة، يجب أن تحوي ترويسة Header الطلب على المفاتيح المساعدة ولغة الطلب، وستعيد لنا الواجهة البرمجية لمنصة زد، إجابة Response تحوي على مصفوفة كائنات Array Of Objects تحت مفتاح باسم countries بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77175" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/List_All_Countries.png.281dd6d3c9bdf66d7e0f024b0e567660.png" rel=""><img alt="List_All_Countries.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77175" data-unique="g1h9jw526" src="https://academy.hsoub.com/uploads/monthly_2021_09/List_All_Countries.thumb.png.7e51ae513e2486d343fb7511840386d8.png"></a>
</p>

<h2>
	استعراض قائمة المدن
</h2>

<p>
	للحصول على قائمة المدن المدعومة، يجب أن نرسل طلبا من نوع GET إلى نقطة الوصول التالية:
</p>

<pre class="ipsCode" id="ips_uid_7719_13">
/settings/cities/by-country-id/{country_id}</pre>

<p>
	بحيث يتم استبدال country_id بالرقم المعرف الخاص بالبلد الذي نريد استعراض المدن الموجودة فيه، فمثلا لو أردنا استعراض المدن الموجودة في المملكة العربية السعودية، سنرسل الطلب كالتالي:
</p>

<pre class="ipsCode" id="ips_uid_7719_15">
/settings/cities/by-country-id/184</pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		ملحوظة: الأرقام التعريفية للبلدان -مثل الرقم 184 الذي استعملناه في للتو- نتحصل عليها من قائمة البلدان التي جلبناها من طلبنا السابق (استعراض قائمة البلدان المدعومة).
	</p>
</blockquote>

<p>
	لنجرب الآن إرسال الطلبية وسنحصل على نتيجة مشابهة للرد التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77177" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/List_Country_Cities.png.804025f29f75aea1d4d0ac37c8eec1cf.png" rel=""><img alt="List_Country_Cities.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77177" data-unique="rvol5exm9" src="https://academy.hsoub.com/uploads/monthly_2021_09/List_Country_Cities.thumb.png.e847226099a0cc0b7b16875de2189519.png"></a>
</p>

<p>
	في حالة كان الرقم التعريفي الخاص بالبلد صحيحًا، سترسل الواجهة البرمجية قائمة المدن على شكل مصفوفة كائنات Array Of Objects تحوي جميع المدن لذلك البلد كما هو واضح في الصورة السابقة.
</p>

<h2>
	إضافة وسيلة شحن
</h2>

<p>
	ﻹضافة وسيلة شحن لمتجرك باستخدام الواجهة البرمجية، يكفي أن نرسل طلبًا من النوع POST لنقطة الوصول التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_959_27" style="">
<span class="str">/managers/</span><span class="pln">store</span><span class="pun">/</span><span class="pln">delivery</span><span class="pun">-</span><span class="pln">options</span><span class="pun">/</span><span class="pln">add</span></pre>

<p>
	ترويسات الطلب Headers يجب أن تحوي كل من مفتاح الوصول Access Token ومفتاح المتجر X-Manager-Token واللغة Accept-Language مثل العادة.
</p>

<p>
	أما بدن الطلب Body فيجب أن يحوي المعلومات التالية:
</p>

<ul>
<li>
		name: اسم وسيلة الشحن المراد إضافتها.
	</li>
	<li>
		cost: تكلفة الشحن وتكون ثابتة.
	</li>
	<li>
		cod_enabled: وتعني الدفع عند اﻹستلام، وتكون إما 0 لتعطيل الخيار أو 1 لتفعيله.
	</li>
	<li>
		cod_fee: تكلفة الدفع عن اﻹستلام إن كانت موجودة.
	</li>
	<li>
		cities: ويجب أن تحتوي على المعرفات الخاصة بالمدن (تُحصّل من خلال الطلب السابق).
	</li>
	<li>
		delivery_estimated_time_ar: وصف للفترة المتوقعة لوصول المشتريات باللغة العربية.
	</li>
	<li>
		delivery_estimated_time_en: وصف للفترة المتوقعة لوصول المشتريات باللغة اﻹنجليزية.
	</li>
</ul>
<p>
	سنرسل طلبًا بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_959_29" style="">
<span class="pun">{</span><span class="pln">
    </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Hsoub Delivery"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"cost"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"50"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"cod_enabled"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"1"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"cod_fee"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"20"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"cities"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
        </span><span class="lit">71</span><span class="pun">,</span><span class="pln">
        </span><span class="lit">76</span><span class="pun">,</span><span class="pln">
        </span><span class="lit">38</span><span class="pln">
    </span><span class="pun">],</span><span class="pln">
    </span><span class="str">"delivery_estimated_time_ar"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"3 أيام"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"delivery_estimated_time_en"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"3 days"</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عند إرسال الطلب، سنتلقى ردًا Response من الواجهة البرمجية يفيد بأن نقطة الوصول هذه قد حصلت على حمايتها، ولم يعد باﻹمكان الوصول إليها من الواجهة البرمجية باستخدام مفتاح الوصول Access Token الخاص بنا وقت كتابة المقال وقد تصبح متاحة لاحقًا أثناء قراءة المقال.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77174" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Error_Response.png.2ea71f4e67533bc4d17048123fc38962.png" rel=""><img alt="Error_Response.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77174" data-unique="fhevcfph9" src="https://academy.hsoub.com/uploads/monthly_2021_09/Error_Response.thumb.png.32b742dd6af305ea9a444952ae3171ca.png"></a>
</p>

<p>
	هذا مثال جيد عن رسائل الأخطاء المختلفة التي ممكن أن تعيدها الواجهة البرمجية، ويجب أن تحصن تطبيقك جيدًا بمعالجة أي خطأ يحتمل أن تعيده الواجهة البرمجية، إذ يؤخذ بالحسبان عادة رمز الخطأ (في حالتنا هو 403) ويفترض أن تعرف معنى تلك الرموز أثناء الطوير لتعرف كيف تتصرف مع رموز الأخطاء والحالات التي تهمك، وعمومًا هذا الأمر يحتاج إلى مقال منفصل، ننصحك بالاطلاع على مقال <a data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/general/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-http-r73/" rel="">مدخل إلى HTTP</a> ومقال <a data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/general/%D8%B1%D9%85%D9%88%D8%B2-%D8%A7%D9%84%D8%A5%D8%AC%D8%A7%D8%A8%D8%A9-%D9%81%D9%8A-http-r75/" rel="">رموز الإجابة في HTTP</a>.
</p>

<h2>
	خاتمة
</h2>

<p>
	اﻵن، وقد استعرضنا عددًا من نقاط الوصول التي توفرها الواجهة البرمجية لمنصة زد، وتعرفنا على طرق إرسال الطلبات، دعنا نطبق كل ما تعلمنا إلى الآن في تطبيق عملي يستعمل يستفيد من واجهة زد البرمجية وهو بناء تطبيق بسيط لزيادة وﻻء العملاء مع شرح كيفية تحويل هذا التطبيق إلى مشروع تجاري.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a data-ss1631885755="1" data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/javascript/nodejs/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%8A%D8%B2%D9%8A%D8%AF-%D9%85%D9%86-%D8%A7%D8%AD%D8%AA%D9%81%D8%A7%D8%B8-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D8%A7%D8%A1-%D8%B9%D8%A8%D8%B1-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%B2%D8%AF-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1320/" rel="">تطوير تطبيق عملي يزيد من احتفاظ العملاء عبر واجهة زد البرمجية</a>
	</li>
	<li>
		<a data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/apps/web/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%AA%D8%AC%D8%B1-%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-%D9%85%D8%AA%D9%83%D8%A7%D9%85%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%85%D9%86%D8%B5%D8%A9-%D8%B2%D8%AF-r440/" rel="">كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد</a>
	</li>
	<li>
		<a data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-fetch-api-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1297/" rel="">الواجهة البرمجية Fetch <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> في جافاسكريبت</a>
	</li>
	<li>
		<a data-ss1631886114="1" data-ss1631887115="1" href="https://academy.hsoub.com/programming/general/http-%D9%84%D9%86%D9%86%D8%B7%D9%84%D9%82-%D8%B4%D8%B1%D8%AD-%D8%A7%D9%84%D8%AA%D8%AE%D8%A7%D8%B7%D8%A8-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-r74/" rel="">HTTP - لننطلق: شرح التخاطب بين العميل والخادوم</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1319</guid><pubDate>Thu, 16 Sep 2021 15:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x627;&#x62A;&#x635;&#x627;&#x644; &#x628;&#x648;&#x627;&#x62C;&#x647;&#x629; &#x632;&#x62F; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629; &#x648;&#x641;&#x647;&#x645; &#x639;&#x645;&#x644;&#x64A;&#x629; &#x627;&#x644;&#x627;&#x633;&#x62A;&#x64A;&#x62B;&#x627;&#x642; &#x648;&#x627;&#x644;&#x62A;&#x635;&#x631;&#x64A;&#x62D;</title><link>https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%B2%D8%AF-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%88%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-%D9%88%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D8%AD-r1318/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_09/614423b33f165_(1).png.910193d7f6ed6f762da6c03930d8ca5f.png" /></p>

<p>
	شرحنا في المقال السابق <a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">مدخل إلى الواجهات البرمجية <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a>  الفكرة العامة حول الواجهات البرمجية، وكنا قد شبهناها بالنادل في المطعم الذي يأخذ طلبات الزبائن إلى الطباخ والفريق العامل معه من أجل تحضيرها، ومن ثم استلام استجابة الطباخ للطلبية وتوصيلها إلى أصحابها، وهو ما تفعله الواجهات البرمجية بالضبط مع بعض الإختلاف بالنظر إلى طبيعة العمل في مجال التقنية.
</p>

<p>
	سنتعرف في هذا المقال أكثر على عملية التواصل التي تنظمها الواجهة البرمجية، ثم سنطبق ذلك عمليًا على واجهة برمجة واخترنا واجهة زد البرمجية للغرض الذي شرحنا في السابق.
</p>

<p>
	هذا المقال هو جزء من سلسلة مقالات حول الواجهة البرمجية <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> وكيفية الاستفادة منها في بناء تطبيق ويب:
</p>

<ol>
<li>
		<a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">مدخل إلى الواجهات البرمجية <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a>
	</li>
	<li>
		الاتصال بواجهة زد البرمجية وفهم عملية الاستيثاق والتصريح
	</li>
	<li>
		<a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/programming/general/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D9%84%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AA%D8%A7%D8%AC%D8%B1-%D8%B2%D8%AF-zid-api-r1319/" rel="">أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a>
	</li>
	<li>
		<a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/programming/javascript/nodejs/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%8A%D8%B2%D9%8A%D8%AF-%D9%85%D9%86-%D8%A7%D8%AD%D8%AA%D9%81%D8%A7%D8%B8-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D8%A7%D8%A1-%D8%B9%D8%A8%D8%B1-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%B2%D8%AF-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1320/" rel="">تطوير تطبيق عملي يزيد من احتفاظ العملاء عبر واجهة زد البرمجية</a>
	</li>
</ol>
<h2>
	آلية التواصل وتنظيم عملية الاتصال
</h2>

<p>
	قبل أن أكمل الحديث عن الواجهة البرمجية، هل سألت نفسك، لماذا ﻻ يذهب الزبائن مباشرةً إلى الطباخ في مقال المطعم السابق ويخبروه بما يريدون تناوله من مختلف الأطباق التي تُقدَّم في المطعم؟
</p>

<p>
	الجواب ببساطة هو أن الطلبيات ستصبح عشوائيةً آنذاك ولن يستطيع الطباخ أن يحضّر أيًا من الطلبات بسبب العشوائية، وقد لا يفهم على الزبون ماذا يريد أي تحصل عشوائية وغموض في الطلب، فكل زبون يطلب طلبيته بصيغة مختلفة عن الآخر قد تكون بلغة أخرى تمامًا.
</p>

<p>
	في حالة أخرى، هل يستطيع أي عامل في المطعم أن يكون نادﻻ؟ في هذه الحالة ستكون فوضى أخرى ولكن بدرجة أقل، بحيث هنالك احتمالية كبيرة ﻷن تُحضّر نفس الطلبية أكثر من مرة لنفس الشخص وفي مرات أخرى من الممكن نسيان طلبية زبون آخر، وفي حالة أخرى، لن يكون باﻹمكان معرفة صاحب الطلبية من غيره أو حتى عدم فهم طلبية الزبون.
</p>

<p>
	كانت هذه الحالة الخاصة بالمطعم، فلك أن تتخيل كقاميف ستكون في حالة الواجهات البرمجية؟ تقريبا هي نفس الشيء ولكنها بشكل أسوأ بكثير بسبب أن الواجهة البرمجية <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> تنظِّم الكثير والكثير من الطلبات لعدد كبير جدا من العملاء التي قد تصل إلى أرقام كبيرة وخيالية.
</p>

<p>
	حُلت المشكلة في حالة المطعم بتحديد من يستطيع التحدث مع الزبائن وتدريبهم بأخذ الطلبيات إلى الطباخ وفريقه ومن ثم إعادة الاستجابة أو الناتج الذي حُضِّر إلى الزبون نفسه الذي طلبها تحديدًا ولم يسبق أن دخلت مطعمًا ونسي النادل طلبيتي أو جاءني بطلبية أخرى فهل سألت نفسك عن السبب؟ هل رأيته يكتب في ورقة أمامه ويسألك عن اسمك وينظر في الطاولة والموقع برهة ويذهب؟ وهل قلت لنفسك إن تأخر لقد نسيني أو لم يعرفني ثم يعود جالبًا لك طلبيتك التي طلبتها تمامًا دون أي نسيان؟ للنادل آلية يتذكر فيها صاحب كل طلبية وطلبيته بالضبط ولا ينساها مطلقًا والأمر في حالة الواجهة البرمجة مشابه تمامًا.
</p>

<p>
	حلت المشكلة السابقة عن طريق ما يسمى المفتاح المساعد Token وهو سلسلة نصية String تخص العميل طالب الخدمة وتميزه تصدرها الواجهة البرمجة غالبًا (سواءً بمقابل مادي أو مجرد التسجيل في منصة مقدم الواجهة البرمجية) بحيث يرسل المفتاح المساعد Token مع كل طلب خدمة إلى الواجهة البرمجية، من ثم تتحقق الواجهة البرمجية من صلاحية المفتاح المساعد، إن كان صالحا، فستُقدَّم الخدمة المطلوبة للعميل، أما إن لم يكن صالحا، فعادةً ما تُرجع رسالة خطأ تفيد بأن المفتاح المساعد غير صالح، أي لا يمكن إلا لأشخاص مخوليين التواصل مع الواجهة البرمجية وإلا لعمت الفوضى وجاء الجميع للاستفادة من الخدمة التي تقدمها الواجهة.
</p>

<h2>
	التواصل مع واجهة منصة زد البرمجية
</h2>

<p>
	حتى نفهم أكثر هذه العملية، سنأخذ مثالًا من الحياة العملية، بحيث سنوجه طلبات إلى الواجهة البرمجية لمنصة زد من أجل اﻹستعلام عن بعض الخدمات الخاصة بهم، دعونا نبدأ.
</p>

<p>
	قبل أن نبدأ، ستحتاج إلى التالي:
</p>

<ol>
<li>
		حساب مطور على منصة زد
	</li>
	<li>
		برناج إرسال طلبات HTTP مثل Insomnia أو البرنامج الأكثر شهرة Postman (أصبح البرنامج بطيئًا نوعا ما موازنةً ببرنامج Insomnia ولهذا سنستخدم اﻷخير).
	</li>
</ol>
<h3>
	إنشاء حساب مطور على منصة زد
</h3>

<p>
	ندخل إلى <a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://portal.zid.dev/devportal/" rel="external nofollow">بوابة المطورين</a> في منصة زد، سنجدها بسيطة وسهلة اﻹستخدام، يكفي فقط أن عنوان بريدك اﻹلكتروني في الخانة المخصصة، كما في الصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77170" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Zid_Developer_Portal.png.19ef40a3de939055c4ed5d78951e4f43.png" rel=""><img alt="Zid_Developer_Portal.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77170" data-unique="tjsozgodv" src="https://academy.hsoub.com/uploads/monthly_2021_09/Zid_Developer_Portal.thumb.png.10fd9c9e3896e13874d8c94eed24960e.png"></a>
</p>

<p>
	بعد أن تدخل عنوان بريدك اﻹلكتروني، والضغط على الزر START NOW، سيُعاد توجيهك إلى لوحة تحكم المطورين، أين يمكنك أخذ نظرة عن الواجهة البرمجية لمنصة زد
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77169" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Zid_Developer_Panel.png.200c43d65c5483c6cc181da87fd4ace3.png" rel=""><img alt="Zid_Developer_Panel.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77169" data-unique="qxkunz1ha" src="https://academy.hsoub.com/uploads/monthly_2021_09/Zid_Developer_Panel.thumb.png.c1f69bf289b722d79acb18d14c47967d.png"></a>
</p>

<p>
	عند الضغط على ZidAPI ﻻكتشاف تفاصيل الواجهة البرمجية لمنصة زد، كما في الصورة الموالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77171" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/6144241d104b7_Zid_Developer_Panel_2.png.b696b061579429d401f5693e072b1079.png" rel=""><img alt="ًZid_Developer_Panel_2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77171" data-unique="hdqzw6d7l" src="https://academy.hsoub.com/uploads/monthly_2021_09/6144241d104b7_Zid_Developer_Panel_2.png.b696b061579429d401f5693e072b1079.png"></a>
</p>

<p>
	ستظهر لنا النافذة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_09/ZidAPI_Overview.png.ac5945c14ee99401e16de48c83076809.png.9e837da16f0424e23086b4d160d7e90c.png" data-fileid="77962" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="77962" data-unique="ughl8if1o" src="https://academy.hsoub.com/uploads/monthly_2021_09/ZidAPI_Overview.png.ac5945c14ee99401e16de48c83076809.thumb.png.b9124e72449ed2947fb7b98267b5be4c.png" style="" alt="ZidAPI_Overview.png.ac5945c14ee99401e16de48c83076809.png"></a>
</p>

<p>
	وفيها نجد جميع المعلومات اللازمة للاتصال بالواجهة البرمجية لمنصة زد، بحيث ذُكرت جميع نقاط الوصول Endpoints، مع المعلومات التي يجب إرسالها والمعلومات التي ستُحصّل عند كل نقطة وصول.
</p>

<p>
	في الجزء Gateway Environments، وعند الضغط على القائمة Production and Sandbox، ستظهر معلومات مهمة، هي نقطة الوصول الرئيسية للواجهة البرمجية، ولكن ما الذي تعنيه Production and Sandbox.
</p>

<p>
	ببساطة Production Environment، هي البيئة الإنتاجية للواجهة البرمجية التي عليك استخدامها في مشروعك النهائي المقدم كخدمة للزبائن، بحيث أن كل العمليات التي تحدث فيها، هي عمليات فعلية. أما Sandbox Environment، فهي البيئة التطويرية التجريبية التي تستخدم أثناء عملية التطوير، بحيث أن جميع العمليات التي تتم فيها، هي عمليات تجريبية فقط.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77147" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/API_Env.png.1e241c845ed0dab060941bc692e3e4e9.png" rel=""><img alt="API_Env.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77147" data-unique="myiyv9cx0" src="https://academy.hsoub.com/uploads/monthly_2021_09/API_Env.thumb.png.d6c54286607a933200e17451e67180e1.png"></a>
</p>

<p>
	في الواجهة البرمجية لمنصة زد، نلاحظ أن اﻹختلاف بين البيئة الإنتاجية والبيئة التطويرية التجريبية طفيف، فهو يمكن فقط في البروتوكول المستخدم HTTP.
</p>

<h3>
	فهم طلبيات HTTP وأنواعها
</h3>

<p>
	نريد اﻵن ااتصال بالواجهة البرمجية لمنصة زد، كل المعلومات لدينا ولم يبقى إﻻ عملية اﻹتصال. للقيام بذلك، نحتاج برنامجا ﻹرسال طلبات HTTP، أو ما يسمى باللغة اﻹنجليزية HTTP Client، ولكن ما هو هذا البرنامج، وما هو عمله؟
</p>

<p>
	ببساطة، برنامج HTTP Client، هو وسيط بينك وبين الواجهة البرمجية، بحيث يرسل الطلبات حسب بروتوكول HTTP. هنالك عدة أنواع من الطلبات الخاصة ببروتوكول HTTP، أشهرها GET و POST و PUT و DELETE.
</p>

<p>
	كمعلومة جانبية، متصفح اﻹنترنت الذي تعرفه، مثل كروم Google Chrome، وفايرفوكس أو أي متصفح آخر يعتبر HTTP Client، أي لديه القدرة أن يرسل طلبات HTTP للاستزادة في هذه النقطة، سأشرح أنواع طلبيات HTTP وهي:
</p>

<ul>
<li>
		الطلب GET: يستخدم لجلب بيانات من الخادم أو الواجهة البرمجية.
	</li>
	<li>
		الطلب POST: يستخدم ﻹرسال البيانات إلى الخادم أو الواجهة البرمجية.
	</li>
	<li>
		الطلب PUT: يستخدم لتحديث بيانات في الخادم.
	</li>
	<li>
		الطلب DELETE: يستخدم لحذف البيانات على الخادم.
	</li>
</ul>
<h3>
	استعمال Insomnia لإدارة الطلبيات التجريبية
</h3>

<p>
	سنستخدم برنامج Insomnia من أجل إرسال الطلبات لواجهة زد البرمجية، يمكنك تنزيل البرنامج من <a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://insomnia.rest/download" rel="external nofollow">الموقع الرسمي للشركة المطورة</a>.
</p>

<p>
	بعد التحميل والتثبيت، ستظهر نافذة البرنامج كما في الصورة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77165" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_REST_Client.png.49c297af17143b010bcd197e6d411ec8.png" rel=""><img alt="Insomnia_REST_Client.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77165" data-unique="40rjct8my" src="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_REST_Client.thumb.png.6d42d5df749b31b067c4db6a99b199db.png"></a>
</p>

<p>
	واجهة بسيطة وسهلة اﻹستخدام، أليس كذلك؟ نضغط على الزر New Request ﻹرسال طلب للواجهة البرمجية لمنصة زد:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77161" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_Add_Request.png.7e72b409da44e15f869f09a56bc735f9.png" rel=""><img alt="Insomnia_Add_Request.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77161" data-unique="7xvfxkvih" src="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_Add_Request.thumb.png.d763ddf61a0b08f905907c81a6a29cb4.png"></a>
</p>

<ol>
<li>
		لتسمية الطلب الجديد، يمكنك اختيار أي اسم كان، أو ترك الاسم الافتراضي، ولكن يفضل أن تُسمى الطلبات بأسماء ذات معنى للعمل الذي تنجزه.
	</li>
	<li>
		نوع الطلب، ويمكننا تحديد أي طلب كان حسب حاجتنا وحسب ما تفرضه الواجهة البرمجية.
	</li>
	<li>
		إنشاء وحفظ الطلب الجديد.
	</li>
</ol>
<p>
	احفظ الطلب الجديد باسم Get Profiles، لأننا سنتصل بالواجهة البرمجية لمنصة زد من أجل جلب الملفات الشخصية Profiles المتعلقة بحسابنا على منصة زد.
</p>

<h3>
	التعرف على نقاط الوصول
</h3>

<p>
	حينما نتصفح صفحة <a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://portal.zid.dev/devportal/apis" rel="external nofollow">Developer Portal</a> التي وفرتها منصة زد، سنجد توثيقا يخص الواجهة البرمجية لمنصة زد. التوثيق هو شرح لجميع نقاط الوصول Endpoints للواجهة البرمجية، وما هي المعلومات التي عليك إرسالها لكل نقطة وصول والمعلومات التي ستتحصل عليها من نقطة الوصول تلك.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77146" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/API_Documentation.png.430aa4e78a2f7d577181b5c697fe2656.png" rel=""><img alt="API_Documentation.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77146" data-unique="pzixhx4qn" src="https://academy.hsoub.com/uploads/monthly_2021_09/API_Documentation.thumb.png.1b6ba193f7fbc658ff77ff59c5561d7c.png"></a>
</p>

<p>
	تلاحظ أن هناك نقطة وصول تتيح لنا الحصول على الملفات الشخصية Profiles، وهي موجودة على المسار Path:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6396_8" style="">
<span class="str">/managers/</span><span class="pln">account</span><span class="pun">/</span><span class="pln">profile</span></pre>

<p>
	تذكر أن علينا إضافة نقطة الوصول الرئيسية للواجهة البرمجية قبل رابط تلك المسارات أو نقاط الوصول الفرعية، وبالتالي يصبح الرابط النهائي الذي علينا توجيه الطلب إليه كالتالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_6396_12" style="">
<span class="pln">http</span><span class="pun">:/</span><span class="str">/api.zid.dev/</span><span class="pln">app</span><span class="pun">/</span><span class="pln">v1</span><span class="pun">/</span><span class="pln">managers</span><span class="pun">/</span><span class="pln">account</span><span class="pun">/</span><span class="pln">profile</span></pre>

<p>
	ولكن كيف كونا الرابط النهائي لنقطة الوصول هذه؟
</p>

<p>
	اﻷمر بسيط جدا، من التوثيق الخاص بالواجهة البرمجية لمنصة زد، فنجد Servers والتي تحوي الرابط الرئيسي لكل من البيئة الإنتاجية والبيئة التجريبية للواجهة البرمجية.
</p>

<h3>
	طلب التصريح والاستيثاق من الطلبية
</h3>

<p>
	بعدها نجد مسار نقطة الوصول Endpoint تمامًا مثل هذا المثال:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77154" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Endpoint.png.989b9dcda54c8bd9a625977095be84a1.png" rel=""><img alt="Endpoint.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77154" data-unique="9rzcaig4d" src="https://academy.hsoub.com/uploads/monthly_2021_09/Endpoint.thumb.png.d0b4e7929059491dbebfa183a3965f02.png"></a>
</p>

<p>
	لكل نقطة وصول معلومات مطلوبة حتى تستطيع الوصول إليها واستخدامها، فمثلا نقطة الوصول الموضح بالصورة تتطلب مُعامِلات Parameters خاصة بها وهي:
</p>

<ul>
<li>
		X-MANAGER-TOKEN: وهو المفتاح المتجر المساعد الذي يخص المتجر اﻹلكتروني المراد تطبيق العملية عليه ولكل متجر في زد مفتاح مساعد خاص به فقط.
	</li>
	<li>
		Accept-Language: وهي اللغة التي تريد أن ترسل لك الواجهة البرمجية الإجابة Response فيها، وتأخذ القيمة ar للغة العربية أو en للغة اﻹنجليزية.
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77155" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/First_Get_Request.png.2143f0fe5f2c8a8f28a7e06202f54c75.png" rel=""><img alt="First_Get_Request.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77155" data-unique="xajaorro1" src="https://academy.hsoub.com/uploads/monthly_2021_09/First_Get_Request.thumb.png.424a4696422f9a806efe975c1b684fc6.png"></a>
</p>

<p>
	الآن، سنرسل الطلب للواجهة البرمجية لمنصة زد، وننتظر الرد:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77160" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Get_Request_Error.png.8bbe91e57d4678115efc53b89cb72d97.png" rel=""><img alt="Get_Request_Error.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77160" data-unique="oh2il9km0" src="https://academy.hsoub.com/uploads/monthly_2021_09/Get_Request_Error.thumb.png.3345e642713a57ced41cbb49581b9fd5.png"></a>
</p>

<p>
	لقد واجهتنا رسالة تفيد بأن علينا إرفاق مفتاح المبرمج المساعد Token مع الطلب حتى يتم التحقق بأننا مخولون للدخول واستعمال نقاط الوصول الخاصة بالواجهة البرمجية، هو نفسه الذي شرحناه آنفًا في بداية المقال فكما ذكرنا أنه يجب أن يكون مصرحًا لك استعمال الواجهة البرمجية وإلا جاء أي أحد واستعملها وستتأكد الواجهة البرمجة من ذلك التصريح وتستوثق منه.
</p>

<p>
	تذكر أن العملية مشابهة تمامًا للباب ومفتاحه فلأي مكان باب مثل منزلك عليه باب ولا يخول لأي أحد دخوله إلا من يملك مفتاح الباب، وتخيل أن يكون باب المنزل دون مفتاح أو أن يملك أي أحد مفتاح باب منزلك! العملية هنا نفسها تمامًا.
</p>

<h3>
	الحصول على مفاتيح التصريح المخولة
</h3>

<p>
	التوثيق الخاص بالواجهة البرمجية لمنصة زد، يشرح طريقة الحصول على المفتاح المبرمج المساعد أي المفتاح الخاص بك الذي يصرح لك استعمال الواجهة البرمجية، يكفيك أن تتوجه إلى التبويب Subscriptions ومنه أنشئ التطبيق الخاص بك، باستخدام Subscriptions &amp; Key Generation Wizard.
</p>

<p>
	سيطلب منك معلومات بسيطة تعريفية بالتطبيق، تابع الصور التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77148" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Create_App_1.png.fd7e867134c8ff298c3a2f892425784b.png" rel=""><img alt="Create_App_1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77148" data-unique="uu9d8zcue" src="https://academy.hsoub.com/uploads/monthly_2021_09/Create_App_1.thumb.png.20d2bf87fbb1405e0d3e7349cc8141c5.png"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77149" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Create_App_2.png.4f1fa3d9fd6724b06f3475a179d8ad41.png" rel=""><img alt="Create_App_2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77149" data-unique="a2qyw21ks" src="https://academy.hsoub.com/uploads/monthly_2021_09/Create_App_2.thumb.png.4dfc16b35513f1a2564d186400c48566.png"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77150" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Create_App_3.png.52d30ce4ee4c1c4cec22b77e26d71903.png" rel=""><img alt="Create_App_3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77150" data-unique="lovmmyia6" src="https://academy.hsoub.com/uploads/monthly_2021_09/Create_App_3.thumb.png.6d101715ae892192ff0eac86e6822f07.png"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77151" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Create_App_4.png.a3e87e23c5a6ec5548a5f789e57ccce3.png" rel=""><img alt="Create_App_4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77151" data-unique="h2wiclq4r" src="https://academy.hsoub.com/uploads/monthly_2021_09/Create_App_4.thumb.png.370f6fd21c1f98d410d480afdfc5880d.png"></a>
</p>

<p>
	عليك الآن أن تنتظر إلى حين الموافقة على التطبيق من طرف فريق منصة زد.
</p>

<p>
	بعد أن يوافق فريق منصة زد على تطبيقك، سيصبح لديك حق الاتصال بالواجهة البرمجية لمنصة زد، ولكن بقيت خطوة أخيرة وهي إنشاء مفتاح مساعد Token.
</p>

<p>
	هنالك طريقتان: الأولى، عن طريق لوحة التحكم في منصة زد نفسها، بحيث من نفس الصفحة السابقة، نختار التطبيق الذي أنشاناه، ونختار Manage App، وبعدها نختار Sandbox Keys، حتى نستعمل الواجهة البرمجية الخاصة بالتجربة فقط:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_09/6152eb4b02c1a_2.png.535dd0df6f77cabb4f02be5f89aa4ecc.png" data-fileid="77963" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="77963" data-unique="dswo1bfcp" src="https://academy.hsoub.com/uploads/monthly_2021_09/6152eb4bad408_2.thumb.png.8f64dc28ee6ec6284993d4fad0d3e7e1.png" style="" alt="2 زد.png"></a>
</p>

<p>
	نضغط على Generate Access Token، لتظهر نافذة منبثقة، تطلب تأكيد توليد المفتاح المساعد Token:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77158" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Generate_Token.png.79902f681a53c9db5c790c284d9b3c9e.png" rel=""><img alt="Generate_Token.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77158" data-unique="xic6ukru3" src="https://academy.hsoub.com/uploads/monthly_2021_09/Generate_Token.png.79902f681a53c9db5c790c284d9b3c9e.png"></a>
</p>

<p>
	بعد الضغط على GENERATE، ستظهر سلسلة نصية متكونة من أحرف وأرقام، علينا نسخها ولصقها في مكان يسهل علينا الرجوع إليه.
</p>

<p>
	الطريقة الثانية ﻹنشاء مفتاح مساعد هي أن نتجه إلى التبويب <a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://portal.zid.dev/devportal/apis/" rel="external nofollow">Subscriptions</a> في قسم Zid Developer Portal، ونختار التطبيق الذي أنشأناه سابقًا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77152" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Curl_Access_Token.png.635e9ed168491a6c2ea12f72ac464747.png" rel=""><img alt="Curl_Access_Token.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77152" data-unique="uo3s59ubg" src="https://academy.hsoub.com/uploads/monthly_2021_09/Curl_Access_Token.thumb.png.7a16e195fe6068e61ffd7e12fd9ebf06.png"></a>
</p>

<p>
	نضغط على Sandbox Keys:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77153" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Curl_Access_Token_2.png.c4db532955ab02c8d33c4fb6dc0d9bdf.png" rel=""><img alt="Curl_Access_Token_2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77153" data-unique="f7tzqtty7" src="https://academy.hsoub.com/uploads/monthly_2021_09/Curl_Access_Token_2.thumb.png.e47f746270973a939373b75d776ac4a0.png"></a>
</p>

<p>
	ثم نضغط بعدها على CURL TO GENERATE ACCESS TOKEN:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77145" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Access_Token_Endpoint.png.8966349fb181447ad81990c3eff11d2f.png" rel=""><img alt="Access_Token_Endpoint.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77145" data-unique="l7w4rdbnf" src="https://academy.hsoub.com/uploads/monthly_2021_09/Access_Token_Endpoint.png.8966349fb181447ad81990c3eff11d2f.png"></a>
</p>

<p>
	نختار الرابط الثاني (الطريقة الثانية) ﻹنشاء المفتاح المساعد Access Token ونلضغط على الزر الموجود على الجانب من أجل نسخه، ونفتح برنامج Insomnia:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77162" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_Generate_Token.png.16dbed1777270b19a25d90680a5e5e71.png" rel=""><img alt="Insomnia_Generate_Token.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77162" data-unique="104wj96ou" src="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_Generate_Token.thumb.png.7fa89b7ef83b143e5e61c60032ea3c9d.png"></a>
</p>

<p>
	بعدها نختار كما موضح في الصورة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77163" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_Generate_Token_2.png.6e8c06b8451e25ad98ade32ccaca7d1b.png" rel=""><img alt="Insomnia_Generate_Token_2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77163" data-unique="brkx1n1tk" src="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_Generate_Token_2.thumb.png.c4a72169c3f0bce2affd0d5b0ef775ec.png"></a>
</p>

<p>
	ستظهر نافذة تسألك إن كنت تريد استيراد السطر في نفس النافذة أم نافذة جديدة، اختر ما يناسبك سيُنشَأ طلب جديد من نوع POST مثل الصورة الموالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77164" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_Generate_Token_3.png.f60a73a48f630ddfba0cfe958ea7b9ca.png" rel=""><img alt="Insomnia_Generate_Token_3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77164" data-unique="xzaen8gre" src="https://academy.hsoub.com/uploads/monthly_2021_09/Insomnia_Generate_Token_3.thumb.png.acf4c1b55f0d741e7d5c101fb966467a.png"></a>
</p>

<p>
	اﻵن علينا أن نضيف ترويسة إلى قبل إرسال طلبنا عن طريق الذهاب إلى التبويب Header وإضافته كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77167" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Request_Header.png.b6f4171a405fbd7332c3b99af974b749.png" rel=""><img alt="Request_Header.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77167" data-unique="txzjbvs18" src="https://academy.hsoub.com/uploads/monthly_2021_09/Request_Header.png.b6f4171a405fbd7332c3b99af974b749.png"></a>
</p>

<p>
	ما الذي يعنيه هذا الجزء من الطلب؟
</p>

<p>
	يعني هذا الجزء ببساطة، إرسال مفتاح فرعي مع الطلب يثبت أن لدينا حسابًا مفعلا في الواجهة البرمجية لمنصة زد حتى يكون بإمكاننا إرسال طلب إنشاء مفتاح مساعد، ولكن من أين أتينا بهته المعلومات؟ هي معلومات موجودة في الرابط الذي نسخناه ولصقناه قبل قليل.
</p>

<p>
	إن لم تستوعب الفكرة اﻵن فلا داعي للقلق، سنشرح كل شيء بالتفصيل في المقاﻻت القادمة ويكفي اﻵن أن تضغط على Send، ﻹرسال طلب إنشاء مفتاح مساعد جديد، وسيُرسَل إليك كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77157" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Generated_Access_Token.png.1354862d4f4e0568bf31a4dd88fdf467.png" rel=""><img alt="Generated_Access_Token.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77157" data-unique="ujlntvypu" src="https://academy.hsoub.com/uploads/monthly_2021_09/Generated_Access_Token.thumb.png.3b888b704b09c805a731720241423f74.png"></a>
</p>

<p>
	بقيت اﻵن خطوة أخيرة وهي إنشاء <a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://zid.sa/" rel="external nofollow">متجر تجريبي</a> على منصة زد من أجل التجربة عليه، المنصة تمنحك فترة 14 يوما من أجل اكتشاف خصائص المنصة والتعرف على طريقة التعامل معها (انظر مقال <a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/apps/web/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%AA%D8%AC%D8%B1-%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-%D9%85%D8%AA%D9%83%D8%A7%D9%85%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%85%D9%86%D8%B5%D8%A9-%D8%B2%D8%AF-r440/" rel="">كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد</a> لمزيد من التفاصيل حول كيفية إنشاء متجر).
</p>

<p>
	بعد أن تنشئ متجرًا على منصة زد، أدخُل إلى حسابك وتوجه إلى صفحة "اﻹعدادات"، ثم اختر "الربط مع الخدمات"، ثم اضغط على زر "قم بإنشاء رمز المصادقة Manager Token":
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77166" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/Manager_Token.png.6a12a39fab4e7affef1e1a74a3444400.png" rel=""><img alt="Manager_Token.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77166" data-unique="t50s7m48t" src="https://academy.hsoub.com/uploads/monthly_2021_09/Manager_Token.thumb.png.b7564fb2ada37522680fd87533aff9a3.png"></a>
</p>

<h3>
	إنشاء أول اتصال مع الواجهة البرمجية
</h3>

<p>
	اﻵن وبعد أن توافرت لدينا كل المفاتيح والمعلومات المطلوبة للاتصال بالواجهة البرمجية، يمكننا العودة للطلب الذي أنشأناه سابقا واﻹتصال بالواجهة البرمجية لمنصة زد كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="77156" data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/First_Successful_Request.png.f3eaad766158731420ea02ea5c8d53e7.png" rel=""><img alt="First_Successful_Request.png" class="ipsImage ipsImage_thumbnailed" data-fileid="77156" data-unique="qejjumgg1" src="https://academy.hsoub.com/uploads/monthly_2021_09/First_Successful_Request.thumb.png.c323620d5d04f3d85db3d20fa8187f8f.png"></a>
</p>

<p>
	ﻻحظ أننا ضمنا كلًا من مفتاح المبرمج Access Token ومفتاح المتجر Manager Token في ترويسة Header الطلب تحت تسمية Authorization و X-MANAGER-TOKEN على الترتيب، وهو ما يسمح للواجهة البرمجية لمنصة زد من التحقق من قدرتنا على الوصول إلى نقطة الوصول Endpoint هته وهل نمتلك الصلاحية لذلك وتعرف أيضًا أي متجر بالتحديد نريد تطبيق العمليات عليه.
</p>

<p>
	إن كنت قد تساءلت لماذا أضفنا كلمة Bearer قبل السلسلة النصية في Authorization، فببساطة هنالك عدة أنواع من المفاتيح المساعدة ولكن أشهرها هي Basic وBearer، اﻹختلاف بينهما هو في نمط التشفير وفك التشفير فقط.
</p>

<h2>
	خاتمة
</h2>

<p>
	تعلمنا في هذا المقال كيفية إنشاء أول اتصال مع واجهة برمجية نموذجية -مثل واجهة منصة زد- بتأمين مفاتيح التصريح المطلوبة وكل المعلومات اللازمة لها وأصبح بإمكانك الآن تطبيق ما تعلمته في المقال على أي واجهة برمجية والاتصال بها والاستفادة من الخدمات التي تقدمها على الوجهة التي تريد.
</p>

<p>
	سنتعرف في المقال التالي أكثر على واجهة منصة زد والاتصال بمختلف نقاط وصول الواجهة البرمجية والاطلاع على المعلومات التي يمكن أن تزودنا فيها وكيف يمكن الاستفادة منها.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/programming/general/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D9%84%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AA%D8%A7%D8%AC%D8%B1-%D8%B2%D8%AF-zid-api-r1319/" rel="">أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a>
	</li>
	<li>
		<a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/apps/web/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%84%D9%88%D8%AD%D8%A9-%D8%AA%D8%AD%D9%83%D9%85-%D9%85%D8%AA%D8%AC%D8%B1-%D8%B2%D8%AF-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-%D9%88%D8%B6%D8%A8%D8%B7-%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D8%AC%D8%B1-r441/" rel="">التعرف على لوحة تحكم متجر زد الإلكتروني وضبط عمليات المتجر</a>
	</li>
	<li>
		<a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/apps/web/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%AA%D8%AC%D8%B1-%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-%D9%85%D8%AA%D9%83%D8%A7%D9%85%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%85%D9%86%D8%B5%D8%A9-%D8%B2%D8%AF-r440/" rel="">كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد</a>
	</li>
	<li>
		<a data-ss1631885755="1" data-ss1631887029="1" data-ss1631887107="1" href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-fetch-api-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1297/" rel="">الواجهة البرمجية Fetch <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> في جافاسكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1318</guid><pubDate>Wed, 15 Sep 2021 15:00:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x627;&#x644;&#x648;&#x627;&#x62C;&#x647;&#x627;&#x62A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629; API</title><link>https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_09/613f976357593_API.png.df46963ab736322b3f3727c872ec39a5.png" /></p>
<p>
	سنتعرف في هذا المقال على مفهوم واجهة برمجية التطبيقات Application Programming Interface، هذا المصطلح السهل المعقد حيث سنحاول فهمه وكيفية بناء مواقع الويب والتطبيقات الحديثة في يومنا هذا بالاعتماد على الواجهات البرمجية ونجيب على سؤال مهم وهو كيف ترتبط الواجهة الأمامية مع الواجهة الخلفية لتطبيق الويب أو الموقع الإلكتروني.
</p>

<p>
	هذا المقال هو جزء من سلسلة مقالات حول الواجهة البرمجية <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> وكيفية الاستفادة منها في بناء تطبيق ويب:
</p>

<ol>
	<li>
		مدخل إلى الواجهات البرمجية <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
	</li>
	<li>
		<a data-ss1631886109="1" data-ss1631887096="1" href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api-%D9%88%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-%D9%88%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D8%AD-r1318/" rel="">الاتصال بواجهة زد البرمجية وفهم عملية الاستيثاق والتصريح</a>
	</li>
	<li>
		<a data-ss1631885755="1" data-ss1631886109="1" data-ss1631887096="1" href="https://academy.hsoub.com/programming/general/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D9%84%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D8%AA%D8%A7%D8%AC%D8%B1-%D8%B2%D8%AF-zid-api-r1319/" rel="">أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a>
	</li>
	<li>
		<a data-ss1631885755="1" data-ss1631886109="1" data-ss1631887096="1" href="https://academy.hsoub.com/programming/javascript/nodejs/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%8A%D8%B2%D9%8A%D8%AF-%D9%85%D9%86-%D8%A7%D8%AD%D8%AA%D9%81%D8%A7%D8%B8-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D8%A7%D8%A1-%D8%B9%D8%A8%D8%B1-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%B2%D8%AF-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1320/" rel="">تطوير تطبيق عملي يزيد من احتفاظ العملاء عبر واجهة زد البرمجية</a>
	</li>
</ol>

<h2>
	مفهوم الواجهة البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	قبل أن ندخل في أية تفاصيل تقنية عن موضوعنا اليوم، سأحكي لك يومًا في حياة علي. علي هو مبرمج تطبيقات ويب يعمل في إحدى الشركات التقنية العربية، علي يحب تجربة المأكوﻻت المختلفة، بحيث يجرب في كل يوم أكلة جديدة في المطاعم المحيطة وإن سمع بافتتاح مطعم جديد بالقرب من مكان عمله، فإنه ﻻ يتوانى في زيارته وتذوق مختلف اﻷطباق التي يقدمها.
</p>

<p>
	ذهب علي ﻷحد المطاعم التي فتحت أبوابها مؤخرا، واختار مكانا هادئًا ونادى النادل يسأله عن اﻷطباق التي يقدمونها من أجل أن يأخذ طلبيته إلى الطباخ لتحضير ما طلبه علي. دوَّن النادل ما يريد علي تناوله من مأكوﻻت وذهب بها إلى الطباخ من أجل تحضيرها، بعد مدة وجيزة، عاد النادل إلى علي وهو يحمل كل ما طلبه وقدمها متمنيا أنه يعجبه اﻷكل، تذوق علي المأكوﻻت وأبدى إعجابه اﻷولي بها، وبدأ في اﻷكل إلى أن أنهى كل ما في الصحون، دفع الحساب، وخرج من المطعم شاكرا النادل على حسن اﻷستقبال.
</p>

<p>
	هل تتساءل اﻵن، ما علاقة هذه القصة بالواجهات البرمجية؟ وهل تساءلت يومًا عن طريقة عمل تطبيقات الهواتف الذكية، وكيف تتصل بخوادم الشركات المطورة لها، هل استطعت الوصول إلى إجابات كافية عن ذلك؟ سأبين لك ما العلاقة بين المثال السابق والواجهات البرمجية وكيف أن الواجهات البرمجية ماهي إﻻ تطبيق لمثالنا باختلاف بسيط وهو مكان التطبيق فقط، فمثالنا هو من الواقع الذي نعيشه يوميًا ونراه دائمًا حتى تعودنا عليه حتى أصبحنا ﻻ ندركه، أما الواجهات البرمجية، فقد أصبحت جزءًا ﻻ يتجزأ من حياة مبرمج المواقع وتطبيقات الويب المهنية.
</p>

<p>
	كنت قد نوهتك ﻷن تسأل نفسك عن طريقة ربط تطبيقات الهواتف الذكية مع خوادم الشركات. هنالك طريقتين لربط تطبيقات الهواتف الذكية مع خوادم الشركات المطورة، الطريقة اﻷقدم تسمى SOAP وهي اختصار لجملة Simple Object Access Protocol، أما الطريقة اﻷحدث فهي الواجهة البرمجيةللتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> وهي اختصار لجملة Application Programming Interface، وهي التي سأركز عليها، ولكن باختصار، <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> هي طريقة لتواصل البرمجيات في ما بينها باستخدام صيغة JavaScript Object Notation والتي تعرف اختصارا بـ JSON.
</p>

<p>
	لن أدخل في التفاصيل التاريخية وسأبقى مركزا على الجانب التقني فقط، لهذا أتوقع منك أن تحاول البحث عن تاريخ ابتكار وتطوير تقنية <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> والتقنية المكملة لها REST والتي هي اختصار لجملة <a data-ss1631886109="1" data-ss1631887096="1" href="https://academy.hsoub.com/programming/general/%D8%B4%D8%B1%D8%AD-%D9%81%D9%84%D8%B3%D9%81%D9%84%D8%A9-restful-%D8%AA%D8%B9%D9%84%D9%85-%D9%83%D9%8A%D9%81-%D8%AA%D8%A8%D9%86%D9%8A-%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-rest-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r635/" rel="">REpresentational State Transfer</a>.
</p>

<h2>
	مصطلحات وجب معرفتها
</h2>

<p>
	سنسرد بعض المصطلحات باللغة الإنجليزية والعربية الضروري على كل مطور ويب أن يعرفها:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-backend-web-development/" rel="">Backend</a>: الواجهة الخلفية، هي المسؤولة عن العمليات المنطقية للنظام، تتعامل مع الملفات أيضا ومع قواعد البيانات.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-frontend-web-development/" rel="">Frontend</a>: الواجهات الأمامية، كل ما يراه المستخدم ويتعامل معه بشكل مباشر، ويتم ربطها مع النظم الخلفية بما يعرف بالواجهة البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>.
	</li>
	<li>
		<abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>: الواجهة البرمجية للتطبيقات، هي حلقة الوصل ما بين النظم أو الواجهة الخلفية والواجهات الأمامية.
	</li>
	<li>
		Request: الطلب الذي يرسله العميل (قد تكون الواجهة الأمامية) إلى الخادم Server الموجود في الواجهة الخلفية.
	</li>
	<li>
		Header: ترويسة الطلب Request المرسل والذي يحوي بعض البيانات الوصفية التي تصف الطلبية وحالها وأية معلومات إضافية مطلوبة.
	</li>
	<li>
		Body: جسم أو متن الطلب المرسل والذي يحوي غالبًا على البيانات المتبادلة في الطلبية.
	</li>
	<li>
		Response: استجابة أو رد الخادم وهي المعلومات الراجعة من الخادم إلى العميل مقدم الطلب ردًا على طلبه. تحوي المعلومات الراجعة من الخادم إلى العميل على ترويسة Header وأيضا على متن Body.
	</li>
	<li>
		Endpoint: نقطة الوصول، وهي نقطة اتصال الواجهات الأمامية مع موقع محدد في الواجهة الخلفية أي نقطة محددة تتصل عبرها الواجهة الأمامية مع الواجهة الخلفية لغرض محدَّد.
	</li>
	<li>
		HTTP Client Software: عميل خادم HTTP وهو برنامج يساعد على تسريع التعامل مع الواجهات البرمجية بتوفير آلية واضحة في عملية إرسال واستقبال الطلبيات والردود.
	</li>
</ul>

<p>
	هل تعرفت على أي من المصطلحات التي ذكرناها قبل قليل؟ لا بأس إن لم تفعل، فسنشرحها لك حتى تكون لديك معرفة مبدئية بموضوع الواجهات البرمجية.
</p>

<h2>
	لماذا نستخدم الواجهات البرمجية للتطبيقات APIs وما هي فائدتها؟
</h2>

<p>
	تُعَد الواجهات البرمجية للتطبيقات طبقة الحماية الأولى First Security Layer للبرمجية الموجودة على خادم الويب، بسبب أنها تفصل ما بين النظم الخلفية والعمليات الجارية على قواعد البيانات عن الواجهات الأمامية سواءً كانت صفحات ويب عادية أو تطبيقات هواتف ذكية.
</p>

<p>
	أي أن أي تطبيق ويب أو موقع اليوم يتألف من واجهة خلفية وواجهة أمامية وواجهة برمجية تعد وصلة وصل بينهما. أما الواجهة الخلفية، فتحوي على كامل العمليات والإجراءات والخدمات التي يوفرها التطبيق أو الموقع مثل معالجة صورة أو بيانات أو حتى تقديم خدمة الطقس. أما الواجهة الأمامية فهي الواجهة التي يراها المستخدم والمسؤولة عن عرض البيانات القادمة من الواجهة الخلفية للمستخدم بصورة مناسبة ومتناسقة مع إرسال البيانات من المستخدم إلى الخادم بالشكل الذي يطلبها، فالبيانات المتبادلة تلك تكون بشكلها الخام (تستعمل غالبًا صيغة JSON أو حتى صيغة XML)، أما الواجهة البرمجية للتطبيقات  <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> فهي صلة الوصل كما ذكرنا ووظيفتها استلام البيانات من الواجهة الأمامية وتسلميها للواجهة الخلفية وإرسال البيانات من الواجهة الخلفية إلى الأمامية بطريقة وأسلوب موحد أي هي التي تؤمن عملية التفاهم بين الواجهة الأمامية والخلفية لتأمين التخاطب فيما بينهما.
</p>

<h2>
	كيف تعمل الواجهات البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	سأحاول قدر اﻹمكان تبسيط آلية عمل الواجهات البرمجية بمثال عملي من حياتنا اليومية، وليكن مثلا منصة فيسبوك. كما تعلم أنه بإمكانك الدخول إلى حسابك في فيسبوك من أي جهاز تريد، سواءً من هاتفك الذكي أو من جهازك اللوحي أو من جهاز الحاسوب بل بإمكانك الدخول منها مجتمعة وفي نفس الوقت، وهنا يجب أن تطرح سؤاﻻ مهمًا، كيف تتم مزامنة حسابك في كل تلك اﻷجهزة؟
</p>

<p>
	هنا تأتي أهمية الواجهة البرمجية، بحيث أن كل تلك اﻷجهزة متصلة بنظام خلفي واحد وكلها تتصل بالواجهة البرمجية التي تكون حلقة الوصل ما بين كل اﻷجهزة المتصلة و النظام الخلفي.
</p>

<p>
	سنأخذ مثاﻻ من حياتنا اليومية وهو موقع فيسبوك، سنقوم بالدخول إلى حسابنا باستخدام الأجهزة التي بحوزتنا، إن لم تكن لديك أجهزة غير جهاز الحاسوب، افتح أكثر من متصفح، ليس نفس المتصفح، مثلا متصفح كروم Google Chrome ومتصفح فايرفوكس Mozilla Firefox، في هذه الحالة يمكنك فتح حسابك 4 مرات باستخدام التصفح الخفي، في متصفح كروم يسمى Incognito Mode أما في متصفح فايرفوكس فيسمى Private Mode. هل قمت بذلك؟ كيف تستطيع إرسال رسائل إلى أصدقائك من أي متصفح وتشاهدها في نفس الوقت من بقية المتصفحات؟
</p>

<p>
	قم بالدخول إلى حسابك على فيسبوك من هاتفك الذكي، من التطبيق الرسمي أو من المتصفح، هل تستطيع أن ترى الرسائل التي قمت بإرسالها على هاتفك أيضا، كيف يحدث ذلك؟ كيف تستطيع الدخول إلى حسابك من أماكن مختلفة في نفس الوقت؟
</p>

<p>
	سأشرح العملية بأكملها بشكل بسيط وبالمقارنة مع مثالنا في بداية المقال وبدون الدخول في التفاصيل الدقيقة في الوقت الحالي.
</p>

<p>
	عند دخول علي مطور الويب إلى المطعم، كان عليه أن يختار طاولة محددة برقم حتى يعلم النادل موقعه وأنه يريد تناول الطعام وبالتالي يستطيع تقديم مختلف الخدمات التي يعرضها المطعم. هنا الطاولة وتفاصيلها (من رقم وحجم وغيرهما) تعتبر المكان المتفق عليه من أجل اﻹستفادة من خدمات المطعم، ويمكن القول أنها نقطة الوصول إلى خدمات المطعم Endpoint.
</p>

<p>
	في حالة موقع فيسبوك، وعند قيامك فتح التطبيق مثلا، سيتصل تطبيقك بخادم الشركة، في نقطة متفق عليها ومحددة مسبقًا في التطبيق وفيها فقط يستطيع الخادم أن يقدم خدماته للتطبيق.
</p>

<p>
	جاء النادل إلى عليٍ والذي يسمى العميل client ليأخذ الطلبات منه، ودون أية ملاحظات أو أي خدمات أخرى، وبعدها ذهب إلى المطبخ ليخبر الطباخ بالطلبات من أجل تحضيرها. هنا نسمي العملية: إرسال طلب Send Request من العميل علي إلى الطباخ في المطعم مقدمة الخدمة. في حالة موقع فيسبوك، أقرب عملية لذلك المثال عملية تسجيل الدخول حيث تُدخل اسم المستخدم الخاص بك مع كلمة المرور، تأخذ الواجهة الأمامية منك هذه المعلومات وترسلها للواجهة الخلفية لموقع فيسبوك لتتحقق منها ومن الطلب الخاص بك، طلب تسجيل الدخول.
</p>

<p>
	يستلم الطباخ الطلبية ويتأكد من أنها طلبية صالحة ويمكنك تحضيرها (أي ليست طلبية شراء ملابس مثلًا) ثم يبدأ بتحضيرها وعندما ينتهي منها، يعطيها للنادل الذي يرتبها بدوره في صينية ويأخذها إلى علي ليضعها على طاولته حتى يتسنى له البدء في تذوقها. هذه العملية تسمى: اﻹستجابة Send Response أي استجاب الطباخ لطلبية علي وقدم له ما يريد. وفي حالة موقع فيسبوك، إن كانت المعلومات المقدمة صالحة، سيقوم خادم فيسبوك بالسماح لك بالدخول واستعراض مختلف الصفحات واﻷجزاء الخاصة به والاستفادة من خدمته التي يقدمها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="76837" data-ss1631886109="1" data-ss1631887096="1" href="https://academy.hsoub.com/uploads/monthly_2021_09/613f975fa6c40_APIdiagram.png.0300721837ad498d3f8069eebb142c64.png" rel=""><img alt="API diagram.png" class="ipsImage ipsImage_thumbnailed" data-fileid="76837" data-unique="wmyhuczdd" src="https://academy.hsoub.com/uploads/monthly_2021_09/613f97607024e_APIdiagram.thumb.png.c16fcef990e403ec35d11e2dabf2be62.png"></a>
</p>

<p>
	هل اتضحت الصورة العامة اﻵن؟
</p>

<p>
	ببساطة، الواجهة البرمجية تنفذ عمل النادل في المطعم، حيث أن النادل يقوم بأخذ طلبات الزبائن إلى الطباخ وفريقه لتحضيرها وبعد ذلك، يقوم بأخذ تلك استجابة الطباخ لتلك الطلبات إلى أصحابها، أي أن الواجهة البرمجية تأخذ الطلبات من المستخدمين (الواجهة الأمامية) إلى النظام الخلفي لتقوم بعمل محدد ومن ثم تعيد النتائج المتحصل عليها إلى طالبيها أي تعيدها للواجهة الأمامية مرةً أخرى.
</p>

<h2>
	خاتمة
</h2>

<p>
	تعرفنا على ماهية الواجهة البرمجية للتطبيقات وأهم المصطلحات فيها وكيف يستفيد منها المطورون في بناء تطبيقات الويب الحديثة واستثمارها في التواصل ما بين الواجهة الأمامية والخلفية لتطبيقات الويب والمواقع الحالية، فالتعامل مع الواجهة البرمجية للتطبيقات ضروري لأي مبرمج متخصص في <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8/" rel="">تطوير الويب</a>، وعليه أن يعي مفهوم الواجهة البرمجة تمامًا إذ أصبح هذا المفهوم هو المفهوم الحديث في التواصل ما بين الواجهة البرمجية الخلفية والأمامية للمواقع وتطبيقات الويب، أضف إلى ذلك أن الكثير من الخدمات والمواقع أصبحت تتيح واجهتها البرمجية (مثل الواجهة البرمجية للمطورين من فيسبوك وتويتر وغيرهما) للاستفادة منها أو حتى هنالك واجهة برمجية مخصصة فقط لتقديم خدمات محددة (مثل واجهة برمجية للحصول على معلومات الطقس) وتقدمها للمطورين للاستفادة من تلك الخدمات في مختلف المشاريع.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a data-ss1631886109="1" data-ss1631887096="1" href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api-%D9%88%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-%D9%88%D8%A7%D9%84%D8%AA%D8%B5%D8%B1%D9%8A%D8%AD-r1318/" rel="">الاتصال بواجهة زد البرمجية وفهم عملية الاستيثاق والتصريح</a>
	</li>
	<li>
		<a data-ss1631886109="1" data-ss1631887096="1" href="https://academy.hsoub.com/apps/web/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%AA%D8%AC%D8%B1-%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-%D9%85%D8%AA%D9%83%D8%A7%D9%85%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%85%D9%86%D8%B5%D8%A9-%D8%B2%D8%AF-r440/" rel="">كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد</a>
	</li>
	<li>
		<a data-ss1631886109="1" data-ss1631887096="1" href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-fetch-api-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1297/" rel="">الواجهة البرمجية Fetch <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> في جافاسكريبت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1314</guid><pubDate>Fri, 10 Sep 2021 15:00:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x642;&#x631;&#x627;&#x621;&#x629; &#x627;&#x644;&#x628;&#x631;&#x627;&#x645;&#x62C; &#x644;&#x645;&#x62F;&#x62E;&#x644;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x633;&#x62A;&#x62E;&#x62F;&#x645;</title><link>https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-r1311/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_09/6138951edbe72_---.png.4d8ec06429623d6d6fefff043e41cd35.png" /></p>
<p>
	تعاملت البرامج التي كتبناها في المقالات السابقة مع بيانات ثابتة، نستطيع فحصها -عند الحاجة- قبل أن يستخدمها البرنامج، ونصمم البرنامج ليناسب تلك البيانات، لكن الواقع يقول أن أغلب البرامج تتصرف وفقًا لمدخلات المستخدم، حيث يخبر المستخدم البرنامج بالملف التي يجب عليه فتحه أو تعديله مثلًا، وقد يطلب البرنامج من المستخدم بيانات ضروريةً، ويشار إلى مثل هذا المنظور البرمجي باسم واجهة المستخدم، وتصميم وبناء هذه الواجهة في السوق البرمجي وظيفة متخصصين في التفاعل بين الآلة والبشر، وفي كيفية تصميم بيئات العمل؛ أما المبرمج العادي فليس لديه تلك الرفاهية، فهو يتصرف بما لديه من منطق، ويفكر مليًا في كيفية تفاعل المستخدمين مع برنامجه أثناء استخدامه. وأبسط ميزة لواجهة المستخدم هي عرض المخرجات، وقد شرحنا ذلك من قبل بطرق بدائية وبسيطة، باستخدام الدالة <code>print</code> في بايثون، والدالة <code>write()‎</code> في جافاسكربت، وصندوق <code>MsgBox</code> الحواري في VBScript.
</p>

<p>
	تتمثل الخطوة التالية في تصميم واجهة المستخدم في أخذ المدخلات من المستخدم مباشرةً، وأبسط طريقة لفعل ذلك هي جعل البرنامج يطلب الدخل في وقت التشغيل، أو جعل المستخدم يمرر البيانات عندما يشغِّل البرنامج، أو -في الحالة المتقدمة- تكون لدينا واجهة رسومية فيها صناديق إدخال للنصوص مثلًا.
</p>

<p>
	سنشرح في هذا المقال الطريقتين الأولى والثانية فقط، ونترك الواجهة الرسومية لوقت لاحق من هذه السلسلة لأنها أكثر تعقيدًا، غير أن هناك وحدةً تسمح لنا بتنفيذ صناديق حوارية رسومية بسيطة، وسندرِجها في هذا المقال أيضًا.
</p>

<p>
	سنرى الآن كيف نستطيع الحصول على البيانات من المستخدم في جلسة بايثون تفاعلية عادية تعمل في IDLE، أو في طرفية نظام التشغيل، ثم نحاول الحصول على نفس البيانات داخل برنامج.
</p>

<h2>
	دخل المستخدم في بايثون
</h2>

<p>
	نحصل على ما يدخله المستخدم في بايثون بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_15" style=""><span class="pun">&gt;&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Type something: "</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	تعرض <code>input()‎</code> المحث المعطى، وهو "Type something" في حالتنا، وتلتقط أي شيء يكتبه المستخدم، ثم تعرض <code>print()‎</code> تلك الإجابة، ونستطيع إسناد ما يدخله المستخدم إلى متغير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_17" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> resp </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"What's your name? "</span><span class="pun">)</span></pre>

<p>
	يمكننا طباعة أي قيمة يلتقطها ذلك المتغير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_19" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Hi "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> resp </span><span class="pun">+</span><span class="pln"> </span><span class="str">", nice to meet you"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ أننا لم نستخدم هذه المرة عامل تنسيق السلسلة النصية لعرض القيمة المخزَّنة في المتغير <code>resp</code>، واكتفينا بإدراج القيمة بين سلسلتين نصيتين، ودمجنا السلاسل الثلاث باستخدام عامل إضافة السلاسل النصية <code>+</code>، وقيمة المتغير <code>resp</code> هي التي التُقطت من المستخدم بواسطة <code>input()‎</code>.
</p>

<p>
	لاحظ كيف استخدمنا المسافات داخل السلاسل النصية التي في المحث المعطى إلى <code>input()‎</code> وسلسلة الخرج، وانظر الجزء الثالث من سلسلة الخرج الذي يبدأ بالفاصلة المتبوعة بمسافة، إذ يخطئ الكثيرون في أماكن تلك المسافات عند إنتاج خرج كهذا، لذا تفحص مثل هذه المواضع جيدًا عند اختبارك للبرامج.
</p>

<p>
	قرأ المثال السابق السلاسل النصية، لكن ماذا عن أنواع البيانات الأخرى؟ نجيب على هذا السؤال بأن بايثون تأتي بمجموعة كاملة من دوال تحويل البيانات، التي تستطيع تحويل سلسلة نصية إلى نوع بيانات آخر، مع وجوب أن تكون البيانات التي في السلسلة النصية متوافقةً مع ذلك النوع وإلا فسنحصل على خطأ، ولنعدل مثلًا جدول الضرب الذي ذكرناه من قبل، ليقرأ قيمة المضاعف من المستخدم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_21" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> multiplier </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Which multiplier do you want? Pick a number "</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> multiplier </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">multiplier</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> j </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">13</span><span class="pun">):</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%d x %d = %d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j</span><span class="pun">,</span><span class="pln"> multiplier</span><span class="pun">,</span><span class="pln"> j </span><span class="pun">*</span><span class="pln"> multiplier</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	نقرأ في هذا المثال القيمة من المستخدم، ثم نحولها إلى عدد صحيح باستخدام دالة التحويل <code>int()‎</code>، كما يمكننا تحويلها إلى عدد ذي فاصلة عائمة باستخدام <code>float()‎</code> عند الحاجة إلى ذلك، ونفذنا التحويل هنا في سطر منفصل لنفصّل الخطوات لتبسيط الشرح، أما في البرمجة في سوق العمل من الشائع تغليف استدعاء <code>input()‎</code> داخل التحويل كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_24" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> multiplier </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Which multiplier do you want? Pick a number "</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> j </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">13</span><span class="pun">):</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%d x %d = %d"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j</span><span class="pun">,</span><span class="pln"> multiplier</span><span class="pun">,</span><span class="pln"> j </span><span class="pun">*</span><span class="pln"> multiplier</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	غلفنا استدعاء <code>input()‎</code> داخل استدعاء <code>int()‎</code>، لنجرب تطبيق هذا في برنامج حقيقي، وسنستخدم برنامج دليل جهات الاتصال الذي أنشأناه باستخدام قاموس في مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A7%D9%84%D8%AA%D8%AC%D9%85%D9%8A%D8%B9%D8%A7%D8%AA-collections-r1288/" rel="">البيانات وأنواعها</a> بما أننا نستطيع كتابة الحلقات التكرارية وقراءة بيانات الإدخال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_26" style=""><span class="com"># أنشئ قاموس فارغًا لدليل جهات اتصال</span><span class="pln">
addressBook </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">

</span><span class="com"># اقرأ المدخلات إلى أن تصل إلى سلسلة فارغة</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">()</span><span class="pln">  </span><span class="com"># print a blank line </span><span class="pln">
name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Type the Name(leave blank to finish): "</span><span class="pun">)</span><span class="pln"> 
</span><span class="kwd">while</span><span class="pln"> name </span><span class="pun">!=</span><span class="pln"> </span><span class="str">""</span><span class="pun">:</span><span class="pln">
   entry </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Type the Street, Town, Phone.(Leave blank to finish): "</span><span class="pun">)</span><span class="pln">
   addressBook</span><span class="pun">[</span><span class="pln">name</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> entry
   name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Type the Name(leave blank to finish): "</span><span class="pun">)</span><span class="pln">

</span><span class="com"># والآن، اطلب عرض واحد منها</span><span class="pln">
name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Which name to display?(leave blank to finish): "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> name </span><span class="pun">!=</span><span class="pln"> </span><span class="str">""</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> addressBook</span><span class="pun">[</span><span class="pln">name</span><span class="pun">]</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
   name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Which name to display?(leave blank to finish): "</span><span class="pun">)</span></pre>

<p>
	لعل هذا البرنامج هو أكبر برنامج كتبناه حتى الآن، إذ يشمل تسلسلات وحلقتين تكراريتين، وعلى الرغم من أن تصميم واجهة المستخدم فيه ليس مثاليًا؛ إلا أنه يؤدي الغرض المطلوب منه، وسنرى كيفية تطوير هذه الواجهة في مقالات تالية؛ أما الآن فنريد الإشارة إلى استخدام الاختبار البولياني في حلقات <code>while</code> لتحديد رغبة المستخدم في التوقف، لاحظ أيضًا أننا مع استخدامنا لقائمة في مقال <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87%D8%A7-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r1287/" rel="">مدخل إلى البيانات وأنواعها: أنواع البيانات الأساسية</a> لتخزين البيانات في حقول منفصلة، إلا أننا خزنّاها هنا في سلسلة نصية واحدة، لأننا لم نشرح كيفية تقسيم السلسلة النصية إلى حقول منفصلة بعد.
</p>

<h2>
	الإدخال في لغة VBScript
</h2>

<p>
	تقرأ تعليمات InputBox في لغة VBScript دخل المستخدم كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4921_28" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> </span><span class="typ">Input</span><span class="pln">
</span><span class="typ">Input</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Enter your name"</span><span class="pun">)</span><span class="pln"> 
</span><span class="typ">MsgBox</span><span class="pln"> </span><span class="pun">(</span><span class="str">"You entered: "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="typ">Input</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	تمثل دالة <code>InputBox</code> صندوقًا حواريًا مع محث وحقل إدخال، وتعيد محتويات حقل الإدخال، وهناك عدة قيم يمكن تمريرها إليها، مثل سلسلة عنوان الصندوق الحواري، إضافةً إلى المحث، فإذا ضغط المستخدم زر الإلغاء Cancel، فستعيد الدالة سلسلةً فارغةً بغض النظر عن محتويات حقل الإدخال.
</p>

<p>
	سيبدو مثال دليل الاستخدام في لغة VBScript كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4921_30" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">Dim</span><span class="pln"> dict</span><span class="pun">,</span><span class="pln">name</span><span class="pun">,</span><span class="pln">entry  </span><span class="str">'</span><span class="pln"> </span><span class="typ">Create</span><span class="pln"> some variables</span><span class="pun">.</span><span class="pln">
</span><span class="typ">Set</span><span class="pln"> dict </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CreateObject</span><span class="pun">(</span><span class="str">"Scripting.Dictionary"</span><span class="pun">)</span><span class="pln">
name </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Enter a name"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Address Book Entry"</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Do</span><span class="pln"> </span><span class="typ">While</span><span class="pln"> name </span><span class="pun">&lt;&gt;</span><span class="pln"> </span><span class="str">""</span><span class="pln">
   entry </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Enter Details - Street, Town, Phone number"</span><span class="pun">,</span><span class="pln">
                    </span><span class="str">"Address Book Entry"</span><span class="pun">)</span><span class="pln">
   dict</span><span class="pun">.</span><span class="typ">Add</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> entry </span><span class="str">'</span><span class="pln"> </span><span class="typ">Add</span><span class="pln"> key and details</span><span class="pun">.</span><span class="pln">
   name </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Enter a name"</span><span class="pun">,</span><span class="str">"Address Book Entry"</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Loop</span><span class="pln">

</span><span class="str">'</span><span class="pln"> </span><span class="typ">Now</span><span class="pln"> read back the values
name </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Enter a name"</span><span class="pun">,</span><span class="str">"Address Book Lookup"</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Do</span><span class="pln"> </span><span class="typ">While</span><span class="pln"> name </span><span class="pun">&lt;&gt;</span><span class="pln"> </span><span class="str">""</span><span class="pln">
   </span><span class="typ">MsgBox</span><span class="pun">(</span><span class="pln">name </span><span class="pun">&amp;</span><span class="pln"> </span><span class="str">" - "</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> dict</span><span class="pun">.</span><span class="typ">Item</span><span class="pun">(</span><span class="pln">name</span><span class="pun">))</span><span class="pln">
   name </span><span class="pun">=</span><span class="pln"> </span><span class="typ">InputBox</span><span class="pun">(</span><span class="str">"Enter a name"</span><span class="pun">,</span><span class="str">"Address Book Lookup"</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Loop</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لاحظ أن الهيكل الأساسي هنا مطابق تمامًا لبرنامج بايثون، مع أن بعض الأسطر أطول هنا بسبب الحاجة إلى التصريح المسبق عن المتغيرات باستخدام <code>Dim</code> في VBScript، وبسبب الحاجة إلى تعليمة <code>Loop</code> لإنهاء كل حلقة.
</p>

<h2>
	قراءة المدخلات في جافاسكربت
</h2>

<p>
	تمثل جافاسكربت تحديًا في هذا المجال لأنها تعمل أساسًا داخل المتصفحات، ولقراءة المدخلات يمكننا استخدام صندوق إدخال بسيط كما في VBScript باستخدام دالة <code>prompt()‎</code>، أو قراءة المدخلات من عنصر استمارة في HTML، أو استخدام تقنية Active Scripting الخاصة بمايكروسوفت -وذلك في إنترنت إكسبلورر فقط- لتوليد صندوق <code>InputBox</code> كما في VBSCript، ولتنويع الأمثلة سنشرح كيفية استخدام تقنية عنصر الاستمارة في HTML، فإذا لم تكن تعرضت للغة HTML من قبل فانظر <a href="https://wiki.hsoub.com/HTML" rel="external">توثيقها في موسوعة حسوب</a>، أو انسخ ما سنكتبه هنا إذا شئت.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4921_32" style=""><span class="pun">&lt;</span><span class="pln">form id</span><span class="pun">=</span><span class="str">'entry'</span><span class="pln"> name</span><span class="pun">=</span><span class="str">'entry'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Type</span><span class="pln"> a value then click outside the field </span><span class="kwd">with</span><span class="pln"> your mouse</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">'text'</span><span class="pln"> name</span><span class="pun">=</span><span class="str">'data'</span><span class="pln"> 
          onChange</span><span class="pun">=</span><span class="str">'alert("We got a value of " + document.forms["entry"].data.value);'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span></pre>

<p>
	تتكون شيفرة HTML أعلاه من عنصر استمارة <code>form</code> الذي يحتوي على فقرة <code>&lt;p&gt;</code> من سطر واحد، حيث يمثل رسالةً إلى المستخدم، وحقل إدخال نصي <code>input</code>، يحتوي على شيفرة من سطر واحد مرتبطة به، تنفَّذ في كل مرة تتغير فيها القيمة المدخلة، ووظيفة هذه الشيفرة ببساطة، أن تخرِج صندوق رسالة <code>alert</code> يشبه ذاك الذي في VBScript، ويحتوي على القيمة التي في الحقل النصي.
</p>

<p>
	كما نرى في أول سطر في الشيفرة، فإن للاستمارة خاصيتين هما <code>id</code> و <code>name</code>، وتحتويان على القيمة <code>entry</code>، وتُخزَّن الاستمارات في سياق المستند <code>document</code> داخل مصفوفة مفهرسة بالاسم، لأنه يمكن استخدام مصفوفات جافاسكربت مثل القواميس كما ذكرنا من قبل، ويحتوي حقل <code>input</code> على الخاصية <code>name</code> التي تحمل القيمة <code>data</code> داخل سياق الاستمارة، ومع ذلك نستطيع الإشارة إلى قيمة <code>value</code> حقل ما داخل برنامج جافاسكربت كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4921_34" style=""><span class="pln">document</span><span class="pun">.</span><span class="pln">forms</span><span class="pun">[</span><span class="str">"entry"</span><span class="pun">].</span><span class="pln">data</span><span class="pun">.</span><span class="pln">value</span></pre>

<p>
	لن نشرح هنا مثال دليل جهات الاتصال في جافاسكربت، لأن HTML ستتعقَّد وسنحتاج إلى شرح الدوال، لذا سنؤجل هذا إلى مقال تال.
</p>

<h2>
	مجاري الدخل والخرج القياسية
</h2>

<p>
	ننظر الآن في أحد المفاهيم الأساسية في حوسبة سطر الأوامر، وهو مفهوم مجاري البيانات data streams، فمصطلح <code>stdin</code> هو أحد المصطلاحات الحاسوبية التي تشير إلى جهاز الدخل القياسي standard input device، وهو عادةً لوحة المفاتيح، وبالمثل يشير <code>stdout</code> إلى جهاز الخرج القياسي، وهو الشاشة عادةً، وسنرى إشارات كثيرةً إلى هذين المصطلحين عند الحديث عن البرمجة، كما يوجد مصطلح ثالث لا يُستخدم كثيرًا، وهو <code>stderr</code> الذي يشير إلى المكان الذي ترسَل إليه جميع أخطاء الطرفية، ويظهر عادةً في نفس مكان stdout، ويطلق على هذه المصطلحات اسم مجاري البيانات، لأن البيانات تظهر في صورة مجارٍ من البايتات التي تتدفق إلى الأجهزة، وقد أُعدَّ كل من stdin وstdout ليشبها الملفات، ليتوافقا مع شيفرة معالجة الملفات.
</p>

<p>
	وتوجد هذه المصطلحات في لغة بايثون داخل الوحدة <code>sys</code>، وتسميان <code>sys.stdin</code> و<code>sys.stdout</code>، وتستخدم الدالة <code>input()‎</code> تلقائيًا stdin، بينما تستخدم <code>print()‎</code> الخرج القياسي stdout.
</p>

<p>
	نستطيع أن نقرأ من الدخل القياسي stdin، وأن نكتب مباشرةً في الخرج القياسي stdout، مما يسمح لنا بتحكم دقيق في الدخل والخرج، لننظر في المثال التالي إلى القراءة من الدخل القياسي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4921_36" style=""><span class="kwd">import</span><span class="pln"> sys
print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Type a value: "</span><span class="pun">,</span><span class="pln"> end</span><span class="pun">=</span><span class="str">''</span><span class="pun">)</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">تمنع</span><span class="pln"> </span><span class="pun">السطر</span><span class="pln"> </span><span class="pun">الجديد</span><span class="pln">
value </span><span class="pun">=</span><span class="pln"> sys</span><span class="pun">.</span><span class="pln">stdin</span><span class="pun">.</span><span class="pln">readline</span><span class="pun">()</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">صراحة</span><span class="pln"> stdin </span><span class="pun">استخدم</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> value </span><span class="pun">)</span></pre>

<p>
	تطابق الشيفرة أعلاه تقريبًا الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4921_39" style=""><span class="pln">print</span><span class="pun">(</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Type a value: "</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	إن ميزة النسخة الصريحة هنا أننا نستطيع جعل الدخل القياسي يشير إلى ملف حقيقي، ليقرأ البرنامج الدخل الخاص به من الملف عوضًا عن الطرفية، وهذه الطريقة مفيدة في حالة جلسات الاختبار الطويلة التي يقرأ البرنامج فيها مدخلاته من ملف بدلًا من الجلوس وكتابة الدخل يدويًا كلما طلبه البرنامج، مما يضمن تكرار تشغيل الاختبار مع ثبات الدخل في كل مرة، وكذلك الخرج، وتسمى هذه التقنية -التي تكرر الاختبارات السابقة لضمان عدم تعطل شيء في الشيفرة- باسم الاختبار الارتدادي regression testing.
</p>

<p>
	وأخيرًا لدينا مثال عن خرج مباشر إلى <code>sys.stdout</code>، ويمكن إعادة توجيهه إلى ملف كذلك، وتكافئ الدالة <code>print</code> ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4921_41" style=""><span class="pln">sys</span><span class="pun">.</span><span class="pln">stdout</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"Hello world\n"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> \n</span><span class="pun">=</span><span class="pln"> newline</span></pre>

<p>
	لا شك أننا نستطيع تحقيق نفس النتيجة باستخدام سلاسل التنسيق النصية، إذا كنا نعرف الشكل الذي ستكون البيانات عليه، لكن إذا لم نعرف شكلها إلا وقت التشغيل، فمن الأسهل أن نرسلها إلى الخرج القياسي، بدلًا من محاولة بناء سلسلة تنسيق معقدة وقت التشغيل.
</p>

<h3>
	إعادة توجيه الدخل والخرج القياسيين
</h3>

<p>
	يمكن توجيه الدخل والخرج القياسيين إلى ملفات من داخل برنامجنا مباشرةً، باستخدام تقنيات بايثون المعتادة للتعامل مع الملفات، والتي سنشرحها فيما يلي، لكن الطريقة الأسهل هي من خلال نظام التشغيل، تتصرف أوامر النظام عند استخدام إعادة التوجيه في سطر الأوامر كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4921_43" style=""><span class="pln">C</span><span class="pun">:&gt;</span><span class="pln"> dir
C</span><span class="pun">:&gt;</span><span class="pln"> dir </span><span class="pun">&gt;</span><span class="pln"> dir</span><span class="pun">.</span><span class="pln">txt</span></pre>

<p>
	يطبع الأمر الأول قائمةً من المجلدات على الشاشة -والتي تمثل الخرج القياسي-، بينما يطبع الأمر الثاني تلك القائمة إلى ملف، فقد أخبرنا البرنامج أن يوجه الخرج القياسي إلى الملف <code>dir.txt</code>، ويمكن فعل نفس الشيء مع برنامج بايثون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_45" style=""><span class="pln">$ python myprogram</span><span class="pun">.</span><span class="pln">py </span><span class="pun">&gt;</span><span class="pln"> result</span><span class="pun">.</span><span class="pln">txt</span></pre>

<p>
	ستشغّل الشيفرة السابقة البرنامج <code>myprogram.py</code>، وستكتب الخرج إلى الملف <code>result.txt</code> بدلًا من كتابته على الشاشة، ونستطيع رؤية الخرج لاحقًا باستخدام محرر نصي، لاحظ أن محث علامة الدولار <code>$</code> هو المحث القياسي لمستخدمي لينكس وماك.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		يمكن إعادة توجيه خرج الدالة <code>print</code> باستخدام الوسيط الاختياري <code>‎file="result.txt"‎</code>، وتتيح هذه الطريقة التحكم في كل تعليمة، لكن يصعب كتابتها في البرنامج، وهي مناسبة لطباعة مجموعة فرعية بعينها من خرج البرنامج، ولا يفضل استخدامها في حفظ الخرج إلى ملف، وحتى في حالة المجموعة الفرعية يفضَّل توجيه الخرج إلى ملف، لذا لا يُستخدم خيار <code>file=‎</code> كثيرًا.
	</p>
</blockquote>

<p>
	نستخدم علامة <code>‎&lt;‎</code> بدلًا من <code>‎&gt;‎</code> لتوجيه الدخل القياسي إلى ملف، ننشئ في المثال التالي ملفًا باسم <code>echoinput.py</code> يحتوي على الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_47" style=""><span class="kwd">import</span><span class="pln"> sys
inp </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> inp </span><span class="pun">!=</span><span class="pln"> </span><span class="str">''</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> inp </span><span class="pun">)</span><span class="pln">
   inp </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">()</span></pre>

<p>
	نستطيع الآن تشغيل الملف من سطر الأوامر كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_49" style=""><span class="pln">$ python echoinput</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	يجب أن تكون النتيجة برنامجًا يعيد طباعة أي شيء تكتبه إلى أن تكتب سطرًا فارغًا، والآن أنشئ ملفًا نصيًا بسيطًا باسم <code>input.txt</code> يحتوي بعض الأسطر النصية، وشغّل البرنامج الأخير مرةً أخرى معيدًا توجيه الدخل من <code>input.txt</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_51" style=""><span class="pln">$ python echoinput</span><span class="pun">.</span><span class="pln">py </span><span class="pun">&lt;</span><span class="pln"> input</span><span class="pun">.</span><span class="pln">txt</span></pre>

<p>
	ستعيد بايثون طباعة الأسطر النصية الموجودة في الملف.
</p>

<p>
	نستطيع اختبار عدة سيناريوهات على برامجنا بسهولة إذا استخدمنا تلك التقنية على عدة ملفات، مثل قيم البيانات المعطوبة أو أنواع البيانات الخاطئة، وننفذ ذلك بأسلوب موثوق قابل للتكرار، كما نستطيع استخدامها لمعالجة البيانات كبيرة الحجم من ملف، مع السماح بالإدخال اليدوي للبيانات صغيرة الحجم باستخدام نفس البرنامج، وهكذا نرى أن الدخل والخرج القياسيين مفيدان جدًا للمبرمجين.
</p>

<h2>
	معاملات سطر الأوامر
</h2>

<p>
	لدينا نوع آخر من الإدخال، وهو الإدخال من سطر الأوامر، كما في حالة تشغيل المحرر النصي من سطر أوامر النظام:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_53" style=""><span class="pln">  $ edit </span><span class="typ">Foo</span><span class="pun">.</span><span class="pln">txt</span></pre>

<p>
	يستدعي نظام التشغيل هنا البرنامج الذي يحمل الاسم <code>edit</code>، ليمرر إليه اسم الملف الذي نريد تعديله، وهو <code>Foo.txt</code> هنا. لكن كيف يقرأ المحرر اسم الملف؟، يوفر نظام التشغيل في أغلب لغات البرمجة مصفوفةً أو قائمةً من سلاسل نصية تحتوي كلمات سطر الأوامر، وبناءً عليه سيحتوي العنصر الأول على الأمر نفسه، ثم يحتوي العنصر التالي على الوسيط الأول وهكذا، وقد توجد بعض المتغيرات السحرية هنا والتي يُطلق عليها argc، وهي اختصار argument count، وتحمل عدد العناصر الموجودة في القائمة، وتحتفظ الوحدة <code>sys</code> في بايثون بهذه القائمة وتسميها <code>argv</code>، وهي اختصار argument values، وأول عنصر فيها <code>argv[0]‎</code> هو اسم ملف السكربت الذي ينفَّذ، ولا تحتاج بايثون قيمةً من النوع <code>argc</code> لأننا نستطيع استخدام التابع <code>len()‎</code> لإيجاد طول السلسلة، بل لا نحتاج إلى ذلك أصلًا في أغلب الحالات، لأننا نمر على القائمة باستخدام حلقة <code>for</code> الخاصة ببايثون:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4921_55" style=""><span class="kwd">import</span><span class="pln"> sys
</span><span class="kwd">for</span><span class="pln"> item in sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">:</span><span class="pln">
    print</span><span class="pun">(</span><span class="pln"> item </span><span class="pun">)</span><span class="pln">

print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"The first argument was:"</span><span class="pun">,</span><span class="pln"> sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ أن هذه الشيفرة لا تعمل إلا إذا وُضعت في ملف مثل <code>args.py</code>، ونُفذت من محث نظام التشغيل كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_57" style=""><span class="pln">C</span><span class="pun">:</span><span class="pln">\PYTHON\PROJECTS</span><span class="pun">&gt;</span><span class="pln"> python args</span><span class="pun">.</span><span class="pln">py </span><span class="lit">1</span><span class="pln"> </span><span class="lit">23</span><span class="pln"> fred
args</span><span class="pun">.</span><span class="pln">py
</span><span class="lit">1</span><span class="pln">
</span><span class="lit">23</span><span class="pln">
fred
</span><span class="typ">The</span><span class="pln"> first argument was</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
C</span><span class="pun">:</span><span class="pln">\PYTHON\PROJECTS</span><span class="pun">&gt;</span></pre>

<p>
	يجب إحاطة اسم الوسيط بعلامات اقتباس إذا احتوى على مسافات، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4921_59" style=""><span class="pln">C</span><span class="pun">:</span><span class="pln">\PYTHON\PROJECTS</span><span class="pun">&gt;</span><span class="pln"> python args</span><span class="pun">.</span><span class="pln">py </span><span class="str">"Alan Gauld"</span><span class="pln"> fred
args</span><span class="pun">.</span><span class="pln">py
</span><span class="typ">Alan</span><span class="pln"> </span><span class="typ">Gauld</span><span class="pln">
fred
</span><span class="typ">The</span><span class="pln"> first argument was</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Alan</span><span class="pln"> </span><span class="typ">Gauld</span><span class="pln">
C</span><span class="pun">:</span><span class="pln">\PYTHON\PROJECTS</span><span class="pun">&gt;</span></pre>

<h3>
	جافاسكربت وVBscript
</h3>

<p>
	لا نرى مفهوم وسائط سطر الأوامر في هاتين اللغتين لأنهما موجهتان للعمل داخل المتصفحات، فإذا استخدمناهما داخل بيئة <a href="https://docs.microsoft.com/de-de/previous-versions/windows/it-pro/windows-server-2003/cc738350(v=ws.10)" rel="external nofollow">Windows Script Host</a> الخاصة بمايكروسوفت، فستوفر بيئة WSH آليةً لاستخراج مثل تلك الوسائط من كائن <code>WshArguments</code> الذي تملؤه WSH في وقت التشغيل.
</p>

<h2>
	خاتمة
</h2>

<p>
	لن نذهب أبعد من هذا الحد في شأن مدخلات المستخدم في هذه السلسلة، وهو الحد الذي يمكننا من كتابة برامج مفيدة، وقد كان ذلك كل ما يستطيعه المبرمج في الأيام الأولى لأنظمة يونكس أو لمبرمجي الحواسيب الشخصية، ولا شك أن البرامج الرسومية تقرأ المدخلات من المستخدم، لكن التقنيات التي تستخدمها مختلفة كليًا، لهذا سنؤجلها إلى مقالات لاحقة من هذه السلسلة.
</p>

<p>
	تعلمنا في هذا المقال استخدام الدالة <code>input()‎</code> لقراءة السلاسل النصية، وعرفنا أنها تعرض سلسلةً تطلب إدخالًا من المستخدم، كما تعرفنا إلى الدخل والخرج القياسيين لمجاري البيانات، وكيفية إعادة توجيههما ليكونا في صورة ملفات، وعرفنا أن <code>input()‎</code> تعمل مع stdin، وأن <code>print()‎</code> تعمل مع stdout.
</p>

<p>
	ويمكن الحصول على وسطاء سطر الأوامر من قائمة <code>argv</code> المستوردة من وحدة <code>sys</code> في بايثون، حيث يكون العنصر الأول هو اسم البرنامج، ورأينا أن جافاسكربت وVBScript تستطيعان قراءة المدخلات من استمارات الويب <code>forms</code> أو من خلال الصناديق الحوارية، لكن ليس لهما وصول إلى <code>stdin</code>، كما تستطيعان عرض الخرج بكتابته إلى المستند <code>document</code> أو من خلال الصناديق الحوارية، وليس لهما وصول إلى <code>stdout</code>.
</p>

<p>
	ترجمة -بتصرف <a href="http://www.alan-g.me.uk/l2p2/tutinput.htm" rel="external nofollow">للفصل التاسع: Conversing with the user من كتاب Learning To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/" rel="">مقدمة في البرمجة الشرطية</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D9%84%D9%88%D8%A8-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%88%D8%AA%D8%AD%D9%82%D9%8A%D9%82-%D8%B3%D9%87%D9%88%D9%84%D8%A9-%D9%82%D8%B1%D8%A7%D8%A1%D8%AA%D9%87%D8%A7-r1307/" rel="">أسلوب كتابة الشيفرات البرمجية وتحقيق سهولة قراءتها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">دليلك الشامل لتعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B1%D9%85%D9%8A%D8%B2-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r1283/" rel="">ترميز النصوص والتعامل مع كائنات الملفات في جافاسكريبت</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/35-%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/" rel="">تعلم البرمجة للمبتدئين</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1311</guid><pubDate>Sun, 05 Sep 2021 15:00:00 +0000</pubDate></item><item><title>&#x623;&#x633;&#x644;&#x648;&#x628; &#x643;&#x62A;&#x627;&#x628;&#x629; &#x627;&#x644;&#x634;&#x64A;&#x641;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629; &#x648;&#x62A;&#x62D;&#x642;&#x64A;&#x642; &#x633;&#x647;&#x648;&#x644;&#x629; &#x642;&#x631;&#x627;&#x621;&#x62A;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D9%84%D9%88%D8%A8-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%88%D8%AA%D8%AD%D9%82%D9%8A%D9%82-%D8%B3%D9%87%D9%88%D9%84%D8%A9-%D9%82%D8%B1%D8%A7%D8%A1%D8%AA%D9%87%D8%A7-r1307/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_08/6129dd48cb525_---.png.ad8c13948118c34729bb55d26a4d38d2.png" /></p>
<p>
	من الضروري أن تكون البرامج التي نكتبها سهلة القراءة بمجرد النظر إليها، لأن أخلاط الرموز الغريبة المتجاورة والأقواس المتتالية والكلمات المبتورة من اللغة الإنجليزية؛ تكفي ليظن الناظر إلى الشيفرة أن طفلًا صغيرًا عبث بيده على لوحة المفاتيح، فإذا اخترنا أسماءً مفهومةً للمتغيرات تدل على وظائفها، ورتبنا الأسطر فجعلنا كل مجموعة منها تنفذ مهمةً ما بإزاحة خاصة بها، وكتبنا تعليقات توضح سبب اختيار الأرقام أو الرموز التي لا يبدو لها سبب منطقي، وقبل كل ذلك افتتحنا الملف ببيانات تعريفية له نعرف بها من كتبه وإصدار البرنامج وغير ذلك، وإذا اتبعنا مثل هذه السلوكيات -وهي المتبعة في البرمجة بالفعل-؛ فسنوفر كثيرًا من الجهد والوقت اللذين سيهدرَان في معرفة غرض كل سطر من البرنامج ومشاكله المستقبلية، ويسهل تحديثه لاحقًا وإضافة ميزات جديدة للبرنامج.
</p>

<h2>
	التعليقات
</h2>

<p>
	تحدثنا عن التعليقات في مقال <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D9%85%D8%B2%D9%8A%D8%AF-%D9%85%D9%86-%D8%A7%D9%84%D8%AA%D8%B3%D9%84%D8%B3%D9%84%D8%A7%D8%AA-%D9%88%D8%A3%D9%85%D9%88%D8%B1-%D8%A3%D8%AE%D8%B1%D9%89-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1289/" rel="">بعض التسلسلات النصية المهمة لتعلم البرمجة</a>، وسنلقي في هذا المقال الضوء على بعض تطبيقاتها واستخداماتها.
</p>

<h3>
	سجل الإصدارات
</h3>

<p>
	يجب على المبرمج أن يسهّل على من يقرأ برامجه معرفة التفاصيل الأساسية لكل ملف، مثل تاريخ إنشائه واسم مؤلفه وبيانات آخر تعديل فيه وإصداره ووصف عام لمحتوياته، وبقية المعلومات التي تدخل في سجل تغييراته، وهذه الكتلة النصية تُكتب في تعليق، بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2677_7" style=""><span class="com">#############################</span><span class="pln">
</span><span class="com"># Module:   Spam.py</span><span class="pln">
</span><span class="com"># Author:   A.J.Gauld</span><span class="pln">
</span><span class="com"># Version:  Draft 0.4</span><span class="pln">
</span><span class="str">'''</span><span class="pln">
</span><span class="typ">This</span><span class="pln"> module provides a </span><span class="typ">Spam</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> which can be
combined with any other type of </span><span class="typ">Food</span><span class="pln"> object to create
interesting meal combinations</span><span class="pun">.</span><span class="pln">
</span><span class="str">'''</span><span class="pln">
</span><span class="com">###############################</span><span class="pln">
</span><span class="com"># Log:</span><span class="pln">
</span><span class="com"># 2015/09/01    AJG - File created</span><span class="pln">
</span><span class="com"># 2015/09/02    AJG - Fixed bug in pricing strategy</span><span class="pln">
</span><span class="com"># 2015/09/02    AJG - Did it right this time!</span><span class="pln">
</span><span class="com"># 2016/01/03    AJG - Added broiling method(cf Change Req #1234)</span><span class="pln">
</span><span class="com">################################</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> sys</span><span class="pun">,</span><span class="pln"> string</span><span class="pun">,</span><span class="pln"> food
</span><span class="pun">...</span></pre>

<p>
	نرى في هذا المثال ملخصًا بسيطًا لما يحتويه الملف بمجرد فتحه، فنعرف ما الذي تغير فيه من ما قبله، ومن الذي نفذ هذه التغييرات ووقت إجرائها، وتبرز أهمية هذه المعلومات عند العمل على المشروع ضمن فريق، وذلك حين نحتاج إلى معرفة المسؤول عن التغيير الذي بين أيدينا أو تصميم البرنامج الذي تعمل عليه، وقد وضعنا الوصف بين زوج من علامات الاقتباس الثلاثية، وهذا أسلوب تتبعه بايثون يسمى سلسلة التوثيق، ويُستخدم لإضافة هذا التوثيق والوصف إلى الدالة <code>help()‎</code> المضمَّنة فيها، كما سنرى بعد قليل.
</p>

<p>
	من المهم ملاحظة وجود أدوات تعمل مثل مستودعات للشيفرات البرمجية، مثل Git وSubversion وCVS وRCS، إذ تستطيع الاحتفاظ بمعلومات تلقائيًا، مثل اسم المؤلف واسم الملف وتفاصيل سجل الإصدار وننصح بالنظر في خصائص التوثيق في تلك المستودعات وتعلمها، لأنها توفر الكثير من الوقت الضائع في التسجيل اليدوي لهذه التعليقات.
</p>

<h3>
	تعطيل الشيفرات الفاسدة
</h3>

<p>
	تُستخدم التعليقات لعزل جزء فاسد أو غير صالح من الشيفرة عن باقي البرنامج، كأن يكون لدينا برنامج يقرأ بعض البيانات ويعالجها، ويطبع الخرج ثم يحفظ النتائج في ملف البيانات مرةً أخرى، ويجب منع حفظ البيانات الخاطئة أو الفاسدة في الملف وإفساده؛ إذا كانت النتائج على غير ما نريد أو نتوقع. وقد يقال أن الحل الأبسط هو حذف الشيفرة الفاسدة، وهذا صحيح؛ لكننا نستطيع عزلها وتعطيل تنفيذها بتحويلها إلى تعليق، لإصلاحها فيما بعد، وذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2677_9" style=""><span class="pln">data </span><span class="pun">=</span><span class="pln"> readData</span><span class="pun">(</span><span class="pln">datafile</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> item in data</span><span class="pun">:</span><span class="pln">
    results</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">calculateResult</span><span class="pun">(</span><span class="pln">item</span><span class="pun">))</span><span class="pln">
printResults</span><span class="pun">(</span><span class="pln">results</span><span class="pun">)</span><span class="pln">
</span><span class="com">######################</span><span class="pln">
</span><span class="com"># تُعزل الشيفرة أدناه إلى حين إصلاح </span><span class="pln">
</span><span class="com"># calculateResult الزلة التي في </span><span class="pln">
</span><span class="com"># for item in results:</span><span class="pln">
</span><span class="com">#     dataFile.save(item)</span><span class="pln">
</span><span class="com">######################</span><span class="pln">
print </span><span class="str">'Program terminated'</span></pre>

<p>
	ثم نحذف علامات التعليق إذا أصلحنا ذلك الخلل، لجعل الشيفرة نشطةً مرةً أخرى.
</p>

<p>
	تحتوي العديد من المحررات البرمجية مثل IDLE، خاصيةً نستطيع فيها اختيار جزء من الشيفرة وتحويله إلى تعليق تلقائيًا، ثم إلغاء ذلك التحديد عند الحاجة، وسنجد هذه الخاصية في IDLE في القائمة Format ثم الخيار Comment Out Region.
</p>

<h3>
	سلاسل التوثيق
</h3>

<p>
	تسمح جميع اللغات البرمجية بإنشاء تعليقات لتسجيل ما تفعله الدالة أو الوحدة التي نكتبها، لكن قليلًا منها يزيد على ذلك بأن يسمح لنا بتوثيق الدالة بطريقة تستطيع اللغة أو البيئة نفسها أن تستفيد منها لتوفر لنا مساعدةً تفاعليةً أثناء البرمجة، ومن تلك اللغات: جافا وبايثون وSmalltalk، نستخدم هذه الخاصية في بايثون من خلال علامات الاقتباس الثلاثية التي على نمط <code>"""documentation"""</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2677_11" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">Spam</span><span class="pun">:</span><span class="pln">
    </span><span class="str">"""A meat for combining with other foods

    It can be used with other foods to make interesting meals.
    It comes with lots of nutrients and can be cooked using many
    different techniques"""</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">pass</span><span class="pln">   </span><span class="com"># ie. it does nothing!</span><span class="pln">

help</span><span class="pun">(</span><span class="typ">Spam</span><span class="pun">)</span></pre>

<p>
	لاحظ أننا نستطيع الوصول إلى سلسلة التوثيق باستخدام الدالة <code>help()‎</code>، وأن سلاسل التوثيق تصلح للوحدات والدوال والأصناف والتوابع، لننظر إلى الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2677_13" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> sys
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> help </span><span class="pun">(</span><span class="pln">sys</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Help</span><span class="pln"> on built</span><span class="pun">-</span><span class="kwd">in</span><span class="pln"> function exit</span><span class="pun">:</span><span class="pln">

exit</span><span class="pun">(...)</span><span class="pln">
    exit</span><span class="pun">([</span><span class="pln">status</span><span class="pun">])</span><span class="pln">

    </span><span class="typ">Exit</span><span class="pln"> the interpreter by raising </span><span class="typ">SystemExit</span><span class="pun">(</span><span class="pln">status</span><span class="pun">).</span><span class="pln">
    </span><span class="typ">If</span><span class="pln"> the status </span><span class="kwd">is</span><span class="pln"> omitted </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">None</span><span class="pun">,</span><span class="pln"> it defaults to zero </span><span class="pun">(</span><span class="pln">i</span><span class="pun">.</span><span class="pln">e</span><span class="pun">.,</span><span class="pln"> success</span><span class="pun">).</span><span class="pln">
    </span><span class="typ">If</span><span class="pln"> the status </span><span class="kwd">is</span><span class="pln"> numeric</span><span class="pun">,</span><span class="pln"> it will be used </span><span class="kwd">as</span><span class="pln"> the system exit status</span><span class="pun">.</span><span class="pln">
    </span><span class="typ">If</span><span class="pln"> it </span><span class="kwd">is</span><span class="pln"> another kind of object</span><span class="pun">,</span><span class="pln"> it will be printed </span><span class="kwd">and</span><span class="pln"> the system
    exit status will be one </span><span class="pun">(</span><span class="pln">i</span><span class="pun">.</span><span class="pln">e</span><span class="pun">.,</span><span class="pln"> failure</span><span class="pun">).</span><span class="pln">
</span><span class="pun">(</span><span class="pln">END</span><span class="pun">)</span></pre>

<p>
	إذا أردنا الخروج من وضع المساعدة الذي في المثال السابق عند رؤية <code>END</code>؛ التي تشير إلى نهاية التوثيق، فسنضغط على مفتاح Q في لوحة المفاتيح، وهو اختصار كلمة Quit؛ أما إذا كان التوثيق أكثر من صفحة، فسنضغط على مفتاح المسافة لتصفحه، ومن الجدير بالذكر أن كلمة <code>END</code> التي في نهاية التوثيق قد لا تظهر في بعض الطرفيات.
</p>

<p>
	توجد دالة مساعِدة أخرى هي <code>dir()‎</code>، والتي تعرض جميع المزايا التي تعرفها بايثون عن كائن ما، فإذا أردنا معرفة الدوال أو المتغيرات الموجودة في وحدة <code>sys</code> مثلًا، فسنكتب ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2677_15" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> sys
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> dir</span><span class="pun">(</span><span class="pln">sys</span><span class="pun">)</span><span class="pln">
</span><span class="pun">[.....</span><span class="pln"> </span><span class="str">'argv'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'builtin_module_names'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'byteorder'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">....</span><span class="pln"> </span><span class="str">'copyright'</span><span class="pun">,</span><span class="pln"> 
</span><span class="pun">....</span><span class="pln"> </span><span class="str">'exit'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.....</span><span class="pln"> </span><span class="str">'stderr'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'stdin'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'stdout'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'subversion'</span><span class="pun">,</span><span class="pln"> 
</span><span class="str">'version'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'version_info'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'warnoptions'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'winver'</span><span class="pun">]</span></pre>

<p>
	بعد ذلك سنختار ما نريد منها، ونستخدم دالة <code>help()‎</code> للحصول على مزيد من المعلومات، وقد أهملنا العديد من المدخلات في المثال أعلاه لتوفير المساحة، كما نستفيد من وظيفة الدالة <code>dir()‎</code> عند استخدام وحدة ليس لها توثيق جيد أو كافٍ، فقد نتعامل مع وحدات ليس لها توثيق خارجي أصلًا.
</p>

<h2>
	إزاحة الكتل
</h2>

<p>
	ذكرنا عدة مرات أن إزاحة الأسطر مهمة في بايثون، وتتوقف عليها الإجراءات التالية للأسطر المزاحة، مع أن أكثر لغات البرمجة لا تهتم بإزاحة الأسطر، لذا يزيح المبرمجون الأسطر في برامجهم وشيفراتهم لتسهيل قراءتها وتمييز أجزائها لا أكثر، فقد صار لكل مبرمج تقريبًا أسلوبه الخاص في الإزاحة وفق ما يراه مناسبًا، وقد ولّدت كثرة الأهواء والآراء في هذا الشأن جدالات حامية الوطيس في البرمجة منذ زمن، بلغت حد إجراء بدراسات للوقوف على الجوانب التي تؤثر فيها إزاحة الأسطر سوى المظهر الجمالي، كأن تساعد في فهم الشيفرة البرمجية بطريقة أسرع وأسهل، لننظر في المثال التالي من VBScript مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2677_17" style=""><span class="pun">&lt;</span><span class="pln"> script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">For</span><span class="pln"> I </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> TO </span><span class="lit">10</span><span class="pln">
    </span><span class="typ">MsgBox</span><span class="pln"> I
</span><span class="typ">Next</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	ثم لننظر إلى النسخة التالية منه، والتي لا تحوي إزاحات للأسطر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2677_19" style=""><span class="pun">&lt;</span><span class="pln"> script type</span><span class="pun">=</span><span class="str">"text/vbscript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="typ">For</span><span class="pln"> I </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> TO </span><span class="lit">10</span><span class="pln">
</span><span class="typ">MsgBox</span><span class="pln"> I
</span><span class="typ">Next</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	يكاد المثالان يتطابقان في نظرنا نحن البشر، والفرق بينهما هو أن النسخة الأولى أسهل في القراءة في نظرنا، أما في نظر مفسر VBScript فهما متطابقتان تمامًا ولا فرق بينهما، والشرط الحاكم للإزاحة هنا هو أن تعكس الهيكل المنطقي للشيفرة، فتتبع تدفق البرنامج في هيئتها المرئية، وقد أظهرت الدراسات التي أجريت على الشيفرات المزاحة أن الشيفرات المقسَّمة بصريًا إلى كتل تعكس البنية الكتلية المنطقية للبرنامج؛ أسهل في الفهم، وعلى ذلك تكون البنية التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2677_21" style=""><span class="pln">XXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXX</span></pre>

<p>
	أسهل في فهم مرادها ووظيفتها من هذه البنية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2677_23" style=""><span class="pln">XXXXXXXXXXXXXXXXXXXXX
  XXXXX
    XXXXXXXXXXXX
    XXXXXXXXXXXX
    XXXXXXXXXXXX
  XXXXX</span></pre>

<p>
	قد لا تظهر أهمية الإزاحة في الأمثلة البسيطة التي أوردناها إلى الآن، لكن الفرق يتضح عند التعامل مع برامج تحتوي على مئات الآلاف من الأسطر البرمجية.
</p>

<p>
	يتبقى الآن أن ننظر في مقدار تلك الإزاحة، وهو أمر طال الخلاف حوله في مجال البرمجة، ويكمن الاختلاف بين استخدام المسافات spacebar للإزاحة أو استخدام زر الجدول tab. ومع أن استخدام زر الجدول أسهل لأنه يؤدي الغرض بنقرة واحدة؛ غير أن هذه النقرة الواحدة تساوي 8 مسافات، وهي إزاحة كبيرة، كما يصعب تحديد آلية الإزاحة الموجودة في شيفرة ما، فهل نتجت عن استخدام زر المسافة أم زر الجدول، لأننا لا نستطيع استخدامهما معًا، فإما هذا أو ذاك، وتظهر هذه المشكلة لمن يتعامل مع برنامج كتبه مبرمج غيره، ولتجنب هذه المعضلة من بداية تعلمنا للبرمجة، يُفضّل تجنب استخدام زر الجدول في الإزاحة، لأن بعض الدراسات أظهرت أن أفضل صورة للشيفرة -من حيث سهولة القراءة- تتحقق إذا كانت الإزاحة محصورةً بين مسافتين وخمس مسافات؛ أما مستخدمو بايثون فقد اصطلحوا على استخدام أربع مسافات في الإزاحة، على الرغم من صلاحية الأمثلة التي استخدمناها إلى الآن، والتي كانت إزاحاتها أقل من ذلك، لأنها توفر بعض المساحة على الشاشة.
</p>

<h2>
	أسماء المتغيرات
</h2>

<p>
	لم نستخدم أسماءً لها معانٍ للمتغيرات في الأمثلة التي أوردناها في ما سبق، لأننا لم نقصد إلا شرح بعض التقنيات البرمجية، لكن يُفضل أن تعكس أسماء المتغيرات ما تمثله في الشيفرة، من حيث الوظيفة التي تنفذها، فقد استخدمنا المتغير <code>multiplier</code> في تدريب جدول الضرب مثلًا؛ والذي سبق أن عرضناه مثل متغير يوضح الجدول الذي نريد طباعته. علمًا أن هذه التسمية أفضل من اختيار اسم عشوائي أو رمزي مثل <code>m</code> الذي لن يسبب مشاكل في تنفيذ الشيفرة، بل سيريحنا في الكتابة بما أنه حرف واحد، لكنه بلا معنىً، وسيتسبب في مشاكل مستقبلية إذا أردنا معرفة وظيفة هذا المتغير، أو أراد مبرمج آخر ذلك.
</p>

<p>
	يُفضل في تسمية المتغيرات أن تكون مفهومةً على أن تكون سهلة الكتابة، وأفضل حل لأسماء المتغيرات هو أن تكون قصيرةً وذات معنىً في نفس الوقت، فالأسماء الطويلة مربكة وصعبة الكتابة، فمثلًا: نستطيع استخدام <code>the_table_we_are_printing</code> عوضًا عن <code>multiplier</code>، غير أن هذا الاسم طويل ويتجاوز المعقول في الكتابة البرمجية.
</p>

<h2>
	حفظ البرامج
</h2>

<p>
	ذكرنا سابقًا أننا نخسر كل شيء كتبناه في محث بايثون <code>‎&gt;&gt;&gt;‎</code> بمجرد الخروج منه، فهو وإن كان ممتازًا في تجربة الأفكار بسرعة؛ إلا أنه غير مفيد على المدى البعيد، إذ نريد أن نكتب البرامج ونشغلها مرةً بعد مرة وقتما نشاء، فهذا هو المنطق، ولفعل ذلك في بايثون؛ ننشئ ملفًا نصيًا للبرنامج ونجعله بالامتداد <code>‎.py</code>، وهو اصطلاح متبع، رغم أننا نستطيع استخدام أي امتداد نريده هنا، لكن يُفضل اتباع هذا الاصطلاح، ثم نستطيع تشغيل البرنامج من محث سطر أوامر النظام بكتابة ما يلي:
</p>

<pre class="ipsCode">C:\WINDOWS&gt; python spam.py
</pre>

<p>
	فيكون اسم برنامج بايثون هنا هو <code>spam.py</code>، ومحث نظام التشغيل هو <code>C:\WINDOWS&gt;‎</code>.
</p>

<p>
	إحدى مزايا استخدام هذه الطريقة في برامج بايثون أننا نستطيع تشغيل البرنامج بمجرد النقر عليه في مدير الملفات، مثل أي ملف تنفيذي يمثل برنامجًا بما أن ويندوز يربط امتداد <code>‎.py</code> بمفسر بايثون، كما أن استخدام الملفات لتخزين البرامج يسمح بتصحيح أخطائها دون الحاجة إلى إعادة كتابة الجزء الخاطئ من البرنامج مرةً أخرى في محث بايثون، أو التحرك بالمؤشر في IDLE حتى نتجاوز الخطأ كي نعيد تحديد الشيفرة، لأن IDLE تدعم فتح الملف لتعديله وتشغيله من القائمة Run، ثم خيار Run module، أو باستخدام مفتاح F5 على لوحة المفاتيح.
</p>

<p>
	لن نعرض محث بايثون <code>‎&gt;&gt;&gt;‎</code> مرةً أخرى في الأمثلة البرمجية التي نشرحها، إذ سنفترض أنك تنشئ البرامج في ملف منفصل وتشغلها إما داخل IDLE أو من محث سطر الأوامر.
</p>

<h3>
	ملاحظة لمستخدمي ويندوز
</h3>

<p>
	يمكن إعداد ربط الملفات التي تنتهي بامتداد <code>‎.py</code> داخل مدير الملفات، مما يسمح بتشغيل برامج بايثون بالنقر المزدوج على أيقونة الملف، والمفترض أن مثبت بايثون قد نفذ هذا الإجراء بالفعل، وللتحقق من ذلك؛ ابحث عن ملف بامتداد بايثون وجرب تشغيله، فإذا نجحت يكون الربط جاهزًا على حاسوبك، حتى لو أخرج لك رسالة خطأ.
</p>

<p>
	المشكلة التي قد تواجهها هنا هي أن الملفات التي أيقونتها شعار بايثون نفسه؛ إذ ستشَغل في صندوق DOS ثم تغلَق بسرعة بحيث لا تكاد تراها، ويمكن حل هذا بكتابة السطر التالي في نهاية البرنامج:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2677_34" style=""><span class="pln">input</span><span class="pun">(</span><span class="str">"Hit ENTER to quit"</span><span class="pun">)</span></pre>

<p>
	سيعرض هذا السطر رسالةً تخبرك أن تضغط زر ENTER للخروج، وينتظر حتى يحدث ذلك؛ أما في إصدارات بايثون الأخيرة فهناك أداة إضافية في ويندوز ستساعدك على تشغيل بايثون دون مشاكل، وهي <code>py.exe</code>، فإذا كتبنا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2677_32" style=""><span class="pln"> C</span><span class="pun">:</span><span class="pln">\WINDOWS</span><span class="pun">&gt;</span><span class="pln"> py spam</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	فستبحث هذه الأداة عن بايثون، وتشغل الشيفرة تشغيلًا صحيحًا، كما تستفيد من أي سطر كامل المسار shebang line داخل الملف لتعرف أي إصدار تستخدمه من بايثون -إذا وُجد أكثر من إصدار مثبت على حاسوبك-.
</p>

<h3>
	ملاحظة لمستخدمي يونكس
</h3>

<p>
	يجب أن يحتوي أول سطر في ملف سكربت بايثون على التسلسل <code>‎#!‎</code> متبوعًا بالمسار الكامل لبايثون على حاسوبك، ويُعرف سطر المسار الكامل هذا أحيانًا باسم <a href="https://wiki.hsoub.com/Python/Basic_Syntax#.D8.B3.D8.B7.D8.B1_.D8.B4.D9.8A.D8.A8.D8.A7.D9.86.D9.83_shebang_line" rel="external">شيبانك shebang</a> باللغة الإنجليزية، وهو السطر الذي يجعل شيفرة بايثون قابلةً للتنفيذ عبر مفسر بايثون المحدد بالمسار، والذي نعثر عليه بكتابة السطر التالي في محث الصدفة shell prompt:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2677_30" style=""><span class="pln">$ which python</span></pre>

<p>
	وقد يبدو ذلك المسار كما يلي:
</p>

<pre class="ipsCode">#!/usr/local/bin/python
</pre>

<p>
	مما يسمح لنا بتشغيل الملف دون استدعاء بايثون، بعد إعدادها لتكون قابلةً للتشغيل من خلال chmod كما تعلم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2677_36" style=""><span class="pln">$ spam</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	يمكن استخدام <code>‎/usr/bin/env python</code> بدل معلومات المسار، مثل أسلوب أفضل يمكن تنفيذه على أغلب أنظمة يونكس، بما فيها جميع توزيعات لينكس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2677_38" style=""><span class="com">#!/usr/bin/env python</span></pre>

<p>
	سيبحث هذا الأمر عن بايثون في مسارك تلقائيًا، غير أن عيبه يظهر عندما توجد عدة إصدارات من بايثون، ولا يعمل السكربت إلا مع إصدار واحد منها فقط عند استخدام ميزة جديدة في بايثون مثلًا، وهنا يُفضَّل استخدام أسلوب المسار الكامل، أو على الأقل تحديد إصدار بايثون المناسب، سواء كان <code>python2</code> أو <code>python3</code>.
</p>

<p>
	أما سطر <code>‎#!‎</code> فلا يسبب مشاكل في نظامي ويندوز أو ماك لأنه سيبدو تعليقًا، لذا لا بأس بكتابته عند استخدام هذين النظامين، وذلك تحسبًا لاحتمال تشغيل الشيفرة على حاسوب يونكس يومًا ما، أو استخدام مطلِق <code>py.exe</code> الذي لا يتجاهل سطر المسار الكامل shebang.
</p>

<h3>
	جافاسكربت وVBScript
</h3>

<p>
	لا يحتاج من يبرمج مستخدمًا جافاسكربت وVBScript إلى الملاحظات التي ذكرناها أعلاه، لأن هذه البرامج تُحفظ في ملفات.
</p>

<h2>
	خاتمة
</h2>

<p>
	تعلمنا في هذا المقال ما يلي:
</p>

<ul>
	<li>
		استخدام التعليقات لعزل جزء من الشيفرة مؤقتًا عند الاختبارات أو تنقيح الشيفرة debugging، وكذلك استخدامها لتوفير ترويسة توضيحية يُذكر فيها سجل إصدارات الملف.
	</li>
	<li>
		كيفية استخدام سلاسل التوثيق في توفير معلومات فورية runtime-information عن وحدة ما، والكائنات التي داخلها.
	</li>
	<li>
		فائدة إزاحة كتل الشيفرات في توضيح الترتيب المنطقي لهيكل الشيفرة البرمجية، وتسهيل تتبع عين القارئ لذلك التسلسل المنطقي.
	</li>
	<li>
		حفظ برامج بايثون في ملفات لإعادة تشغيلها في أي وقت، بدلًا من كتابتها في محث بايثون <code>‎&gt;&gt;&gt;‎</code> ثم ضياعها عند الخروج منه، وذلك بكتابة <code>‎$ python progname.py</code> في سطر الأوامر، أو بتشغيل الملف في مدير الملفات بالنقر عليه.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutstyle.htm" rel="external nofollow">للفصل الثامن: Coding Style من كتاب Learning To Program</a> لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%82%D8%B1%D8%A7%D8%A1%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-r1311/" rel="">كيفية قراءة البرامج لمدخلات المستخدم</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1306/" rel="">الحلقات التكرارية في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">دليلك الشامل لتعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%B6%D8%B9-%D8%A7%D9%84%D8%B5%D8%A7%D8%B1%D9%85-%D8%A7%D9%84%D9%86%D9%85%D8%B7-%D8%A7%D9%84%D8%AD%D8%AF%D9%8A%D8%AB-%D9%84%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r670/" rel="">الوضع الصارم: النمط الحديث لكتابة شيفرات جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/cpp/%D8%AA%D8%AD%D8%B3%D9%8A%D9%86-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D9%88%D8%A8%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-cpp-%D9%88%D8%AA%D8%B4%D8%AE%D9%8A%D8%B5%D9%87%D8%A7-r1191/" rel="">تحسين الشيفرات المكتوبة بلغة Cpp وتشخيصها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/ruby/%D8%AF%D9%84%D9%8A%D9%84-airbnb-%D9%84%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D8%A7%D9%84%D8%B4%D9%8A%D9%81%D8%B1%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%BA%D8%A9-%D8%B1%D9%88%D8%A8%D9%8A-ruby-r886/" rel="">دليل Airbnb لتنسيق الشيفرة البرمجية للغة روبي Ruby</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1307</guid><pubDate>Mon, 30 Aug 2021 15:03:00 +0000</pubDate></item></channel></rss>
